blob: 0ceaa9f55e68d40664a7e7739fb599d9c668b990 [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{
Ben Cheng4238ec22009-08-24 16:32:22 -0700266 BasicBlock *loopBody = cUnit->blockList[1];
267 MIR *mir;
268 bool loopBodyCanThrow = false;
Ben Cheng4238ec22009-08-24 16:32:22 -0700269
270 for (mir = loopBody->firstMIRInsn; mir; mir = mir->next) {
271 DecodedInstruction *dInsn = &mir->dalvikInsn;
272 int dfAttributes =
273 dvmCompilerDataFlowAttributes[mir->dalvikInsn.opCode];
274
275 /* Skip extended MIR instructions */
276 if (dInsn->opCode > 255) continue;
277
278 int instrFlags = dexGetInstrFlags(gDvm.instrFlags, dInsn->opCode);
279
280 /* Instruction is clean */
281 if ((instrFlags & kInstrCanThrow) == 0) continue;
282
283 /*
284 * Currently we can only optimize away null and range checks. Punt on
285 * instructions that can throw due to other exceptions.
286 */
287 if (!(dfAttributes & DF_HAS_NR_CHECKS)) {
288 loopBodyCanThrow = true;
289 continue;
290 }
291
292 /*
293 * This comparison is redundant now, but we will have more than one
294 * group of flags to check soon.
295 */
296 if (dfAttributes & DF_HAS_NR_CHECKS) {
297 /*
298 * Check if the null check is applied on a loop invariant register?
299 * If the register's SSA id is less than the number of Dalvik
300 * registers, then it is loop invariant.
301 */
302 int refIdx;
303 switch (dfAttributes & DF_HAS_NR_CHECKS) {
304 case DF_NULL_N_RANGE_CHECK_0:
305 refIdx = 0;
306 break;
307 case DF_NULL_N_RANGE_CHECK_1:
308 refIdx = 1;
309 break;
310 case DF_NULL_N_RANGE_CHECK_2:
311 refIdx = 2;
312 break;
313 default:
314 refIdx = 0;
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800315 LOGE("Jit: bad case in doLoopBodyCodeMotion");
316 dvmCompilerAbort(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -0700317 }
318
319 int useIdx = refIdx + 1;
320 int subNRegArray =
321 dvmConvertSSARegToDalvik(cUnit, mir->ssaRep->uses[refIdx]);
Ben Cheng4238ec22009-08-24 16:32:22 -0700322 int arraySub = DECODE_SUB(subNRegArray);
323
324 /*
325 * If the register is never updated in the loop (ie subscript == 0),
326 * it is an optimization candidate.
327 */
328 if (arraySub != 0) {
329 loopBodyCanThrow = true;
330 continue;
331 }
332
333 /*
334 * Then check if the range check can be hoisted out of the loop if
335 * it is basic or dependent induction variable.
336 */
337 if (dvmIsBitSet(cUnit->loopAnalysis->isIndVarV,
338 mir->ssaRep->uses[useIdx])) {
339 mir->OptimizationFlags |=
340 MIR_IGNORE_RANGE_CHECK | MIR_IGNORE_NULL_CHECK;
341 updateRangeCheckInfo(cUnit, mir->ssaRep->uses[refIdx],
342 mir->ssaRep->uses[useIdx]);
343 }
344 }
345 }
346
347 return !loopBodyCanThrow;
348}
349
350static void dumpHoistedChecks(CompilationUnit *cUnit)
351{
Ben Cheng4238ec22009-08-24 16:32:22 -0700352 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
353 unsigned int i;
354
355 for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
356 ArrayAccessInfo *arrayAccessInfo =
357 GET_ELEM_N(loopAnalysis->arrayAccessInfo,
358 ArrayAccessInfo*, i);
359 int arrayReg = DECODE_REG(
360 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
361 int idxReg = DECODE_REG(
362 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
363 LOGE("Array access %d", i);
364 LOGE(" arrayReg %d", arrayReg);
365 LOGE(" idxReg %d", idxReg);
366 LOGE(" endReg %d", loopAnalysis->endConditionReg);
367 LOGE(" maxC %d", arrayAccessInfo->maxC);
368 LOGE(" minC %d", arrayAccessInfo->minC);
369 LOGE(" opcode %d", loopAnalysis->loopBranchOpcode);
370 }
371}
372
373static void genHoistedChecks(CompilationUnit *cUnit)
374{
375 unsigned int i;
376 BasicBlock *entry = cUnit->blockList[0];
377 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
Ben Cheng4238ec22009-08-24 16:32:22 -0700378 int globalMaxC = 0;
379 int globalMinC = 0;
380 /* Should be loop invariant */
381 int idxReg = 0;
382
383 for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
384 ArrayAccessInfo *arrayAccessInfo =
385 GET_ELEM_N(loopAnalysis->arrayAccessInfo,
386 ArrayAccessInfo*, i);
387 int arrayReg = DECODE_REG(
388 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
389 idxReg = DECODE_REG(
390 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
391
392 MIR *rangeCheckMIR = dvmCompilerNew(sizeof(MIR), true);
393 rangeCheckMIR->dalvikInsn.opCode = (loopAnalysis->isCountUpLoop) ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700394 kMirOpNullNRangeUpCheck : kMirOpNullNRangeDownCheck;
Ben Cheng4238ec22009-08-24 16:32:22 -0700395 rangeCheckMIR->dalvikInsn.vA = arrayReg;
396 rangeCheckMIR->dalvikInsn.vB = idxReg;
397 rangeCheckMIR->dalvikInsn.vC = loopAnalysis->endConditionReg;
398 rangeCheckMIR->dalvikInsn.arg[0] = arrayAccessInfo->maxC;
399 rangeCheckMIR->dalvikInsn.arg[1] = arrayAccessInfo->minC;
400 rangeCheckMIR->dalvikInsn.arg[2] = loopAnalysis->loopBranchOpcode;
401 dvmCompilerAppendMIR(entry, rangeCheckMIR);
402 if (arrayAccessInfo->maxC > globalMaxC) {
403 globalMaxC = arrayAccessInfo->maxC;
404 }
405 if (arrayAccessInfo->minC < globalMinC) {
406 globalMinC = arrayAccessInfo->minC;
407 }
408 }
409
410 if (loopAnalysis->arrayAccessInfo->numUsed != 0) {
411 if (loopAnalysis->isCountUpLoop) {
412 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700413 boundCheckMIR->dalvikInsn.opCode = kMirOpLowerBound;
Ben Cheng4238ec22009-08-24 16:32:22 -0700414 boundCheckMIR->dalvikInsn.vA = idxReg;
415 boundCheckMIR->dalvikInsn.vB = globalMinC;
416 dvmCompilerAppendMIR(entry, boundCheckMIR);
417 } else {
418 if (loopAnalysis->loopBranchOpcode == OP_IF_LT ||
419 loopAnalysis->loopBranchOpcode == OP_IF_LE) {
420 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700421 boundCheckMIR->dalvikInsn.opCode = kMirOpLowerBound;
Ben Cheng4238ec22009-08-24 16:32:22 -0700422 boundCheckMIR->dalvikInsn.vA = loopAnalysis->endConditionReg;
423 boundCheckMIR->dalvikInsn.vB = globalMinC;
424 /*
425 * If the end condition is ">", add 1 back to the constant field
426 * to reflect the fact that the smallest index value is
427 * "endValue + constant + 1".
428 */
429 if (loopAnalysis->loopBranchOpcode == OP_IF_LT) {
430 boundCheckMIR->dalvikInsn.vB++;
431 }
432 dvmCompilerAppendMIR(entry, boundCheckMIR);
433 } else if (loopAnalysis->loopBranchOpcode == OP_IF_LTZ) {
434 /* Array index will fall below 0 */
435 if (globalMinC < 0) {
436 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700437 boundCheckMIR->dalvikInsn.opCode = kMirOpPunt;
Ben Cheng4238ec22009-08-24 16:32:22 -0700438 dvmCompilerAppendMIR(entry, boundCheckMIR);
439 }
440 } else if (loopAnalysis->loopBranchOpcode == OP_IF_LEZ) {
441 /* Array index will fall below 0 */
442 if (globalMinC < -1) {
443 MIR *boundCheckMIR = dvmCompilerNew(sizeof(MIR), true);
Bill Buzbee1465db52009-09-23 17:17:35 -0700444 boundCheckMIR->dalvikInsn.opCode = kMirOpPunt;
Ben Cheng4238ec22009-08-24 16:32:22 -0700445 dvmCompilerAppendMIR(entry, boundCheckMIR);
446 }
447 } else {
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800448 LOGE("Jit: bad case in genHoistedChecks");
449 dvmCompilerAbort(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -0700450 }
451 }
452
453 }
454}
455
456/* Main entry point to do loop optimization */
457void dvmCompilerLoopOpt(CompilationUnit *cUnit)
458{
Ben Cheng4238ec22009-08-24 16:32:22 -0700459 LoopAnalysis *loopAnalysis = dvmCompilerNew(sizeof(LoopAnalysis), true);
460
Bill Buzbee1465db52009-09-23 17:17:35 -0700461 assert(cUnit->blockList[0]->blockType == kEntryBlock);
462 assert(cUnit->blockList[2]->blockType == kDalvikByteCode);
463 assert(cUnit->blockList[3]->blockType == kExitBlock);
Ben Cheng4238ec22009-08-24 16:32:22 -0700464
465 cUnit->loopAnalysis = loopAnalysis;
466 /*
467 * Find live-in variables to the loop body so that we can fake their
468 * definitions in the entry block.
469 */
470 dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerFindLiveIn);
471
472 /* Insert phi nodes to the loop body */
473 handlePhiPlacement(cUnit);
474
475 dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerDoSSAConversion);
476 fillPhiNodeContents(cUnit);
477
478 /* Constant propagation */
479 cUnit->isConstantV = dvmAllocBitVector(cUnit->numSSARegs, false);
480 cUnit->constantValues = dvmCompilerNew(sizeof(int) * cUnit->numSSARegs,
481 true);
482 dvmCompilerDataFlowAnalysisDispatcher(cUnit,
483 dvmCompilerDoConstantPropagation);
484 DEBUG_LOOP(dumpConstants(cUnit);)
485
486 /* Find induction variables - basic and dependent */
487 loopAnalysis->ivList = dvmCompilerNew(sizeof(GrowableList), true);
488 dvmInitGrowableList(loopAnalysis->ivList, 4);
489 loopAnalysis->isIndVarV = dvmAllocBitVector(cUnit->numSSARegs, false);
490 dvmCompilerDataFlowAnalysisDispatcher(cUnit,
491 dvmCompilerFindInductionVariables);
492 DEBUG_LOOP(dumpIVList(cUnit);)
493
494 /* If the loop turns out to be non-optimizable, return early */
495 if (!isLoopOptimizable(cUnit))
496 return;
497
498 loopAnalysis->arrayAccessInfo = dvmCompilerNew(sizeof(GrowableList), true);
499 dvmInitGrowableList(loopAnalysis->arrayAccessInfo, 4);
500 loopAnalysis->bodyIsClean = doLoopBodyCodeMotion(cUnit);
501 DEBUG_LOOP(dumpHoistedChecks(cUnit);)
502
503 /*
504 * Convert the array access information into extended MIR code in the loop
505 * header.
506 */
507 genHoistedChecks(cUnit);
508}