blob: b9ad3d364a96fc4338861a588f11d670644810f2 [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{
Ben Cheng00603072010-10-28 11:13:58 -070041 BasicBlock *entry =
42 (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 0);
43 BasicBlock *loopBody =
44 (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 1);
45 BasicBlock *loopBranch =
46 (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 2);
Ben Cheng4238ec22009-08-24 16:32:22 -070047 dvmCopyBitVector(entry->dataFlowInfo->defV,
48 loopBody->dataFlowInfo->liveInV);
49
50 BitVector *phiV = dvmCompilerAllocBitVector(cUnit->method->registersSize,
51 false);
Ben Cheng00603072010-10-28 11:13:58 -070052 BitVector *phi2V = dvmCompilerAllocBitVector(cUnit->method->registersSize,
53 false);
Ben Cheng4238ec22009-08-24 16:32:22 -070054 dvmIntersectBitVectors(phiV, entry->dataFlowInfo->defV,
55 loopBody->dataFlowInfo->defV);
Ben Cheng00603072010-10-28 11:13:58 -070056 dvmIntersectBitVectors(phi2V, entry->dataFlowInfo->defV,
Ben Cheng4238ec22009-08-24 16:32:22 -070057 loopBranch->dataFlowInfo->defV);
Ben Cheng00603072010-10-28 11:13:58 -070058 dvmUnifyBitVectors(phiV, phiV, phi2V);
Ben Cheng4238ec22009-08-24 16:32:22 -070059
60 /* Insert the PHI MIRs */
61 int i;
62 for (i = 0; i < cUnit->method->registersSize; i++) {
63 if (!dvmIsBitSet(phiV, i)) {
64 continue;
65 }
Carl Shapirofc75f3e2010-12-07 11:43:38 -080066 MIR *phi = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -080067 phi->dalvikInsn.opcode = kMirOpPhi;
Ben Cheng4238ec22009-08-24 16:32:22 -070068 phi->dalvikInsn.vA = i;
69 dvmCompilerPrependMIR(loopBody, phi);
70 }
71}
72
73static void fillPhiNodeContents(CompilationUnit *cUnit)
74{
Ben Cheng00603072010-10-28 11:13:58 -070075 BasicBlock *entry =
76 (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 0);
77 BasicBlock *loopBody =
78 (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 1);
79 BasicBlock *loopBranch =
80 (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 2);
Ben Cheng4238ec22009-08-24 16:32:22 -070081 MIR *mir;
82
83 for (mir = loopBody->firstMIRInsn; mir; mir = mir->next) {
Dan Bornstein9a1f8162010-12-01 17:02:26 -080084 if (mir->dalvikInsn.opcode != kMirOpPhi) break;
Ben Cheng4238ec22009-08-24 16:32:22 -070085 int dalvikReg = mir->dalvikInsn.vA;
86
87 mir->ssaRep->numUses = 2;
Carl Shapirofc75f3e2010-12-07 11:43:38 -080088 mir->ssaRep->uses = (int *)dvmCompilerNew(sizeof(int) * 2, false);
Ben Cheng4238ec22009-08-24 16:32:22 -070089 mir->ssaRep->uses[0] =
90 DECODE_REG(entry->dataFlowInfo->dalvikToSSAMap[dalvikReg]);
91 mir->ssaRep->uses[1] =
92 DECODE_REG(loopBranch->dataFlowInfo->dalvikToSSAMap[dalvikReg]);
93 }
94
95
96}
97
Ben Chengfc075c22010-05-28 15:20:08 -070098#if 0
99/* Debugging routines */
Ben Cheng4238ec22009-08-24 16:32:22 -0700100static void dumpConstants(CompilationUnit *cUnit)
101{
102 int i;
103 for (i = 0; i < cUnit->numSSARegs; i++) {
104 if (dvmIsBitSet(cUnit->isConstantV, i)) {
105 int subNReg = dvmConvertSSARegToDalvik(cUnit, i);
106 LOGE("s%d(v%d_%d) has %d", i,
107 DECODE_REG(subNReg), DECODE_SUB(subNReg),
108 cUnit->constantValues[i]);
109 }
110 }
111}
112
113static void dumpIVList(CompilationUnit *cUnit)
114{
115 unsigned int i;
116 GrowableList *ivList = cUnit->loopAnalysis->ivList;
117 int *ssaToDalvikMap = (int *) cUnit->ssaToDalvikMap->elemList;
118
119 for (i = 0; i < ivList->numUsed; i++) {
120 InductionVariableInfo *ivInfo = ivList->elemList[i];
121 /* Basic IV */
122 if (ivInfo->ssaReg == ivInfo->basicSSAReg) {
123 LOGE("BIV %d: s%d(v%d) + %d", i,
124 ivInfo->ssaReg,
125 ssaToDalvikMap[ivInfo->ssaReg] & 0xffff,
126 ivInfo->inc);
127 /* Dependent IV */
128 } else {
129 LOGE("DIV %d: s%d(v%d) = %d * s%d(v%d) + %d", i,
130 ivInfo->ssaReg,
131 ssaToDalvikMap[ivInfo->ssaReg] & 0xffff,
132 ivInfo->m,
133 ivInfo->basicSSAReg,
134 ssaToDalvikMap[ivInfo->basicSSAReg] & 0xffff,
135 ivInfo->c);
136 }
137 }
138}
139
Ben Chengfc075c22010-05-28 15:20:08 -0700140static void dumpHoistedChecks(CompilationUnit *cUnit)
141{
142 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
143 unsigned int i;
144
145 for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
146 ArrayAccessInfo *arrayAccessInfo =
147 GET_ELEM_N(loopAnalysis->arrayAccessInfo,
148 ArrayAccessInfo*, i);
149 int arrayReg = DECODE_REG(
150 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
151 int idxReg = DECODE_REG(
152 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
153 LOGE("Array access %d", i);
154 LOGE(" arrayReg %d", arrayReg);
155 LOGE(" idxReg %d", idxReg);
156 LOGE(" endReg %d", loopAnalysis->endConditionReg);
157 LOGE(" maxC %d", arrayAccessInfo->maxC);
158 LOGE(" minC %d", arrayAccessInfo->minC);
159 LOGE(" opcode %d", loopAnalysis->loopBranchOpcode);
160 }
161}
162
163#endif
164
Ben Cheng4238ec22009-08-24 16:32:22 -0700165/*
166 * A loop is considered optimizable if:
167 * 1) It has one basic induction variable
168 * 2) The loop back branch compares the BIV with a constant
169 * 3) If it is a count-up loop, the condition is GE/GT, or LE/LT/LEZ/LTZ for
170 * a count-down loop.
Ben Cheng4a419582010-08-04 13:23:09 -0700171 *
172 * Return false if the loop is not optimizable.
Ben Cheng4238ec22009-08-24 16:32:22 -0700173 */
174static bool isLoopOptimizable(CompilationUnit *cUnit)
175{
176 unsigned int i;
Ben Cheng00603072010-10-28 11:13:58 -0700177 BasicBlock *loopBranch =
178 (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 2);
Ben Cheng4238ec22009-08-24 16:32:22 -0700179 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
180
181 if (loopAnalysis->numBasicIV != 1) return false;
182 for (i = 0; i < loopAnalysis->ivList->numUsed; i++) {
183 InductionVariableInfo *ivInfo;
184
185 ivInfo = GET_ELEM_N(loopAnalysis->ivList, InductionVariableInfo*, i);
186 /* Count up or down loop? */
187 if (ivInfo->ssaReg == ivInfo->basicSSAReg) {
Ben Cheng4a419582010-08-04 13:23:09 -0700188 /* Infinite loop */
189 if (ivInfo->inc == 0) {
190 return false;
191 }
Ben Cheng4238ec22009-08-24 16:32:22 -0700192 loopAnalysis->isCountUpLoop = ivInfo->inc > 0;
193 break;
194 }
195 }
196
197 MIR *branch = loopBranch->lastMIRInsn;
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800198 Opcode opcode = branch->dalvikInsn.opcode;
Ben Cheng4238ec22009-08-24 16:32:22 -0700199
200 /*
201 * If the instruction is not accessing the IV as the first operand, return
202 * false.
203 */
204 if (branch->ssaRep->numUses == 0 || branch->ssaRep->numDefs != 0) {
205 return false;
206 }
207
208 /*
209 * If the first operand of the comparison is not the basic induction
210 * variable, return false.
211 */
212 if (branch->ssaRep->uses[0] != loopAnalysis->ssaBIV) {
213 return false;
214 }
215
216 if (loopAnalysis->isCountUpLoop) {
217 /*
218 * If the condition op is not > or >=, this is not an optimization
219 * candidate.
220 */
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800221 if (opcode != OP_IF_GT && opcode != OP_IF_GE) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700222 return false;
223 }
224 /*
225 * If the comparison is not between the BIV and a loop invariant,
Ben Cheng4a419582010-08-04 13:23:09 -0700226 * return false. endReg is loop invariant if one of the following is
227 * true:
228 * - It is not defined in the loop (ie DECODE_SUB returns 0)
229 * - It is reloaded with a constant
Ben Cheng4238ec22009-08-24 16:32:22 -0700230 */
231 int endReg = dvmConvertSSARegToDalvik(cUnit, branch->ssaRep->uses[1]);
Ben Cheng4a419582010-08-04 13:23:09 -0700232 if (DECODE_SUB(endReg) != 0 &&
233 !dvmIsBitSet(cUnit->isConstantV, branch->ssaRep->uses[1])) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700234 return false;
235 }
236 loopAnalysis->endConditionReg = DECODE_REG(endReg);
237 } else {
238 /*
239 * If the condition op is not < or <=, this is not an optimization
240 * candidate.
241 */
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800242 if (opcode == OP_IF_LT || opcode == OP_IF_LE) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700243 /*
244 * If the comparison is not between the BIV and a loop invariant,
245 * return false.
246 */
247 int endReg = dvmConvertSSARegToDalvik(cUnit,
248 branch->ssaRep->uses[1]);
249
250 if (DECODE_SUB(endReg) != 0) {
251 return false;
252 }
253 loopAnalysis->endConditionReg = DECODE_REG(endReg);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800254 } else if (opcode != OP_IF_LTZ && opcode != OP_IF_LEZ) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700255 return false;
256 }
257 }
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800258 loopAnalysis->loopBranchOpcode = opcode;
Ben Cheng4238ec22009-08-24 16:32:22 -0700259 return true;
260}
261
262/*
263 * Record the upper and lower bound information for range checks for each
264 * induction variable. If array A is accessed by index "i+5", the upper and
265 * lower bound will be len(A)-5 and -5, respectively.
266 */
267static void updateRangeCheckInfo(CompilationUnit *cUnit, int arrayReg,
268 int idxReg)
269{
270 InductionVariableInfo *ivInfo;
271 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
272 unsigned int i, j;
273
274 for (i = 0; i < loopAnalysis->ivList->numUsed; i++) {
275 ivInfo = GET_ELEM_N(loopAnalysis->ivList, InductionVariableInfo*, i);
276 if (ivInfo->ssaReg == idxReg) {
277 ArrayAccessInfo *arrayAccessInfo = NULL;
278 for (j = 0; j < loopAnalysis->arrayAccessInfo->numUsed; j++) {
279 ArrayAccessInfo *existingArrayAccessInfo =
280 GET_ELEM_N(loopAnalysis->arrayAccessInfo,
281 ArrayAccessInfo*,
282 j);
283 if (existingArrayAccessInfo->arrayReg == arrayReg) {
284 if (ivInfo->c > existingArrayAccessInfo->maxC) {
285 existingArrayAccessInfo->maxC = ivInfo->c;
286 }
287 if (ivInfo->c < existingArrayAccessInfo->minC) {
288 existingArrayAccessInfo->minC = ivInfo->c;
289 }
290 arrayAccessInfo = existingArrayAccessInfo;
291 break;
292 }
293 }
294 if (arrayAccessInfo == NULL) {
295 arrayAccessInfo =
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800296 (ArrayAccessInfo *)dvmCompilerNew(sizeof(ArrayAccessInfo),
297 false);
Ben Cheng4238ec22009-08-24 16:32:22 -0700298 arrayAccessInfo->ivReg = ivInfo->basicSSAReg;
299 arrayAccessInfo->arrayReg = arrayReg;
300 arrayAccessInfo->maxC = (ivInfo->c > 0) ? ivInfo->c : 0;
301 arrayAccessInfo->minC = (ivInfo->c < 0) ? ivInfo->c : 0;
302 dvmInsertGrowableList(loopAnalysis->arrayAccessInfo,
Ben Cheng00603072010-10-28 11:13:58 -0700303 (intptr_t) arrayAccessInfo);
Ben Cheng4238ec22009-08-24 16:32:22 -0700304 }
305 break;
306 }
307 }
308}
309
310/* Returns true if the loop body cannot throw any exceptions */
311static bool doLoopBodyCodeMotion(CompilationUnit *cUnit)
312{
Ben Cheng00603072010-10-28 11:13:58 -0700313 BasicBlock *loopBody =
314 (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 1);
Ben Cheng4238ec22009-08-24 16:32:22 -0700315 MIR *mir;
316 bool loopBodyCanThrow = false;
Ben Cheng4238ec22009-08-24 16:32:22 -0700317
318 for (mir = loopBody->firstMIRInsn; mir; mir = mir->next) {
319 DecodedInstruction *dInsn = &mir->dalvikInsn;
320 int dfAttributes =
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800321 dvmCompilerDataFlowAttributes[mir->dalvikInsn.opcode];
Ben Cheng4238ec22009-08-24 16:32:22 -0700322
323 /* Skip extended MIR instructions */
Dan Bornsteinccaab182010-12-03 15:32:40 -0800324 if (dInsn->opcode >= kNumPackedOpcodes) continue;
Ben Cheng4238ec22009-08-24 16:32:22 -0700325
Dan Bornsteine4852762010-12-02 12:45:00 -0800326 int instrFlags = dexGetFlagsFromOpcode(dInsn->opcode);
Ben Cheng4238ec22009-08-24 16:32:22 -0700327
328 /* Instruction is clean */
329 if ((instrFlags & kInstrCanThrow) == 0) continue;
330
331 /*
332 * Currently we can only optimize away null and range checks. Punt on
333 * instructions that can throw due to other exceptions.
334 */
335 if (!(dfAttributes & DF_HAS_NR_CHECKS)) {
336 loopBodyCanThrow = true;
337 continue;
338 }
339
340 /*
341 * This comparison is redundant now, but we will have more than one
342 * group of flags to check soon.
343 */
344 if (dfAttributes & DF_HAS_NR_CHECKS) {
345 /*
346 * Check if the null check is applied on a loop invariant register?
347 * If the register's SSA id is less than the number of Dalvik
348 * registers, then it is loop invariant.
349 */
350 int refIdx;
351 switch (dfAttributes & DF_HAS_NR_CHECKS) {
352 case DF_NULL_N_RANGE_CHECK_0:
353 refIdx = 0;
354 break;
355 case DF_NULL_N_RANGE_CHECK_1:
356 refIdx = 1;
357 break;
358 case DF_NULL_N_RANGE_CHECK_2:
359 refIdx = 2;
360 break;
361 default:
362 refIdx = 0;
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800363 LOGE("Jit: bad case in doLoopBodyCodeMotion");
364 dvmCompilerAbort(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -0700365 }
366
367 int useIdx = refIdx + 1;
368 int subNRegArray =
369 dvmConvertSSARegToDalvik(cUnit, mir->ssaRep->uses[refIdx]);
Ben Cheng4238ec22009-08-24 16:32:22 -0700370 int arraySub = DECODE_SUB(subNRegArray);
371
372 /*
373 * If the register is never updated in the loop (ie subscript == 0),
374 * it is an optimization candidate.
375 */
376 if (arraySub != 0) {
377 loopBodyCanThrow = true;
378 continue;
379 }
380
381 /*
382 * Then check if the range check can be hoisted out of the loop if
383 * it is basic or dependent induction variable.
384 */
385 if (dvmIsBitSet(cUnit->loopAnalysis->isIndVarV,
386 mir->ssaRep->uses[useIdx])) {
387 mir->OptimizationFlags |=
388 MIR_IGNORE_RANGE_CHECK | MIR_IGNORE_NULL_CHECK;
389 updateRangeCheckInfo(cUnit, mir->ssaRep->uses[refIdx],
390 mir->ssaRep->uses[useIdx]);
391 }
392 }
393 }
394
395 return !loopBodyCanThrow;
396}
397
Ben Cheng4238ec22009-08-24 16:32:22 -0700398static void genHoistedChecks(CompilationUnit *cUnit)
399{
400 unsigned int i;
Ben Cheng00603072010-10-28 11:13:58 -0700401 BasicBlock *entry =
402 (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 0);
Ben Cheng4238ec22009-08-24 16:32:22 -0700403 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
Ben Cheng4238ec22009-08-24 16:32:22 -0700404 int globalMaxC = 0;
405 int globalMinC = 0;
406 /* Should be loop invariant */
407 int idxReg = 0;
408
409 for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
410 ArrayAccessInfo *arrayAccessInfo =
411 GET_ELEM_N(loopAnalysis->arrayAccessInfo,
412 ArrayAccessInfo*, i);
413 int arrayReg = DECODE_REG(
414 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
415 idxReg = DECODE_REG(
416 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
417
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800418 MIR *rangeCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800419 rangeCheckMIR->dalvikInsn.opcode = (loopAnalysis->isCountUpLoop) ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700420 kMirOpNullNRangeUpCheck : kMirOpNullNRangeDownCheck;
Ben Cheng4238ec22009-08-24 16:32:22 -0700421 rangeCheckMIR->dalvikInsn.vA = arrayReg;
422 rangeCheckMIR->dalvikInsn.vB = idxReg;
423 rangeCheckMIR->dalvikInsn.vC = loopAnalysis->endConditionReg;
424 rangeCheckMIR->dalvikInsn.arg[0] = arrayAccessInfo->maxC;
425 rangeCheckMIR->dalvikInsn.arg[1] = arrayAccessInfo->minC;
426 rangeCheckMIR->dalvikInsn.arg[2] = loopAnalysis->loopBranchOpcode;
427 dvmCompilerAppendMIR(entry, rangeCheckMIR);
428 if (arrayAccessInfo->maxC > globalMaxC) {
429 globalMaxC = arrayAccessInfo->maxC;
430 }
431 if (arrayAccessInfo->minC < globalMinC) {
432 globalMinC = arrayAccessInfo->minC;
433 }
434 }
435
436 if (loopAnalysis->arrayAccessInfo->numUsed != 0) {
437 if (loopAnalysis->isCountUpLoop) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800438 MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800439 boundCheckMIR->dalvikInsn.opcode = kMirOpLowerBound;
Ben Cheng4238ec22009-08-24 16:32:22 -0700440 boundCheckMIR->dalvikInsn.vA = idxReg;
441 boundCheckMIR->dalvikInsn.vB = globalMinC;
442 dvmCompilerAppendMIR(entry, boundCheckMIR);
443 } else {
444 if (loopAnalysis->loopBranchOpcode == OP_IF_LT ||
445 loopAnalysis->loopBranchOpcode == OP_IF_LE) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800446 MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800447 boundCheckMIR->dalvikInsn.opcode = kMirOpLowerBound;
Ben Cheng4238ec22009-08-24 16:32:22 -0700448 boundCheckMIR->dalvikInsn.vA = loopAnalysis->endConditionReg;
449 boundCheckMIR->dalvikInsn.vB = globalMinC;
450 /*
Ben Cheng36bd1342010-10-25 20:54:31 -0700451 * If the end condition is ">" in the source, the check in the
452 * Dalvik bytecode is OP_IF_LE. In this case add 1 back to the
453 * constant field to reflect the fact that the smallest index
454 * value is "endValue + constant + 1".
Ben Cheng4238ec22009-08-24 16:32:22 -0700455 */
Ben Cheng36bd1342010-10-25 20:54:31 -0700456 if (loopAnalysis->loopBranchOpcode == OP_IF_LE) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700457 boundCheckMIR->dalvikInsn.vB++;
458 }
459 dvmCompilerAppendMIR(entry, boundCheckMIR);
460 } else if (loopAnalysis->loopBranchOpcode == OP_IF_LTZ) {
461 /* Array index will fall below 0 */
462 if (globalMinC < 0) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800463 MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800464 boundCheckMIR->dalvikInsn.opcode = kMirOpPunt;
Ben Cheng4238ec22009-08-24 16:32:22 -0700465 dvmCompilerAppendMIR(entry, boundCheckMIR);
466 }
467 } else if (loopAnalysis->loopBranchOpcode == OP_IF_LEZ) {
468 /* Array index will fall below 0 */
469 if (globalMinC < -1) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800470 MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800471 boundCheckMIR->dalvikInsn.opcode = kMirOpPunt;
Ben Cheng4238ec22009-08-24 16:32:22 -0700472 dvmCompilerAppendMIR(entry, boundCheckMIR);
473 }
474 } else {
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800475 LOGE("Jit: bad case in genHoistedChecks");
476 dvmCompilerAbort(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -0700477 }
478 }
479
480 }
481}
482
Ben Cheng4a419582010-08-04 13:23:09 -0700483/*
484 * Main entry point to do loop optimization.
485 * Return false if sanity checks for loop formation/optimization failed.
486 */
487bool dvmCompilerLoopOpt(CompilationUnit *cUnit)
Ben Cheng4238ec22009-08-24 16:32:22 -0700488{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800489 LoopAnalysis *loopAnalysis =
490 (LoopAnalysis *)dvmCompilerNew(sizeof(LoopAnalysis), true);
Ben Cheng4238ec22009-08-24 16:32:22 -0700491
Ben Cheng00603072010-10-28 11:13:58 -0700492 assert(((BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 0))
493 ->blockType == kTraceEntryBlock);
494 assert(((BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 2))
495 ->blockType == kDalvikByteCode);
496 assert(((BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList, 3))
497 ->blockType == kTraceExitBlock);
Ben Cheng4238ec22009-08-24 16:32:22 -0700498
499 cUnit->loopAnalysis = loopAnalysis;
500 /*
501 * Find live-in variables to the loop body so that we can fake their
502 * definitions in the entry block.
503 */
Ben Cheng00603072010-10-28 11:13:58 -0700504 dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerFindLocalLiveIn,
505 kAllNodes,
506 false /* isIterative */);
Ben Cheng4238ec22009-08-24 16:32:22 -0700507
508 /* Insert phi nodes to the loop body */
509 handlePhiPlacement(cUnit);
510
Ben Cheng00603072010-10-28 11:13:58 -0700511 dvmCompilerDataFlowAnalysisDispatcher(cUnit, dvmCompilerDoSSAConversion,
512 kAllNodes,
513 false /* isIterative */);
Ben Cheng4238ec22009-08-24 16:32:22 -0700514 fillPhiNodeContents(cUnit);
515
516 /* Constant propagation */
517 cUnit->isConstantV = dvmAllocBitVector(cUnit->numSSARegs, false);
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800518 cUnit->constantValues =
519 (int *)dvmCompilerNew(sizeof(int) * cUnit->numSSARegs,
520 true);
Ben Cheng4238ec22009-08-24 16:32:22 -0700521 dvmCompilerDataFlowAnalysisDispatcher(cUnit,
Ben Cheng00603072010-10-28 11:13:58 -0700522 dvmCompilerDoConstantPropagation,
523 kAllNodes,
524 false /* isIterative */);
Ben Cheng4238ec22009-08-24 16:32:22 -0700525 DEBUG_LOOP(dumpConstants(cUnit);)
526
527 /* Find induction variables - basic and dependent */
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800528 loopAnalysis->ivList =
529 (GrowableList *)dvmCompilerNew(sizeof(GrowableList), true);
Ben Cheng4238ec22009-08-24 16:32:22 -0700530 dvmInitGrowableList(loopAnalysis->ivList, 4);
531 loopAnalysis->isIndVarV = dvmAllocBitVector(cUnit->numSSARegs, false);
532 dvmCompilerDataFlowAnalysisDispatcher(cUnit,
Ben Cheng00603072010-10-28 11:13:58 -0700533 dvmCompilerFindInductionVariables,
534 kAllNodes,
535 false /* isIterative */);
Ben Cheng4238ec22009-08-24 16:32:22 -0700536 DEBUG_LOOP(dumpIVList(cUnit);)
537
538 /* If the loop turns out to be non-optimizable, return early */
539 if (!isLoopOptimizable(cUnit))
Ben Cheng4a419582010-08-04 13:23:09 -0700540 return false;
Ben Cheng4238ec22009-08-24 16:32:22 -0700541
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800542 loopAnalysis->arrayAccessInfo =
543 (GrowableList *)dvmCompilerNew(sizeof(GrowableList), true);
Ben Cheng4238ec22009-08-24 16:32:22 -0700544 dvmInitGrowableList(loopAnalysis->arrayAccessInfo, 4);
545 loopAnalysis->bodyIsClean = doLoopBodyCodeMotion(cUnit);
546 DEBUG_LOOP(dumpHoistedChecks(cUnit);)
547
548 /*
549 * Convert the array access information into extended MIR code in the loop
550 * header.
551 */
552 genHoistedChecks(cUnit);
Ben Cheng4a419582010-08-04 13:23:09 -0700553 return true;
Ben Cheng4238ec22009-08-24 16:32:22 -0700554}
Ben Cheng46cd4fb2011-03-16 17:19:06 -0700555
556void resetBlockEdges(BasicBlock *bb)
557{
558 bb->taken = NULL;
559 bb->fallThrough = NULL;
560 bb->successorBlockList.blockListType = kNotUsed;
561}
562
563static bool clearPredecessorVector(struct CompilationUnit *cUnit,
564 struct BasicBlock *bb)
565{
566 dvmClearAllBits(bb->predecessors);
567 return false;
568}
569
570bool dvmCompilerFilterLoopBlocks(CompilationUnit *cUnit)
571{
572 BasicBlock *firstBB = cUnit->entryBlock->fallThrough;
573
574 int numPred = dvmCountSetBits(firstBB->predecessors);
575 /*
576 * A loop body should have at least two incoming edges. Here we go with the
577 * simple case and only form loops if numPred == 2.
578 */
579 if (numPred != 2) return false;
580
581 BitVectorIterator bvIterator;
582 GrowableList *blockList = &cUnit->blockList;
583 BasicBlock *predBB = NULL;
584
585 dvmBitVectorIteratorInit(firstBB->predecessors, &bvIterator);
586 while (true) {
587 int predIdx = dvmBitVectorIteratorNext(&bvIterator);
588 if (predIdx == -1) break;
589 predBB = (BasicBlock *) dvmGrowableListGetElement(blockList, predIdx);
590 if (predBB != cUnit->entryBlock) break;
591 }
592
593 /* Used to record which block is in the loop */
594 dvmClearAllBits(cUnit->tempBlockV);
595
596 dvmCompilerSetBit(cUnit->tempBlockV, predBB->id);
597
598 /* Form a loop by only including iDom block that is also a predecessor */
599 while (predBB != firstBB) {
600 BasicBlock *iDom = predBB->iDom;
601 if (!dvmIsBitSet(predBB->predecessors, iDom->id)) {
602 return false;
603 /*
604 * And don't form nested loops (ie by detecting if the branch target
605 * of iDom dominates iDom).
606 */
607 } else if (iDom->taken &&
608 dvmIsBitSet(iDom->dominators, iDom->taken->id) &&
609 iDom != firstBB) {
610 return false;
611 }
612 dvmCompilerSetBit(cUnit->tempBlockV, iDom->id);
613 predBB = iDom;
614 }
615
616 /* Add the entry block and first block */
617 dvmCompilerSetBit(cUnit->tempBlockV, firstBB->id);
618 dvmCompilerSetBit(cUnit->tempBlockV, cUnit->entryBlock->id);
619
620 /* Now mark blocks not included in the loop as hidden */
621 GrowableListIterator iterator;
622 dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
623 while (true) {
624 BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
625 if (bb == NULL) break;
626 if (!dvmIsBitSet(cUnit->tempBlockV, bb->id)) {
627 bb->hidden = true;
628 /* Clear the insn list */
629 bb->firstMIRInsn = bb->lastMIRInsn = NULL;
630 resetBlockEdges(bb);
631 }
632 }
633
634 dvmCompilerDataFlowAnalysisDispatcher(cUnit, clearPredecessorVector,
635 kAllNodes, false /* isIterative */);
636
637 dvmGrowableListIteratorInit(&cUnit->blockList, &iterator);
638 while (true) {
639 BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
640 if (bb == NULL) break;
641 if (dvmIsBitSet(cUnit->tempBlockV, bb->id)) {
642 if (bb->taken) {
643 /*
644 * exit block means we run into control-flow that we don't want
645 * to handle.
646 */
647 if (bb->taken == cUnit->exitBlock) {
648 return false;
649 }
650 if (bb->taken->hidden) {
651 bb->taken->blockType = kChainingCellNormal;
652 bb->taken->hidden = false;
653 }
654 dvmCompilerSetBit(bb->taken->predecessors, bb->id);
655 }
656 if (bb->fallThrough) {
657 /*
658 * exit block means we run into control-flow that we don't want
659 * to handle.
660 */
661 if (bb->fallThrough == cUnit->exitBlock) {
662 return false;
663 }
664 if (bb->fallThrough->hidden) {
665 bb->fallThrough->blockType = kChainingCellNormal;
666 bb->fallThrough->hidden = false;
667 }
668 dvmCompilerSetBit(bb->fallThrough->predecessors, bb->id);
669 }
670 /* Loop blocks shouldn't contain any successor blocks (yet) */
671 assert(bb->successorBlockList.blockListType == kNotUsed);
672 }
673 }
674
675 return true;
676}