blob: e996ca2eeddc85cf19ddac3fac3068f58532f690 [file] [log] [blame]
Ben Cheng4238ec22009-08-24 16:32:22 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Dalvik.h"
18#include "CompilerInternals.h"
19#include "Dataflow.h"
20#include "Loop.h"
21
22#define DEBUG_LOOP(X)
23
24/*
25 * Given the current simple natural loops, the phi node placement can be
26 * determined in the following fashion:
27 * entry (B0)
28 * +---v v
29 * | loop body (B1)
30 * | v
31 * | loop back (B2)
32 * +---+ v
33 * exit (B3)
34 *
35 * 1) Add live-ins of B1 to B0 as defs
36 * 2) The intersect of defs(B0)/defs(B1) and defs(B2)/def(B0) are the variables
37 * that need PHI nodes in B1.
38 */
39static void handlePhiPlacement(CompilationUnit *cUnit)
40{
41 BasicBlock *entry = cUnit->blockList[0];
42 BasicBlock *loopBody = cUnit->blockList[1];
43 BasicBlock *loopBranch = cUnit->blockList[2];
44 dvmCopyBitVector(entry->dataFlowInfo->defV,
45 loopBody->dataFlowInfo->liveInV);
46
47 BitVector *phiV = dvmCompilerAllocBitVector(cUnit->method->registersSize,
48 false);
49 dvmIntersectBitVectors(phiV, entry->dataFlowInfo->defV,
50 loopBody->dataFlowInfo->defV);
51 dvmIntersectBitVectors(phiV, entry->dataFlowInfo->defV,
52 loopBranch->dataFlowInfo->defV);
53
54 /* Insert the PHI MIRs */
55 int i;
56 for (i = 0; i < cUnit->method->registersSize; i++) {
57 if (!dvmIsBitSet(phiV, i)) {
58 continue;
59 }
60 MIR *phi = dvmCompilerNew(sizeof(MIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -070061 phi->dalvikInsn.opCode = kMirOpPhi;
Ben Cheng4238ec22009-08-24 16:32:22 -070062 phi->dalvikInsn.vA = i;
63 dvmCompilerPrependMIR(loopBody, phi);
64 }
65}
66
67static void fillPhiNodeContents(CompilationUnit *cUnit)
68{
69 BasicBlock *entry = cUnit->blockList[0];
70 BasicBlock *loopBody = cUnit->blockList[1];
71 BasicBlock *loopBranch = cUnit->blockList[2];
72 MIR *mir;
73
74 for (mir = loopBody->firstMIRInsn; mir; mir = mir->next) {
Bill Buzbee1465db52009-09-23 17:17:35 -070075 if (mir->dalvikInsn.opCode != kMirOpPhi) break;
Ben Cheng4238ec22009-08-24 16:32:22 -070076 int dalvikReg = mir->dalvikInsn.vA;
77
78 mir->ssaRep->numUses = 2;
79 mir->ssaRep->uses = dvmCompilerNew(sizeof(int) * 2, false);
80 mir->ssaRep->uses[0] =
81 DECODE_REG(entry->dataFlowInfo->dalvikToSSAMap[dalvikReg]);
82 mir->ssaRep->uses[1] =
83 DECODE_REG(loopBranch->dataFlowInfo->dalvikToSSAMap[dalvikReg]);
84 }
85
86
87}
88
89static void dumpConstants(CompilationUnit *cUnit)
90{
91 int i;
92 for (i = 0; i < cUnit->numSSARegs; i++) {
93 if (dvmIsBitSet(cUnit->isConstantV, i)) {
94 int subNReg = dvmConvertSSARegToDalvik(cUnit, i);
95 LOGE("s%d(v%d_%d) has %d", i,
96 DECODE_REG(subNReg), DECODE_SUB(subNReg),
97 cUnit->constantValues[i]);
98 }
99 }
100}
101
102static void dumpIVList(CompilationUnit *cUnit)
103{
104 unsigned int i;
105 GrowableList *ivList = cUnit->loopAnalysis->ivList;
106 int *ssaToDalvikMap = (int *) cUnit->ssaToDalvikMap->elemList;
107
108 for (i = 0; i < ivList->numUsed; i++) {
109 InductionVariableInfo *ivInfo = ivList->elemList[i];
110 /* Basic IV */
111 if (ivInfo->ssaReg == ivInfo->basicSSAReg) {
112 LOGE("BIV %d: s%d(v%d) + %d", i,
113 ivInfo->ssaReg,
114 ssaToDalvikMap[ivInfo->ssaReg] & 0xffff,
115 ivInfo->inc);
116 /* Dependent IV */
117 } else {
118 LOGE("DIV %d: s%d(v%d) = %d * s%d(v%d) + %d", i,
119 ivInfo->ssaReg,
120 ssaToDalvikMap[ivInfo->ssaReg] & 0xffff,
121 ivInfo->m,
122 ivInfo->basicSSAReg,
123 ssaToDalvikMap[ivInfo->basicSSAReg] & 0xffff,
124 ivInfo->c);
125 }
126 }
127}
128
129/*
130 * A loop is considered optimizable if:
131 * 1) It has one basic induction variable
132 * 2) The loop back branch compares the BIV with a constant
133 * 3) If it is a count-up loop, the condition is GE/GT, or LE/LT/LEZ/LTZ for
134 * a count-down loop.
135 */
136static bool isLoopOptimizable(CompilationUnit *cUnit)
137{
138 unsigned int i;
139 BasicBlock *loopBranch = cUnit->blockList[2];
140 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
141
142 if (loopAnalysis->numBasicIV != 1) return false;
143 for (i = 0; i < loopAnalysis->ivList->numUsed; i++) {
144 InductionVariableInfo *ivInfo;
145
146 ivInfo = GET_ELEM_N(loopAnalysis->ivList, InductionVariableInfo*, i);
147 /* Count up or down loop? */
148 if (ivInfo->ssaReg == ivInfo->basicSSAReg) {
149 loopAnalysis->isCountUpLoop = ivInfo->inc > 0;
150 break;
151 }
152 }
153
154 MIR *branch = loopBranch->lastMIRInsn;
155 OpCode opCode = branch->dalvikInsn.opCode;
156
157 /*
158 * If the instruction is not accessing the IV as the first operand, return
159 * false.
160 */
161 if (branch->ssaRep->numUses == 0 || branch->ssaRep->numDefs != 0) {
162 return false;
163 }
164
165 /*
166 * If the first operand of the comparison is not the basic induction
167 * variable, return false.
168 */
169 if (branch->ssaRep->uses[0] != loopAnalysis->ssaBIV) {
170 return false;
171 }
172
173 if (loopAnalysis->isCountUpLoop) {
174 /*
175 * If the condition op is not > or >=, this is not an optimization
176 * candidate.
177 */
178 if (opCode != OP_IF_GT && opCode != OP_IF_GE) {
179 return false;
180 }
181 /*
182 * If the comparison is not between the BIV and a loop invariant,
183 * return false.
184 */
185 int endReg = dvmConvertSSARegToDalvik(cUnit, branch->ssaRep->uses[1]);
186
187 if (DECODE_SUB(endReg) != 0) {
188 return false;
189 }
190 loopAnalysis->endConditionReg = DECODE_REG(endReg);
191 } else {
192 /*
193 * If the condition op is not < or <=, this is not an optimization
194 * candidate.
195 */
196 if (opCode == OP_IF_LT || opCode == OP_IF_LE) {
197 /*
198 * If the comparison is not between the BIV and a loop invariant,
199 * return false.
200 */
201 int endReg = dvmConvertSSARegToDalvik(cUnit,
202 branch->ssaRep->uses[1]);
203
204 if (DECODE_SUB(endReg) != 0) {
205 return false;
206 }
207 loopAnalysis->endConditionReg = DECODE_REG(endReg);
208 } else if (opCode != OP_IF_LTZ && opCode != OP_IF_LEZ) {
209 return false;
210 }
211 }
212 loopAnalysis->loopBranchOpcode = opCode;
213 return true;
214}
215
216/*
217 * Record the upper and lower bound information for range checks for each
218 * induction variable. If array A is accessed by index "i+5", the upper and
219 * lower bound will be len(A)-5 and -5, respectively.
220 */
221static void updateRangeCheckInfo(CompilationUnit *cUnit, int arrayReg,
222 int idxReg)
223{
224 InductionVariableInfo *ivInfo;
225 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
226 unsigned int i, j;
227
228 for (i = 0; i < loopAnalysis->ivList->numUsed; i++) {
229 ivInfo = GET_ELEM_N(loopAnalysis->ivList, InductionVariableInfo*, i);
230 if (ivInfo->ssaReg == idxReg) {
231 ArrayAccessInfo *arrayAccessInfo = NULL;
232 for (j = 0; j < loopAnalysis->arrayAccessInfo->numUsed; j++) {
233 ArrayAccessInfo *existingArrayAccessInfo =
234 GET_ELEM_N(loopAnalysis->arrayAccessInfo,
235 ArrayAccessInfo*,
236 j);
237 if (existingArrayAccessInfo->arrayReg == arrayReg) {
238 if (ivInfo->c > existingArrayAccessInfo->maxC) {
239 existingArrayAccessInfo->maxC = ivInfo->c;
240 }
241 if (ivInfo->c < existingArrayAccessInfo->minC) {
242 existingArrayAccessInfo->minC = ivInfo->c;
243 }
244 arrayAccessInfo = existingArrayAccessInfo;
245 break;
246 }
247 }
248 if (arrayAccessInfo == NULL) {
249 arrayAccessInfo =
250 dvmCompilerNew(sizeof(ArrayAccessInfo), false);
251 arrayAccessInfo->ivReg = ivInfo->basicSSAReg;
252 arrayAccessInfo->arrayReg = arrayReg;
253 arrayAccessInfo->maxC = (ivInfo->c > 0) ? ivInfo->c : 0;
254 arrayAccessInfo->minC = (ivInfo->c < 0) ? ivInfo->c : 0;
255 dvmInsertGrowableList(loopAnalysis->arrayAccessInfo,
256 arrayAccessInfo);
257 }
258 break;
259 }
260 }
261}
262
263/* Returns true if the loop body cannot throw any exceptions */
264static bool doLoopBodyCodeMotion(CompilationUnit *cUnit)
265{
266 BasicBlock *entry = cUnit->blockList[0];
267 BasicBlock *loopBody = cUnit->blockList[1];
268 MIR *mir;
269 bool loopBodyCanThrow = false;
270 int numDalvikRegs = cUnit->method->registersSize;
271
272 for (mir = loopBody->firstMIRInsn; mir; mir = mir->next) {
273 DecodedInstruction *dInsn = &mir->dalvikInsn;
274 int dfAttributes =
275 dvmCompilerDataFlowAttributes[mir->dalvikInsn.opCode];
276
277 /* Skip extended MIR instructions */
278 if (dInsn->opCode > 255) continue;
279
280 int instrFlags = dexGetInstrFlags(gDvm.instrFlags, dInsn->opCode);
281
282 /* Instruction is clean */
283 if ((instrFlags & kInstrCanThrow) == 0) continue;
284
285 /*
286 * Currently we can only optimize away null and range checks. Punt on
287 * instructions that can throw due to other exceptions.
288 */
289 if (!(dfAttributes & DF_HAS_NR_CHECKS)) {
290 loopBodyCanThrow = true;
291 continue;
292 }
293
294 /*
295 * This comparison is redundant now, but we will have more than one
296 * group of flags to check soon.
297 */
298 if (dfAttributes & DF_HAS_NR_CHECKS) {
299 /*
300 * Check if the null check is applied on a loop invariant register?
301 * If the register's SSA id is less than the number of Dalvik
302 * registers, then it is loop invariant.
303 */
304 int refIdx;
305 switch (dfAttributes & DF_HAS_NR_CHECKS) {
306 case DF_NULL_N_RANGE_CHECK_0:
307 refIdx = 0;
308 break;
309 case DF_NULL_N_RANGE_CHECK_1:
310 refIdx = 1;
311 break;
312 case DF_NULL_N_RANGE_CHECK_2:
313 refIdx = 2;
314 break;
315 default:
316 refIdx = 0;
317 dvmAbort();
318 }
319
320 int useIdx = refIdx + 1;
321 int subNRegArray =
322 dvmConvertSSARegToDalvik(cUnit, mir->ssaRep->uses[refIdx]);
323 int arrayReg = DECODE_REG(subNRegArray);
324 int arraySub = DECODE_SUB(subNRegArray);
325
326 /*
327 * If the register is never updated in the loop (ie subscript == 0),
328 * it is an optimization candidate.
329 */
330 if (arraySub != 0) {
331 loopBodyCanThrow = true;
332 continue;
333 }
334
335 /*
336 * Then check if the range check can be hoisted out of the loop if
337 * it is basic or dependent induction variable.
338 */
339 if (dvmIsBitSet(cUnit->loopAnalysis->isIndVarV,
340 mir->ssaRep->uses[useIdx])) {
341 mir->OptimizationFlags |=
342 MIR_IGNORE_RANGE_CHECK | MIR_IGNORE_NULL_CHECK;
343 updateRangeCheckInfo(cUnit, mir->ssaRep->uses[refIdx],
344 mir->ssaRep->uses[useIdx]);
345 }
346 }
347 }
348
349 return !loopBodyCanThrow;
350}
351
352static void dumpHoistedChecks(CompilationUnit *cUnit)
353{
354 ArrayAccessInfo *arrayAccessInfo;
355 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
356 unsigned int i;
357
358 for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
359 ArrayAccessInfo *arrayAccessInfo =
360 GET_ELEM_N(loopAnalysis->arrayAccessInfo,
361 ArrayAccessInfo*, i);
362 int arrayReg = DECODE_REG(
363 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
364 int idxReg = DECODE_REG(
365 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
366 LOGE("Array access %d", i);
367 LOGE(" arrayReg %d", arrayReg);
368 LOGE(" idxReg %d", idxReg);
369 LOGE(" endReg %d", loopAnalysis->endConditionReg);
370 LOGE(" maxC %d", arrayAccessInfo->maxC);
371 LOGE(" minC %d", arrayAccessInfo->minC);
372 LOGE(" opcode %d", loopAnalysis->loopBranchOpcode);
373 }
374}
375
376static void genHoistedChecks(CompilationUnit *cUnit)
377{
378 unsigned int i;
379 BasicBlock *entry = cUnit->blockList[0];
380 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
381 ArrayAccessInfo *arrayAccessInfo;
382 int globalMaxC = 0;
383 int globalMinC = 0;
384 /* Should be loop invariant */
385 int idxReg = 0;
386
387 for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
388 ArrayAccessInfo *arrayAccessInfo =
389 GET_ELEM_N(loopAnalysis->arrayAccessInfo,
390 ArrayAccessInfo*, i);
391 int arrayReg = DECODE_REG(
392 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
393 idxReg = DECODE_REG(
394 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
395
396 MIR *rangeCheckMIR = dvmCompilerNew(sizeof(MIR), true);
397 rangeCheckMIR->dalvikInsn.opCode = (loopAnalysis->isCountUpLoop) ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700398 kMirOpNullNRangeUpCheck : kMirOpNullNRangeDownCheck;
Ben Cheng4238ec22009-08-24 16:32:22 -0700399 rangeCheckMIR->dalvikInsn.vA = arrayReg;
400 rangeCheckMIR->dalvikInsn.vB = idxReg;
401 rangeCheckMIR->dalvikInsn.vC = loopAnalysis->endConditionReg;
402 rangeCheckMIR->dalvikInsn.arg[0] = arrayAccessInfo->maxC;
403 rangeCheckMIR->dalvikInsn.arg[1] = arrayAccessInfo->minC;
404 rangeCheckMIR->dalvikInsn.arg[2] = loopAnalysis->loopBranchOpcode;
405 dvmCompilerAppendMIR(entry, rangeCheckMIR);
406 if (arrayAccessInfo->maxC > globalMaxC) {
407 globalMaxC = arrayAccessInfo->maxC;
408 }
409 if (arrayAccessInfo->minC < globalMinC) {
410 globalMinC = arrayAccessInfo->minC;
411 }
412 }
413
414 if (loopAnalysis->arrayAccessInfo->numUsed != 0) {
415 if (loopAnalysis->isCountUpLoop) {
416 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700417 boundCheckMIR->dalvikInsn.opCode = kMirOpLowerBound;
Ben Cheng4238ec22009-08-24 16:32:22 -0700418 boundCheckMIR->dalvikInsn.vA = idxReg;
419 boundCheckMIR->dalvikInsn.vB = globalMinC;
420 dvmCompilerAppendMIR(entry, boundCheckMIR);
421 } else {
422 if (loopAnalysis->loopBranchOpcode == OP_IF_LT ||
423 loopAnalysis->loopBranchOpcode == OP_IF_LE) {
424 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700425 boundCheckMIR->dalvikInsn.opCode = kMirOpLowerBound;
Ben Cheng4238ec22009-08-24 16:32:22 -0700426 boundCheckMIR->dalvikInsn.vA = loopAnalysis->endConditionReg;
427 boundCheckMIR->dalvikInsn.vB = globalMinC;
428 /*
429 * If the end condition is ">", add 1 back to the constant field
430 * to reflect the fact that the smallest index value is
431 * "endValue + constant + 1".
432 */
433 if (loopAnalysis->loopBranchOpcode == OP_IF_LT) {
434 boundCheckMIR->dalvikInsn.vB++;
435 }
436 dvmCompilerAppendMIR(entry, boundCheckMIR);
437 } else if (loopAnalysis->loopBranchOpcode == OP_IF_LTZ) {
438 /* Array index will fall below 0 */
439 if (globalMinC < 0) {
440 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700441 boundCheckMIR->dalvikInsn.opCode = kMirOpPunt;
Ben Cheng4238ec22009-08-24 16:32:22 -0700442 dvmCompilerAppendMIR(entry, boundCheckMIR);
443 }
444 } else if (loopAnalysis->loopBranchOpcode == OP_IF_LEZ) {
445 /* Array index will fall below 0 */
446 if (globalMinC < -1) {
447 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700448 boundCheckMIR->dalvikInsn.opCode = kMirOpPunt;
Ben Cheng4238ec22009-08-24 16:32:22 -0700449 dvmCompilerAppendMIR(entry, boundCheckMIR);
450 }
451 } else {
452 dvmAbort();
453 }
454 }
455
456 }
457}
458
459/* Main entry point to do loop optimization */
460void dvmCompilerLoopOpt(CompilationUnit *cUnit)
461{
462 int numDalvikReg = cUnit->method->registersSize;
463 LoopAnalysis *loopAnalysis = dvmCompilerNew(sizeof(LoopAnalysis), true);
464
Bill Buzbee1465db52009-09-23 17:17:35 -0700465 assert(cUnit->blockList[0]->blockType == kEntryBlock);
466 assert(cUnit->blockList[2]->blockType == kDalvikByteCode);
467 assert(cUnit->blockList[3]->blockType == kExitBlock);
Ben Cheng4238ec22009-08-24 16:32:22 -0700468
469 cUnit->loopAnalysis = loopAnalysis;
470 /*
471 * Find live-in variables to the loop body so that we can fake their
472 * definitions in the entry block.
473 */
474 dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerFindLiveIn);
475
476 /* Insert phi nodes to the loop body */
477 handlePhiPlacement(cUnit);
478
479 dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerDoSSAConversion);
480 fillPhiNodeContents(cUnit);
481
482 /* Constant propagation */
483 cUnit->isConstantV = dvmAllocBitVector(cUnit->numSSARegs, false);
484 cUnit->constantValues = dvmCompilerNew(sizeof(int) * cUnit->numSSARegs,
485 true);
486 dvmCompilerDataFlowAnalysisDispatcher(cUnit,
487 dvmCompilerDoConstantPropagation);
488 DEBUG_LOOP(dumpConstants(cUnit);)
489
490 /* Find induction variables - basic and dependent */
491 loopAnalysis->ivList = dvmCompilerNew(sizeof(GrowableList), true);
492 dvmInitGrowableList(loopAnalysis->ivList, 4);
493 loopAnalysis->isIndVarV = dvmAllocBitVector(cUnit->numSSARegs, false);
494 dvmCompilerDataFlowAnalysisDispatcher(cUnit,
495 dvmCompilerFindInductionVariables);
496 DEBUG_LOOP(dumpIVList(cUnit);)
497
498 /* If the loop turns out to be non-optimizable, return early */
499 if (!isLoopOptimizable(cUnit))
500 return;
501
502 loopAnalysis->arrayAccessInfo = dvmCompilerNew(sizeof(GrowableList), true);
503 dvmInitGrowableList(loopAnalysis->arrayAccessInfo, 4);
504 loopAnalysis->bodyIsClean = doLoopBodyCodeMotion(cUnit);
505 DEBUG_LOOP(dumpHoistedChecks(cUnit);)
506
507 /*
508 * Convert the array access information into extended MIR code in the loop
509 * header.
510 */
511 genHoistedChecks(cUnit);
512}