blob: 54517e415752b9724eb279dc8af4046c9681ffc9 [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
Ben Chengfc075c22010-05-28 15:20:08 -070024#if 0
25/* Debugging routines */
Ben Cheng4238ec22009-08-24 16:32:22 -070026static void dumpConstants(CompilationUnit *cUnit)
27{
28 int i;
Ben Cheng32115a92011-03-22 14:09:09 -070029 LOGE("LOOP starting offset: %x", cUnit->entryBlock->startOffset);
Ben Cheng4238ec22009-08-24 16:32:22 -070030 for (i = 0; i < cUnit->numSSARegs; i++) {
31 if (dvmIsBitSet(cUnit->isConstantV, i)) {
32 int subNReg = dvmConvertSSARegToDalvik(cUnit, i);
Ben Cheng32115a92011-03-22 14:09:09 -070033 LOGE("CONST: s%d(v%d_%d) has %d", i,
Ben Cheng4238ec22009-08-24 16:32:22 -070034 DECODE_REG(subNReg), DECODE_SUB(subNReg),
35 cUnit->constantValues[i]);
36 }
37 }
38}
39
40static void dumpIVList(CompilationUnit *cUnit)
41{
42 unsigned int i;
43 GrowableList *ivList = cUnit->loopAnalysis->ivList;
Ben Cheng4238ec22009-08-24 16:32:22 -070044
45 for (i = 0; i < ivList->numUsed; i++) {
Ben Cheng32115a92011-03-22 14:09:09 -070046 InductionVariableInfo *ivInfo =
47 (InductionVariableInfo *) ivList->elemList[i];
48 int iv = dvmConvertSSARegToDalvik(cUnit, ivInfo->ssaReg);
Ben Cheng4238ec22009-08-24 16:32:22 -070049 /* Basic IV */
50 if (ivInfo->ssaReg == ivInfo->basicSSAReg) {
Ben Cheng32115a92011-03-22 14:09:09 -070051 LOGE("BIV %d: s%d(v%d_%d) + %d", i,
Ben Cheng4238ec22009-08-24 16:32:22 -070052 ivInfo->ssaReg,
Ben Cheng32115a92011-03-22 14:09:09 -070053 DECODE_REG(iv), DECODE_SUB(iv),
Ben Cheng4238ec22009-08-24 16:32:22 -070054 ivInfo->inc);
55 /* Dependent IV */
56 } else {
Ben Cheng32115a92011-03-22 14:09:09 -070057 int biv = dvmConvertSSARegToDalvik(cUnit, ivInfo->basicSSAReg);
58
59 LOGE("DIV %d: s%d(v%d_%d) = %d * s%d(v%d_%d) + %d", i,
Ben Cheng4238ec22009-08-24 16:32:22 -070060 ivInfo->ssaReg,
Ben Cheng32115a92011-03-22 14:09:09 -070061 DECODE_REG(iv), DECODE_SUB(iv),
Ben Cheng4238ec22009-08-24 16:32:22 -070062 ivInfo->m,
63 ivInfo->basicSSAReg,
Ben Cheng32115a92011-03-22 14:09:09 -070064 DECODE_REG(biv), DECODE_SUB(biv),
Ben Cheng4238ec22009-08-24 16:32:22 -070065 ivInfo->c);
66 }
67 }
68}
69
Ben Chengfc075c22010-05-28 15:20:08 -070070static void dumpHoistedChecks(CompilationUnit *cUnit)
71{
72 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
73 unsigned int i;
74
75 for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
76 ArrayAccessInfo *arrayAccessInfo =
77 GET_ELEM_N(loopAnalysis->arrayAccessInfo,
78 ArrayAccessInfo*, i);
79 int arrayReg = DECODE_REG(
80 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
81 int idxReg = DECODE_REG(
82 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
83 LOGE("Array access %d", i);
84 LOGE(" arrayReg %d", arrayReg);
85 LOGE(" idxReg %d", idxReg);
86 LOGE(" endReg %d", loopAnalysis->endConditionReg);
87 LOGE(" maxC %d", arrayAccessInfo->maxC);
88 LOGE(" minC %d", arrayAccessInfo->minC);
89 LOGE(" opcode %d", loopAnalysis->loopBranchOpcode);
90 }
91}
92
93#endif
94
Ben Cheng32115a92011-03-22 14:09:09 -070095static BasicBlock *findPredecessorBlock(const CompilationUnit *cUnit,
96 const BasicBlock *bb)
97{
98 int numPred = dvmCountSetBits(bb->predecessors);
99 BitVectorIterator bvIterator;
100 dvmBitVectorIteratorInit(bb->predecessors, &bvIterator);
101
102 if (numPred == 1) {
103 int predIdx = dvmBitVectorIteratorNext(&bvIterator);
104 return (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList,
105 predIdx);
106 /* First loop block */
107 } else if ((numPred == 2) &&
108 dvmIsBitSet(bb->predecessors, cUnit->entryBlock->id)) {
109 while (true) {
110 int predIdx = dvmBitVectorIteratorNext(&bvIterator);
111 if (predIdx == cUnit->entryBlock->id) continue;
112 return (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList,
113 predIdx);
114 }
115 /* Doesn't support other shape of control flow yet */
116 } else {
117 return NULL;
118 }
119}
120
Ben Cheng535abdd2011-04-04 16:06:22 -0700121/* Used for normalized loop exit condition checks */
122static Opcode negateOpcode(Opcode opcode)
123{
124 switch (opcode) {
125 /* reg/reg cmp */
126 case OP_IF_EQ:
127 return OP_IF_NE;
128 case OP_IF_NE:
129 return OP_IF_EQ;
130 case OP_IF_LT:
131 return OP_IF_GE;
132 case OP_IF_GE:
133 return OP_IF_LT;
134 case OP_IF_GT:
135 return OP_IF_LE;
136 case OP_IF_LE:
137 return OP_IF_GT;
138 /* reg/zero cmp */
139 case OP_IF_EQZ:
140 return OP_IF_NEZ;
141 case OP_IF_NEZ:
142 return OP_IF_EQZ;
143 case OP_IF_LTZ:
144 return OP_IF_GEZ;
145 case OP_IF_GEZ:
146 return OP_IF_LTZ;
147 case OP_IF_GTZ:
148 return OP_IF_LEZ;
149 case OP_IF_LEZ:
150 return OP_IF_GTZ;
151 default:
152 LOGE("opcode %d cannot be negated", opcode);
153 dvmAbort();
154 break;
155 }
156 return -1;
157}
158
Ben Cheng4238ec22009-08-24 16:32:22 -0700159/*
160 * A loop is considered optimizable if:
Ben Cheng535abdd2011-04-04 16:06:22 -0700161 * 1) It has one basic induction variable.
162 * 2) The loop back branch compares the BIV with a constant.
163 * 3) We need to normalize the loop exit condition so that the loop is exited
164 * via the taken path.
165 * 4) If it is a count-up loop, the condition is GE/GT. Otherwise it is
166 * LE/LT/LEZ/LTZ for a count-down loop.
Ben Cheng4a419582010-08-04 13:23:09 -0700167 *
Ben Cheng535abdd2011-04-04 16:06:22 -0700168 * Return false for loops that fail the above tests.
Ben Cheng4238ec22009-08-24 16:32:22 -0700169 */
Ben Cheng32115a92011-03-22 14:09:09 -0700170static bool isSimpleCountedLoop(CompilationUnit *cUnit)
Ben Cheng4238ec22009-08-24 16:32:22 -0700171{
172 unsigned int i;
Ben Cheng535abdd2011-04-04 16:06:22 -0700173 BasicBlock *loopBackBlock = cUnit->entryBlock->fallThrough;
Ben Cheng4238ec22009-08-24 16:32:22 -0700174 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
175
176 if (loopAnalysis->numBasicIV != 1) return false;
177 for (i = 0; i < loopAnalysis->ivList->numUsed; i++) {
178 InductionVariableInfo *ivInfo;
179
180 ivInfo = GET_ELEM_N(loopAnalysis->ivList, InductionVariableInfo*, i);
181 /* Count up or down loop? */
182 if (ivInfo->ssaReg == ivInfo->basicSSAReg) {
Ben Cheng4a419582010-08-04 13:23:09 -0700183 /* Infinite loop */
184 if (ivInfo->inc == 0) {
185 return false;
186 }
Ben Cheng4238ec22009-08-24 16:32:22 -0700187 loopAnalysis->isCountUpLoop = ivInfo->inc > 0;
188 break;
189 }
190 }
191
Ben Cheng535abdd2011-04-04 16:06:22 -0700192 /* Find the block that ends with a branch to exit the loop */
193 while (true) {
194 loopBackBlock = findPredecessorBlock(cUnit, loopBackBlock);
195 /* Loop structure not recognized as counted blocks */
196 if (loopBackBlock == NULL) {
197 return false;
198 }
199 /* Unconditional goto - continue to trace up the predecessor chain */
200 if (loopBackBlock->taken == NULL) {
201 continue;
202 }
203 break;
204 }
205
206 MIR *branch = loopBackBlock->lastMIRInsn;
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800207 Opcode opcode = branch->dalvikInsn.opcode;
Ben Cheng4238ec22009-08-24 16:32:22 -0700208
Ben Cheng535abdd2011-04-04 16:06:22 -0700209 /* Last instruction is not a conditional branch - bail */
210 if (dexGetFlagsFromOpcode(opcode) != (kInstrCanContinue|kInstrCanBranch)) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700211 return false;
212 }
213
Ben Cheng535abdd2011-04-04 16:06:22 -0700214 int endSSAReg;
215 int endDalvikReg;
216
217 /* reg/reg comparison */
218 if (branch->ssaRep->numUses == 2) {
219 if (branch->ssaRep->uses[0] == loopAnalysis->ssaBIV) {
220 endSSAReg = branch->ssaRep->uses[1];
221 } else if (branch->ssaRep->uses[1] == loopAnalysis->ssaBIV) {
222 endSSAReg = branch->ssaRep->uses[0];
223 opcode = negateOpcode(opcode);
224 } else {
225 return false;
226 }
227 endDalvikReg = dvmConvertSSARegToDalvik(cUnit, endSSAReg);
228 /*
229 * If the comparison is not between the BIV and a loop invariant,
230 * return false. endDalvikReg is loop invariant if one of the
231 * following is true:
232 * - It is not defined in the loop (ie DECODE_SUB returns 0)
233 * - It is reloaded with a constant
234 */
235 if ((DECODE_SUB(endDalvikReg) != 0) &&
236 !dvmIsBitSet(cUnit->isConstantV, endSSAReg)) {
237 return false;
238 }
239 /* Compare against zero */
240 } else if (branch->ssaRep->numUses == 1) {
241 if (branch->ssaRep->uses[0] == loopAnalysis->ssaBIV) {
242 /* Keep the compiler happy */
243 endDalvikReg = -1;
244 } else {
245 return false;
246 }
247 } else {
Ben Cheng4238ec22009-08-24 16:32:22 -0700248 return false;
249 }
250
Ben Cheng535abdd2011-04-04 16:06:22 -0700251 /* Normalize the loop exit check as "if (iv op end) exit;" */
252 if (loopBackBlock->taken->blockType == kDalvikByteCode) {
253 opcode = negateOpcode(opcode);
254 }
255
Ben Cheng4238ec22009-08-24 16:32:22 -0700256 if (loopAnalysis->isCountUpLoop) {
257 /*
Ben Cheng535abdd2011-04-04 16:06:22 -0700258 * If the normalized condition op is not > or >=, this is not an
259 * optimization candidate.
Ben Cheng4238ec22009-08-24 16:32:22 -0700260 */
Ben Cheng535abdd2011-04-04 16:06:22 -0700261 switch (opcode) {
262 case OP_IF_GT:
263 case OP_IF_GE:
264 break;
265 default:
266 return false;
Ben Cheng4238ec22009-08-24 16:32:22 -0700267 }
Ben Cheng535abdd2011-04-04 16:06:22 -0700268 loopAnalysis->endConditionReg = DECODE_REG(endDalvikReg);
Ben Cheng4238ec22009-08-24 16:32:22 -0700269 } else {
270 /*
Ben Cheng535abdd2011-04-04 16:06:22 -0700271 * If the normalized condition op is not < or <=, this is not an
272 * optimization candidate.
Ben Cheng4238ec22009-08-24 16:32:22 -0700273 */
Ben Cheng535abdd2011-04-04 16:06:22 -0700274 switch (opcode) {
275 case OP_IF_LT:
276 case OP_IF_LE:
277 loopAnalysis->endConditionReg = DECODE_REG(endDalvikReg);
278 break;
279 case OP_IF_LTZ:
280 case OP_IF_LEZ:
281 break;
282 default:
Ben Cheng4238ec22009-08-24 16:32:22 -0700283 return false;
Ben Cheng4238ec22009-08-24 16:32:22 -0700284 }
285 }
Ben Cheng535abdd2011-04-04 16:06:22 -0700286 /*
287 * Remember the normalized opcode, which will be used to determine the end
288 * value used for the yanked range checks.
289 */
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800290 loopAnalysis->loopBranchOpcode = opcode;
Ben Cheng4238ec22009-08-24 16:32:22 -0700291 return true;
292}
293
294/*
295 * Record the upper and lower bound information for range checks for each
296 * induction variable. If array A is accessed by index "i+5", the upper and
297 * lower bound will be len(A)-5 and -5, respectively.
298 */
299static void updateRangeCheckInfo(CompilationUnit *cUnit, int arrayReg,
300 int idxReg)
301{
302 InductionVariableInfo *ivInfo;
303 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
304 unsigned int i, j;
305
306 for (i = 0; i < loopAnalysis->ivList->numUsed; i++) {
307 ivInfo = GET_ELEM_N(loopAnalysis->ivList, InductionVariableInfo*, i);
308 if (ivInfo->ssaReg == idxReg) {
309 ArrayAccessInfo *arrayAccessInfo = NULL;
310 for (j = 0; j < loopAnalysis->arrayAccessInfo->numUsed; j++) {
311 ArrayAccessInfo *existingArrayAccessInfo =
312 GET_ELEM_N(loopAnalysis->arrayAccessInfo,
313 ArrayAccessInfo*,
314 j);
315 if (existingArrayAccessInfo->arrayReg == arrayReg) {
316 if (ivInfo->c > existingArrayAccessInfo->maxC) {
317 existingArrayAccessInfo->maxC = ivInfo->c;
318 }
319 if (ivInfo->c < existingArrayAccessInfo->minC) {
320 existingArrayAccessInfo->minC = ivInfo->c;
321 }
322 arrayAccessInfo = existingArrayAccessInfo;
323 break;
324 }
325 }
326 if (arrayAccessInfo == NULL) {
327 arrayAccessInfo =
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800328 (ArrayAccessInfo *)dvmCompilerNew(sizeof(ArrayAccessInfo),
329 false);
Ben Cheng4238ec22009-08-24 16:32:22 -0700330 arrayAccessInfo->ivReg = ivInfo->basicSSAReg;
331 arrayAccessInfo->arrayReg = arrayReg;
332 arrayAccessInfo->maxC = (ivInfo->c > 0) ? ivInfo->c : 0;
333 arrayAccessInfo->minC = (ivInfo->c < 0) ? ivInfo->c : 0;
334 dvmInsertGrowableList(loopAnalysis->arrayAccessInfo,
Ben Cheng00603072010-10-28 11:13:58 -0700335 (intptr_t) arrayAccessInfo);
Ben Cheng4238ec22009-08-24 16:32:22 -0700336 }
337 break;
338 }
339 }
340}
341
342/* Returns true if the loop body cannot throw any exceptions */
343static bool doLoopBodyCodeMotion(CompilationUnit *cUnit)
344{
Ben Cheng32115a92011-03-22 14:09:09 -0700345 BasicBlock *loopBody = cUnit->entryBlock->fallThrough;
Ben Cheng4238ec22009-08-24 16:32:22 -0700346 MIR *mir;
347 bool loopBodyCanThrow = false;
Ben Cheng4238ec22009-08-24 16:32:22 -0700348
349 for (mir = loopBody->firstMIRInsn; mir; mir = mir->next) {
350 DecodedInstruction *dInsn = &mir->dalvikInsn;
351 int dfAttributes =
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800352 dvmCompilerDataFlowAttributes[mir->dalvikInsn.opcode];
Ben Cheng4238ec22009-08-24 16:32:22 -0700353
354 /* Skip extended MIR instructions */
Dan Bornsteinccaab182010-12-03 15:32:40 -0800355 if (dInsn->opcode >= kNumPackedOpcodes) continue;
Ben Cheng4238ec22009-08-24 16:32:22 -0700356
Dan Bornsteine4852762010-12-02 12:45:00 -0800357 int instrFlags = dexGetFlagsFromOpcode(dInsn->opcode);
Ben Cheng4238ec22009-08-24 16:32:22 -0700358
359 /* Instruction is clean */
360 if ((instrFlags & kInstrCanThrow) == 0) continue;
361
362 /*
363 * Currently we can only optimize away null and range checks. Punt on
364 * instructions that can throw due to other exceptions.
365 */
366 if (!(dfAttributes & DF_HAS_NR_CHECKS)) {
367 loopBodyCanThrow = true;
368 continue;
369 }
370
371 /*
372 * This comparison is redundant now, but we will have more than one
373 * group of flags to check soon.
374 */
375 if (dfAttributes & DF_HAS_NR_CHECKS) {
376 /*
377 * Check if the null check is applied on a loop invariant register?
378 * If the register's SSA id is less than the number of Dalvik
379 * registers, then it is loop invariant.
380 */
381 int refIdx;
382 switch (dfAttributes & DF_HAS_NR_CHECKS) {
383 case DF_NULL_N_RANGE_CHECK_0:
384 refIdx = 0;
385 break;
386 case DF_NULL_N_RANGE_CHECK_1:
387 refIdx = 1;
388 break;
389 case DF_NULL_N_RANGE_CHECK_2:
390 refIdx = 2;
391 break;
392 default:
393 refIdx = 0;
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800394 LOGE("Jit: bad case in doLoopBodyCodeMotion");
395 dvmCompilerAbort(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -0700396 }
397
398 int useIdx = refIdx + 1;
399 int subNRegArray =
400 dvmConvertSSARegToDalvik(cUnit, mir->ssaRep->uses[refIdx]);
Ben Cheng4238ec22009-08-24 16:32:22 -0700401 int arraySub = DECODE_SUB(subNRegArray);
402
403 /*
404 * If the register is never updated in the loop (ie subscript == 0),
405 * it is an optimization candidate.
406 */
407 if (arraySub != 0) {
408 loopBodyCanThrow = true;
409 continue;
410 }
411
412 /*
413 * Then check if the range check can be hoisted out of the loop if
414 * it is basic or dependent induction variable.
415 */
416 if (dvmIsBitSet(cUnit->loopAnalysis->isIndVarV,
417 mir->ssaRep->uses[useIdx])) {
418 mir->OptimizationFlags |=
Ben Cheng32115a92011-03-22 14:09:09 -0700419 MIR_IGNORE_RANGE_CHECK | MIR_IGNORE_NULL_CHECK;
Ben Cheng4238ec22009-08-24 16:32:22 -0700420 updateRangeCheckInfo(cUnit, mir->ssaRep->uses[refIdx],
421 mir->ssaRep->uses[useIdx]);
422 }
423 }
424 }
425
426 return !loopBodyCanThrow;
427}
428
Ben Cheng4238ec22009-08-24 16:32:22 -0700429static void genHoistedChecks(CompilationUnit *cUnit)
430{
431 unsigned int i;
Ben Cheng32115a92011-03-22 14:09:09 -0700432 BasicBlock *entry = cUnit->entryBlock;
Ben Cheng4238ec22009-08-24 16:32:22 -0700433 LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
Ben Cheng4238ec22009-08-24 16:32:22 -0700434 int globalMaxC = 0;
435 int globalMinC = 0;
436 /* Should be loop invariant */
437 int idxReg = 0;
438
439 for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
440 ArrayAccessInfo *arrayAccessInfo =
441 GET_ELEM_N(loopAnalysis->arrayAccessInfo,
442 ArrayAccessInfo*, i);
443 int arrayReg = DECODE_REG(
444 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
445 idxReg = DECODE_REG(
446 dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
447
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800448 MIR *rangeCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800449 rangeCheckMIR->dalvikInsn.opcode = (loopAnalysis->isCountUpLoop) ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700450 kMirOpNullNRangeUpCheck : kMirOpNullNRangeDownCheck;
Ben Cheng4238ec22009-08-24 16:32:22 -0700451 rangeCheckMIR->dalvikInsn.vA = arrayReg;
452 rangeCheckMIR->dalvikInsn.vB = idxReg;
453 rangeCheckMIR->dalvikInsn.vC = loopAnalysis->endConditionReg;
454 rangeCheckMIR->dalvikInsn.arg[0] = arrayAccessInfo->maxC;
455 rangeCheckMIR->dalvikInsn.arg[1] = arrayAccessInfo->minC;
456 rangeCheckMIR->dalvikInsn.arg[2] = loopAnalysis->loopBranchOpcode;
457 dvmCompilerAppendMIR(entry, rangeCheckMIR);
458 if (arrayAccessInfo->maxC > globalMaxC) {
459 globalMaxC = arrayAccessInfo->maxC;
460 }
461 if (arrayAccessInfo->minC < globalMinC) {
462 globalMinC = arrayAccessInfo->minC;
463 }
464 }
465
466 if (loopAnalysis->arrayAccessInfo->numUsed != 0) {
467 if (loopAnalysis->isCountUpLoop) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800468 MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800469 boundCheckMIR->dalvikInsn.opcode = kMirOpLowerBound;
Ben Cheng4238ec22009-08-24 16:32:22 -0700470 boundCheckMIR->dalvikInsn.vA = idxReg;
471 boundCheckMIR->dalvikInsn.vB = globalMinC;
472 dvmCompilerAppendMIR(entry, boundCheckMIR);
473 } else {
474 if (loopAnalysis->loopBranchOpcode == OP_IF_LT ||
475 loopAnalysis->loopBranchOpcode == OP_IF_LE) {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800476 MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800477 boundCheckMIR->dalvikInsn.opcode = kMirOpLowerBound;
Ben Cheng4238ec22009-08-24 16:32:22 -0700478 boundCheckMIR->dalvikInsn.vA = loopAnalysis->endConditionReg;
479 boundCheckMIR->dalvikInsn.vB = globalMinC;
480 /*
Ben Cheng36bd1342010-10-25 20:54:31 -0700481 * If the end condition is ">" in the source, the check in the
482 * Dalvik bytecode is OP_IF_LE. In this case add 1 back to the
483 * constant field to reflect the fact that the smallest index
484 * value is "endValue + constant + 1".
Ben Cheng4238ec22009-08-24 16:32:22 -0700485 */
Ben Cheng36bd1342010-10-25 20:54:31 -0700486 if (loopAnalysis->loopBranchOpcode == OP_IF_LE) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700487 boundCheckMIR->dalvikInsn.vB++;
488 }
489 dvmCompilerAppendMIR(entry, boundCheckMIR);
490 } else if (loopAnalysis->loopBranchOpcode == OP_IF_LTZ) {
491 /* Array index will fall below 0 */
492 if (globalMinC < 0) {
Ben Cheng32115a92011-03-22 14:09:09 -0700493 MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR),
494 true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800495 boundCheckMIR->dalvikInsn.opcode = kMirOpPunt;
Ben Cheng4238ec22009-08-24 16:32:22 -0700496 dvmCompilerAppendMIR(entry, boundCheckMIR);
497 }
498 } else if (loopAnalysis->loopBranchOpcode == OP_IF_LEZ) {
499 /* Array index will fall below 0 */
500 if (globalMinC < -1) {
Ben Cheng32115a92011-03-22 14:09:09 -0700501 MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR),
502 true);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800503 boundCheckMIR->dalvikInsn.opcode = kMirOpPunt;
Ben Cheng4238ec22009-08-24 16:32:22 -0700504 dvmCompilerAppendMIR(entry, boundCheckMIR);
505 }
506 } else {
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800507 LOGE("Jit: bad case in genHoistedChecks");
508 dvmCompilerAbort(cUnit);
Ben Cheng4238ec22009-08-24 16:32:22 -0700509 }
510 }
Ben Cheng4238ec22009-08-24 16:32:22 -0700511 }
512}
513
Ben Cheng46cd4fb2011-03-16 17:19:06 -0700514void resetBlockEdges(BasicBlock *bb)
515{
516 bb->taken = NULL;
517 bb->fallThrough = NULL;
518 bb->successorBlockList.blockListType = kNotUsed;
519}
520
521static bool clearPredecessorVector(struct CompilationUnit *cUnit,
522 struct BasicBlock *bb)
523{
524 dvmClearAllBits(bb->predecessors);
525 return false;
526}
527
528bool dvmCompilerFilterLoopBlocks(CompilationUnit *cUnit)
529{
530 BasicBlock *firstBB = cUnit->entryBlock->fallThrough;
531
532 int numPred = dvmCountSetBits(firstBB->predecessors);
533 /*
Ben Cheng32115a92011-03-22 14:09:09 -0700534 * A loop body should have at least two incoming edges.
Ben Cheng46cd4fb2011-03-16 17:19:06 -0700535 */
Ben Cheng32115a92011-03-22 14:09:09 -0700536 if (numPred < 2) return false;
Ben Cheng46cd4fb2011-03-16 17:19:06 -0700537
Ben Cheng46cd4fb2011-03-16 17:19:06 -0700538 GrowableList *blockList = &cUnit->blockList;
Ben Cheng46cd4fb2011-03-16 17:19:06 -0700539
Ben Cheng32115a92011-03-22 14:09:09 -0700540 /* Record blocks included in the loop */
Ben Cheng46cd4fb2011-03-16 17:19:06 -0700541 dvmClearAllBits(cUnit->tempBlockV);
542
Ben Cheng32115a92011-03-22 14:09:09 -0700543 dvmCompilerSetBit(cUnit->tempBlockV, cUnit->entryBlock->id);
544 dvmCompilerSetBit(cUnit->tempBlockV, firstBB->id);
Ben Cheng46cd4fb2011-03-16 17:19:06 -0700545
Ben Cheng32115a92011-03-22 14:09:09 -0700546 BasicBlock *bodyBB = firstBB;
547
548 /*
549 * First try to include the fall-through block in the loop, then the taken
550 * block. Stop loop formation on the first backward branch that enters the
551 * first block (ie only include the inner-most loop).
552 */
553 while (true) {
554 /* Loop formed */
555 if (bodyBB->taken == firstBB || bodyBB->fallThrough == firstBB) break;
556
557 /* Inner loops formed first - quit */
558 if (bodyBB->fallThrough &&
559 dvmIsBitSet(cUnit->tempBlockV, bodyBB->fallThrough->id)) {
Ben Cheng46cd4fb2011-03-16 17:19:06 -0700560 return false;
561 }
Ben Cheng32115a92011-03-22 14:09:09 -0700562 if (bodyBB->taken &&
563 dvmIsBitSet(cUnit->tempBlockV, bodyBB->taken->id)) {
564 return false;
565 }
566
567 if (bodyBB->fallThrough) {
568 if (bodyBB->fallThrough->iDom == bodyBB) {
569 bodyBB = bodyBB->fallThrough;
570 dvmCompilerSetBit(cUnit->tempBlockV, bodyBB->id);
571 /*
572 * Loop formation to be detected at the beginning of next
573 * iteration.
574 */
575 continue;
576 }
577 }
578 if (bodyBB->taken) {
579 if (bodyBB->taken->iDom == bodyBB) {
580 bodyBB = bodyBB->taken;
581 dvmCompilerSetBit(cUnit->tempBlockV, bodyBB->id);
582 /*
583 * Loop formation to be detected at the beginning of next
584 * iteration.
585 */
586 continue;
587 }
588 }
589 /*
590 * Current block is not the immediate dominator of either fallthrough
591 * nor taken block - bail out of loop formation.
592 */
593 return false;
Ben Cheng46cd4fb2011-03-16 17:19:06 -0700594 }
595
Ben Cheng46cd4fb2011-03-16 17:19:06 -0700596
597 /* Now mark blocks not included in the loop as hidden */
598 GrowableListIterator iterator;
Ben Cheng32115a92011-03-22 14:09:09 -0700599 dvmGrowableListIteratorInit(blockList, &iterator);
Ben Cheng46cd4fb2011-03-16 17:19:06 -0700600 while (true) {
601 BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
602 if (bb == NULL) break;
603 if (!dvmIsBitSet(cUnit->tempBlockV, bb->id)) {
604 bb->hidden = true;
605 /* Clear the insn list */
606 bb->firstMIRInsn = bb->lastMIRInsn = NULL;
607 resetBlockEdges(bb);
608 }
609 }
610
611 dvmCompilerDataFlowAnalysisDispatcher(cUnit, clearPredecessorVector,
612 kAllNodes, false /* isIterative */);
613
Ben Cheng32115a92011-03-22 14:09:09 -0700614 dvmGrowableListIteratorInit(blockList, &iterator);
Ben Cheng46cd4fb2011-03-16 17:19:06 -0700615 while (true) {
616 BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
617 if (bb == NULL) break;
618 if (dvmIsBitSet(cUnit->tempBlockV, bb->id)) {
619 if (bb->taken) {
620 /*
621 * exit block means we run into control-flow that we don't want
622 * to handle.
623 */
624 if (bb->taken == cUnit->exitBlock) {
625 return false;
626 }
627 if (bb->taken->hidden) {
628 bb->taken->blockType = kChainingCellNormal;
629 bb->taken->hidden = false;
630 }
631 dvmCompilerSetBit(bb->taken->predecessors, bb->id);
632 }
633 if (bb->fallThrough) {
634 /*
635 * exit block means we run into control-flow that we don't want
636 * to handle.
637 */
638 if (bb->fallThrough == cUnit->exitBlock) {
639 return false;
640 }
641 if (bb->fallThrough->hidden) {
642 bb->fallThrough->blockType = kChainingCellNormal;
643 bb->fallThrough->hidden = false;
644 }
645 dvmCompilerSetBit(bb->fallThrough->predecessors, bb->id);
646 }
647 /* Loop blocks shouldn't contain any successor blocks (yet) */
648 assert(bb->successorBlockList.blockListType == kNotUsed);
649 }
650 }
Ben Cheng46cd4fb2011-03-16 17:19:06 -0700651 return true;
652}
Ben Cheng32115a92011-03-22 14:09:09 -0700653
654/*
655 * Main entry point to do loop optimization.
656 * Return false if sanity checks for loop formation/optimization failed.
657 */
658bool dvmCompilerLoopOpt(CompilationUnit *cUnit)
659{
660 LoopAnalysis *loopAnalysis =
661 (LoopAnalysis *)dvmCompilerNew(sizeof(LoopAnalysis), true);
662 cUnit->loopAnalysis = loopAnalysis;
663
664 /* Constant propagation */
665 cUnit->isConstantV = dvmAllocBitVector(cUnit->numSSARegs, false);
666 cUnit->constantValues =
667 (int *)dvmCompilerNew(sizeof(int) * cUnit->numSSARegs,
668 true);
669 dvmCompilerDataFlowAnalysisDispatcher(cUnit,
670 dvmCompilerDoConstantPropagation,
671 kAllNodes,
672 false /* isIterative */);
673 DEBUG_LOOP(dumpConstants(cUnit);)
674
675 /* Find induction variables - basic and dependent */
676 loopAnalysis->ivList =
677 (GrowableList *)dvmCompilerNew(sizeof(GrowableList), true);
678 dvmInitGrowableList(loopAnalysis->ivList, 4);
679 loopAnalysis->isIndVarV = dvmAllocBitVector(cUnit->numSSARegs, false);
680 dvmCompilerDataFlowAnalysisDispatcher(cUnit,
681 dvmCompilerFindInductionVariables,
682 kAllNodes,
683 false /* isIterative */);
684 DEBUG_LOOP(dumpIVList(cUnit);)
685
686 /* Only optimize array accesses for simple counted loop for now */
687 if (!isSimpleCountedLoop(cUnit))
688 return false;
689
690 loopAnalysis->arrayAccessInfo =
691 (GrowableList *)dvmCompilerNew(sizeof(GrowableList), true);
692 dvmInitGrowableList(loopAnalysis->arrayAccessInfo, 4);
693 loopAnalysis->bodyIsClean = doLoopBodyCodeMotion(cUnit);
694 DEBUG_LOOP(dumpHoistedChecks(cUnit);)
695
696 /*
697 * Convert the array access information into extended MIR code in the loop
698 * header.
699 */
700 genHoistedChecks(cUnit);
701 return true;
702}
703
704/*
705 * Select the target block of the backward branch.
706 */
707void dvmCompilerInsertBackwardChaining(CompilationUnit *cUnit)
708{
709 /*
710 * If we are not in self-verification or profiling mode, the backward
711 * branch can go to the entryBlock->fallThrough directly. Suspend polling
712 * code will be generated along the backward branch to honor the suspend
713 * requests.
714 */
715#if !defined(WITH_SELF_VERIFICATION)
716 if (gDvmJit.profileMode != kTraceProfilingContinuous &&
717 gDvmJit.profileMode != kTraceProfilingPeriodicOn) {
718 return;
719 }
720#endif
721 /*
722 * In self-verification or profiling mode, the backward branch is altered
723 * to go to the backward chaining cell. Without using the backward chaining
724 * cell we won't be able to do check-pointing on the target PC, or count the
725 * number of iterations accurately.
726 */
727 BasicBlock *firstBB = cUnit->entryBlock->fallThrough;
728 BasicBlock *backBranchBB = findPredecessorBlock(cUnit, firstBB);
729 if (backBranchBB->taken == firstBB) {
730 backBranchBB->taken = cUnit->backChainBlock;
731 } else {
732 assert(backBranchBB->fallThrough == firstBB);
733 backBranchBB->fallThrough = cUnit->backChainBlock;
734 }
735 cUnit->backChainBlock->startOffset = firstBB->startOffset;
736}