summaryrefslogtreecommitdiff
path: root/vm/compiler/Loop.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vm/compiler/Loop.cpp')
-rw-r--r--vm/compiler/Loop.cpp752
1 files changed, 752 insertions, 0 deletions
diff --git a/vm/compiler/Loop.cpp b/vm/compiler/Loop.cpp
new file mode 100644
index 0000000..90c97d7
--- /dev/null
+++ b/vm/compiler/Loop.cpp
@@ -0,0 +1,752 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Dalvik.h"
+#include "CompilerInternals.h"
+#include "Dataflow.h"
+#include "Loop.h"
+
+#define DEBUG_LOOP(X)
+
+#if 0
+/* Debugging routines */
+static void dumpConstants(CompilationUnit *cUnit)
+{
+ int i;
+ LOGE("LOOP starting offset: %x", cUnit->entryBlock->startOffset);
+ for (i = 0; i < cUnit->numSSARegs; i++) {
+ if (dvmIsBitSet(cUnit->isConstantV, i)) {
+ int subNReg = dvmConvertSSARegToDalvik(cUnit, i);
+ LOGE("CONST: s%d(v%d_%d) has %d", i,
+ DECODE_REG(subNReg), DECODE_SUB(subNReg),
+ cUnit->constantValues[i]);
+ }
+ }
+}
+
+static void dumpIVList(CompilationUnit *cUnit)
+{
+ unsigned int i;
+ GrowableList *ivList = cUnit->loopAnalysis->ivList;
+
+ for (i = 0; i < ivList->numUsed; i++) {
+ InductionVariableInfo *ivInfo =
+ (InductionVariableInfo *) ivList->elemList[i];
+ int iv = dvmConvertSSARegToDalvik(cUnit, ivInfo->ssaReg);
+ /* Basic IV */
+ if (ivInfo->ssaReg == ivInfo->basicSSAReg) {
+ LOGE("BIV %d: s%d(v%d_%d) + %d", i,
+ ivInfo->ssaReg,
+ DECODE_REG(iv), DECODE_SUB(iv),
+ ivInfo->inc);
+ /* Dependent IV */
+ } else {
+ int biv = dvmConvertSSARegToDalvik(cUnit, ivInfo->basicSSAReg);
+
+ LOGE("DIV %d: s%d(v%d_%d) = %d * s%d(v%d_%d) + %d", i,
+ ivInfo->ssaReg,
+ DECODE_REG(iv), DECODE_SUB(iv),
+ ivInfo->m,
+ ivInfo->basicSSAReg,
+ DECODE_REG(biv), DECODE_SUB(biv),
+ ivInfo->c);
+ }
+ }
+}
+
+static void dumpHoistedChecks(CompilationUnit *cUnit)
+{
+ LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
+ unsigned int i;
+
+ for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
+ ArrayAccessInfo *arrayAccessInfo =
+ GET_ELEM_N(loopAnalysis->arrayAccessInfo,
+ ArrayAccessInfo*, i);
+ int arrayReg = DECODE_REG(
+ dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
+ int idxReg = DECODE_REG(
+ dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
+ LOGE("Array access %d", i);
+ LOGE(" arrayReg %d", arrayReg);
+ LOGE(" idxReg %d", idxReg);
+ LOGE(" endReg %d", loopAnalysis->endConditionReg);
+ LOGE(" maxC %d", arrayAccessInfo->maxC);
+ LOGE(" minC %d", arrayAccessInfo->minC);
+ LOGE(" opcode %d", loopAnalysis->loopBranchOpcode);
+ }
+}
+
+#endif
+
+static BasicBlock *findPredecessorBlock(const CompilationUnit *cUnit,
+ const BasicBlock *bb)
+{
+ int numPred = dvmCountSetBits(bb->predecessors);
+ BitVectorIterator bvIterator;
+ dvmBitVectorIteratorInit(bb->predecessors, &bvIterator);
+
+ if (numPred == 1) {
+ int predIdx = dvmBitVectorIteratorNext(&bvIterator);
+ return (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList,
+ predIdx);
+ /* First loop block */
+ } else if ((numPred == 2) &&
+ dvmIsBitSet(bb->predecessors, cUnit->entryBlock->id)) {
+ while (true) {
+ int predIdx = dvmBitVectorIteratorNext(&bvIterator);
+ if (predIdx == cUnit->entryBlock->id) continue;
+ return (BasicBlock *) dvmGrowableListGetElement(&cUnit->blockList,
+ predIdx);
+ }
+ /* Doesn't support other shape of control flow yet */
+ } else {
+ return NULL;
+ }
+}
+
+/* Used for normalized loop exit condition checks */
+static Opcode negateOpcode(Opcode opcode)
+{
+ switch (opcode) {
+ /* reg/reg cmp */
+ case OP_IF_EQ:
+ return OP_IF_NE;
+ case OP_IF_NE:
+ return OP_IF_EQ;
+ case OP_IF_LT:
+ return OP_IF_GE;
+ case OP_IF_GE:
+ return OP_IF_LT;
+ case OP_IF_GT:
+ return OP_IF_LE;
+ case OP_IF_LE:
+ return OP_IF_GT;
+ /* reg/zero cmp */
+ case OP_IF_EQZ:
+ return OP_IF_NEZ;
+ case OP_IF_NEZ:
+ return OP_IF_EQZ;
+ case OP_IF_LTZ:
+ return OP_IF_GEZ;
+ case OP_IF_GEZ:
+ return OP_IF_LTZ;
+ case OP_IF_GTZ:
+ return OP_IF_LEZ;
+ case OP_IF_LEZ:
+ return OP_IF_GTZ;
+ default:
+ LOGE("opcode %d cannot be negated", opcode);
+ dvmAbort();
+ break;
+ }
+ return (Opcode)-1; // unreached
+}
+
+/*
+ * A loop is considered optimizable if:
+ * 1) It has one basic induction variable.
+ * 2) The loop back branch compares the BIV with a constant.
+ * 3) We need to normalize the loop exit condition so that the loop is exited
+ * via the taken path.
+ * 4) If it is a count-up loop, the condition is GE/GT. Otherwise it is
+ * LE/LT/LEZ/LTZ for a count-down loop.
+ *
+ * Return false for loops that fail the above tests.
+ */
+static bool isSimpleCountedLoop(CompilationUnit *cUnit)
+{
+ unsigned int i;
+ BasicBlock *loopBackBlock = cUnit->entryBlock->fallThrough;
+ LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
+
+ if (loopAnalysis->numBasicIV != 1) return false;
+ for (i = 0; i < loopAnalysis->ivList->numUsed; i++) {
+ InductionVariableInfo *ivInfo;
+
+ ivInfo = GET_ELEM_N(loopAnalysis->ivList, InductionVariableInfo*, i);
+ /* Count up or down loop? */
+ if (ivInfo->ssaReg == ivInfo->basicSSAReg) {
+ /* Infinite loop */
+ if (ivInfo->inc == 0) {
+ return false;
+ }
+ loopAnalysis->isCountUpLoop = ivInfo->inc > 0;
+ break;
+ }
+ }
+
+ /* Find the block that ends with a branch to exit the loop */
+ while (true) {
+ loopBackBlock = findPredecessorBlock(cUnit, loopBackBlock);
+ /* Loop structure not recognized as counted blocks */
+ if (loopBackBlock == NULL) {
+ return false;
+ }
+ /* Unconditional goto - continue to trace up the predecessor chain */
+ if (loopBackBlock->taken == NULL) {
+ continue;
+ }
+ break;
+ }
+
+ MIR *branch = loopBackBlock->lastMIRInsn;
+ Opcode opcode = branch->dalvikInsn.opcode;
+
+ /* Last instruction is not a conditional branch - bail */
+ if (dexGetFlagsFromOpcode(opcode) != (kInstrCanContinue|kInstrCanBranch)) {
+ return false;
+ }
+
+ int endSSAReg;
+ int endDalvikReg;
+
+ /* reg/reg comparison */
+ if (branch->ssaRep->numUses == 2) {
+ if (branch->ssaRep->uses[0] == loopAnalysis->ssaBIV) {
+ endSSAReg = branch->ssaRep->uses[1];
+ } else if (branch->ssaRep->uses[1] == loopAnalysis->ssaBIV) {
+ endSSAReg = branch->ssaRep->uses[0];
+ opcode = negateOpcode(opcode);
+ } else {
+ return false;
+ }
+ endDalvikReg = dvmConvertSSARegToDalvik(cUnit, endSSAReg);
+ /*
+ * If the comparison is not between the BIV and a loop invariant,
+ * return false. endDalvikReg is loop invariant if one of the
+ * following is true:
+ * - It is not defined in the loop (ie DECODE_SUB returns 0)
+ * - It is reloaded with a constant
+ */
+ if ((DECODE_SUB(endDalvikReg) != 0) &&
+ !dvmIsBitSet(cUnit->isConstantV, endSSAReg)) {
+ return false;
+ }
+ /* Compare against zero */
+ } else if (branch->ssaRep->numUses == 1) {
+ if (branch->ssaRep->uses[0] == loopAnalysis->ssaBIV) {
+ /* Keep the compiler happy */
+ endDalvikReg = -1;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+
+ /* Normalize the loop exit check as "if (iv op end) exit;" */
+ if (loopBackBlock->taken->blockType == kDalvikByteCode) {
+ opcode = negateOpcode(opcode);
+ }
+
+ if (loopAnalysis->isCountUpLoop) {
+ /*
+ * If the normalized condition op is not > or >=, this is not an
+ * optimization candidate.
+ */
+ switch (opcode) {
+ case OP_IF_GT:
+ case OP_IF_GE:
+ break;
+ default:
+ return false;
+ }
+ loopAnalysis->endConditionReg = DECODE_REG(endDalvikReg);
+ } else {
+ /*
+ * If the normalized condition op is not < or <=, this is not an
+ * optimization candidate.
+ */
+ switch (opcode) {
+ case OP_IF_LT:
+ case OP_IF_LE:
+ loopAnalysis->endConditionReg = DECODE_REG(endDalvikReg);
+ break;
+ case OP_IF_LTZ:
+ case OP_IF_LEZ:
+ break;
+ default:
+ return false;
+ }
+ }
+ /*
+ * Remember the normalized opcode, which will be used to determine the end
+ * value used for the yanked range checks.
+ */
+ loopAnalysis->loopBranchOpcode = opcode;
+ return true;
+}
+
+/*
+ * Record the upper and lower bound information for range checks for each
+ * induction variable. If array A is accessed by index "i+5", the upper and
+ * lower bound will be len(A)-5 and -5, respectively.
+ */
+static void updateRangeCheckInfo(CompilationUnit *cUnit, int arrayReg,
+ int idxReg)
+{
+ InductionVariableInfo *ivInfo;
+ LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
+ unsigned int i, j;
+
+ for (i = 0; i < loopAnalysis->ivList->numUsed; i++) {
+ ivInfo = GET_ELEM_N(loopAnalysis->ivList, InductionVariableInfo*, i);
+ if (ivInfo->ssaReg == idxReg) {
+ ArrayAccessInfo *arrayAccessInfo = NULL;
+ for (j = 0; j < loopAnalysis->arrayAccessInfo->numUsed; j++) {
+ ArrayAccessInfo *existingArrayAccessInfo =
+ GET_ELEM_N(loopAnalysis->arrayAccessInfo,
+ ArrayAccessInfo*,
+ j);
+ if (existingArrayAccessInfo->arrayReg == arrayReg) {
+ if (ivInfo->c > existingArrayAccessInfo->maxC) {
+ existingArrayAccessInfo->maxC = ivInfo->c;
+ }
+ if (ivInfo->c < existingArrayAccessInfo->minC) {
+ existingArrayAccessInfo->minC = ivInfo->c;
+ }
+ arrayAccessInfo = existingArrayAccessInfo;
+ break;
+ }
+ }
+ if (arrayAccessInfo == NULL) {
+ arrayAccessInfo =
+ (ArrayAccessInfo *)dvmCompilerNew(sizeof(ArrayAccessInfo),
+ false);
+ arrayAccessInfo->ivReg = ivInfo->basicSSAReg;
+ arrayAccessInfo->arrayReg = arrayReg;
+ arrayAccessInfo->maxC = (ivInfo->c > 0) ? ivInfo->c : 0;
+ arrayAccessInfo->minC = (ivInfo->c < 0) ? ivInfo->c : 0;
+ dvmInsertGrowableList(loopAnalysis->arrayAccessInfo,
+ (intptr_t) arrayAccessInfo);
+ }
+ break;
+ }
+ }
+}
+
+/* Returns true if the loop body cannot throw any exceptions */
+static bool doLoopBodyCodeMotion(CompilationUnit *cUnit)
+{
+ BasicBlock *loopBody = cUnit->entryBlock->fallThrough;
+ MIR *mir;
+ bool loopBodyCanThrow = false;
+
+ for (mir = loopBody->firstMIRInsn; mir; mir = mir->next) {
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ int dfAttributes =
+ dvmCompilerDataFlowAttributes[mir->dalvikInsn.opcode];
+
+ /* Skip extended MIR instructions */
+ if (dInsn->opcode >= kNumPackedOpcodes) continue;
+
+ int instrFlags = dexGetFlagsFromOpcode(dInsn->opcode);
+
+ /* Instruction is clean */
+ if ((instrFlags & kInstrCanThrow) == 0) continue;
+
+ /*
+ * Currently we can only optimize away null and range checks. Punt on
+ * instructions that can throw due to other exceptions.
+ */
+ if (!(dfAttributes & DF_HAS_NR_CHECKS)) {
+ loopBodyCanThrow = true;
+ continue;
+ }
+
+ /*
+ * This comparison is redundant now, but we will have more than one
+ * group of flags to check soon.
+ */
+ if (dfAttributes & DF_HAS_NR_CHECKS) {
+ /*
+ * Check if the null check is applied on a loop invariant register?
+ * If the register's SSA id is less than the number of Dalvik
+ * registers, then it is loop invariant.
+ */
+ int refIdx;
+ switch (dfAttributes & DF_HAS_NR_CHECKS) {
+ case DF_NULL_N_RANGE_CHECK_0:
+ refIdx = 0;
+ break;
+ case DF_NULL_N_RANGE_CHECK_1:
+ refIdx = 1;
+ break;
+ case DF_NULL_N_RANGE_CHECK_2:
+ refIdx = 2;
+ break;
+ default:
+ refIdx = 0;
+ LOGE("Jit: bad case in doLoopBodyCodeMotion");
+ dvmCompilerAbort(cUnit);
+ }
+
+ int useIdx = refIdx + 1;
+ int subNRegArray =
+ dvmConvertSSARegToDalvik(cUnit, mir->ssaRep->uses[refIdx]);
+ int arraySub = DECODE_SUB(subNRegArray);
+
+ /*
+ * If the register is never updated in the loop (ie subscript == 0),
+ * it is an optimization candidate.
+ */
+ if (arraySub != 0) {
+ loopBodyCanThrow = true;
+ continue;
+ }
+
+ /*
+ * Then check if the range check can be hoisted out of the loop if
+ * it is basic or dependent induction variable.
+ */
+ if (dvmIsBitSet(cUnit->loopAnalysis->isIndVarV,
+ mir->ssaRep->uses[useIdx])) {
+ mir->OptimizationFlags |=
+ MIR_IGNORE_RANGE_CHECK | MIR_IGNORE_NULL_CHECK;
+ updateRangeCheckInfo(cUnit, mir->ssaRep->uses[refIdx],
+ mir->ssaRep->uses[useIdx]);
+ }
+ }
+ }
+
+ return !loopBodyCanThrow;
+}
+
+static void genHoistedChecks(CompilationUnit *cUnit)
+{
+ unsigned int i;
+ BasicBlock *entry = cUnit->entryBlock;
+ LoopAnalysis *loopAnalysis = cUnit->loopAnalysis;
+ int globalMaxC = 0;
+ int globalMinC = 0;
+ /* Should be loop invariant */
+ int idxReg = 0;
+
+ for (i = 0; i < loopAnalysis->arrayAccessInfo->numUsed; i++) {
+ ArrayAccessInfo *arrayAccessInfo =
+ GET_ELEM_N(loopAnalysis->arrayAccessInfo,
+ ArrayAccessInfo*, i);
+ int arrayReg = DECODE_REG(
+ dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->arrayReg));
+ idxReg = DECODE_REG(
+ dvmConvertSSARegToDalvik(cUnit, arrayAccessInfo->ivReg));
+
+ MIR *rangeCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
+ rangeCheckMIR->dalvikInsn.opcode = (loopAnalysis->isCountUpLoop) ?
+ (Opcode)kMirOpNullNRangeUpCheck : (Opcode)kMirOpNullNRangeDownCheck;
+ rangeCheckMIR->dalvikInsn.vA = arrayReg;
+ rangeCheckMIR->dalvikInsn.vB = idxReg;
+ rangeCheckMIR->dalvikInsn.vC = loopAnalysis->endConditionReg;
+ rangeCheckMIR->dalvikInsn.arg[0] = arrayAccessInfo->maxC;
+ rangeCheckMIR->dalvikInsn.arg[1] = arrayAccessInfo->minC;
+ rangeCheckMIR->dalvikInsn.arg[2] = loopAnalysis->loopBranchOpcode;
+ dvmCompilerAppendMIR(entry, rangeCheckMIR);
+ if (arrayAccessInfo->maxC > globalMaxC) {
+ globalMaxC = arrayAccessInfo->maxC;
+ }
+ if (arrayAccessInfo->minC < globalMinC) {
+ globalMinC = arrayAccessInfo->minC;
+ }
+ }
+
+ if (loopAnalysis->arrayAccessInfo->numUsed != 0) {
+ if (loopAnalysis->isCountUpLoop) {
+ MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
+ boundCheckMIR->dalvikInsn.opcode = (Opcode)kMirOpLowerBound;
+ boundCheckMIR->dalvikInsn.vA = idxReg;
+ boundCheckMIR->dalvikInsn.vB = globalMinC;
+ dvmCompilerAppendMIR(entry, boundCheckMIR);
+ } else {
+ if (loopAnalysis->loopBranchOpcode == OP_IF_LT ||
+ loopAnalysis->loopBranchOpcode == OP_IF_LE) {
+ MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR), true);
+ boundCheckMIR->dalvikInsn.opcode = (Opcode)kMirOpLowerBound;
+ boundCheckMIR->dalvikInsn.vA = loopAnalysis->endConditionReg;
+ boundCheckMIR->dalvikInsn.vB = globalMinC;
+ /*
+ * If the end condition is ">" in the source, the check in the
+ * Dalvik bytecode is OP_IF_LE. In this case add 1 back to the
+ * constant field to reflect the fact that the smallest index
+ * value is "endValue + constant + 1".
+ */
+ if (loopAnalysis->loopBranchOpcode == OP_IF_LE) {
+ boundCheckMIR->dalvikInsn.vB++;
+ }
+ dvmCompilerAppendMIR(entry, boundCheckMIR);
+ } else if (loopAnalysis->loopBranchOpcode == OP_IF_LTZ) {
+ /* Array index will fall below 0 */
+ if (globalMinC < 0) {
+ MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR),
+ true);
+ boundCheckMIR->dalvikInsn.opcode = (Opcode)kMirOpPunt;
+ dvmCompilerAppendMIR(entry, boundCheckMIR);
+ }
+ } else if (loopAnalysis->loopBranchOpcode == OP_IF_LEZ) {
+ /* Array index will fall below 0 */
+ if (globalMinC < -1) {
+ MIR *boundCheckMIR = (MIR *)dvmCompilerNew(sizeof(MIR),
+ true);
+ boundCheckMIR->dalvikInsn.opcode = (Opcode)kMirOpPunt;
+ dvmCompilerAppendMIR(entry, boundCheckMIR);
+ }
+ } else {
+ LOGE("Jit: bad case in genHoistedChecks");
+ dvmCompilerAbort(cUnit);
+ }
+ }
+ }
+}
+
+void resetBlockEdges(BasicBlock *bb)
+{
+ bb->taken = NULL;
+ bb->fallThrough = NULL;
+ bb->successorBlockList.blockListType = kNotUsed;
+}
+
+static bool clearPredecessorVector(struct CompilationUnit *cUnit,
+ struct BasicBlock *bb)
+{
+ dvmClearAllBits(bb->predecessors);
+ return false;
+}
+
+bool dvmCompilerFilterLoopBlocks(CompilationUnit *cUnit)
+{
+ BasicBlock *firstBB = cUnit->entryBlock->fallThrough;
+
+ int numPred = dvmCountSetBits(firstBB->predecessors);
+ /*
+ * A loop body should have at least two incoming edges.
+ */
+ if (numPred < 2) return false;
+
+ GrowableList *blockList = &cUnit->blockList;
+
+ /* Record blocks included in the loop */
+ dvmClearAllBits(cUnit->tempBlockV);
+
+ dvmCompilerSetBit(cUnit->tempBlockV, cUnit->entryBlock->id);
+ dvmCompilerSetBit(cUnit->tempBlockV, firstBB->id);
+
+ BasicBlock *bodyBB = firstBB;
+
+ /*
+ * First try to include the fall-through block in the loop, then the taken
+ * block. Stop loop formation on the first backward branch that enters the
+ * first block (ie only include the inner-most loop).
+ */
+ while (true) {
+ /* Loop formed */
+ if (bodyBB->taken == firstBB) {
+ /* Check if the fallThrough edge will cause a nested loop */
+ if (bodyBB->fallThrough &&
+ dvmIsBitSet(cUnit->tempBlockV, bodyBB->fallThrough->id)) {
+ return false;
+ }
+ /* Single loop formed */
+ break;
+ } else if (bodyBB->fallThrough == firstBB) {
+ /* Check if the taken edge will cause a nested loop */
+ if (bodyBB->taken &&
+ dvmIsBitSet(cUnit->tempBlockV, bodyBB->taken->id)) {
+ return false;
+ }
+ /* Single loop formed */
+ break;
+ }
+
+ /* Inner loops formed first - quit */
+ if (bodyBB->fallThrough &&
+ dvmIsBitSet(cUnit->tempBlockV, bodyBB->fallThrough->id)) {
+ return false;
+ }
+ if (bodyBB->taken &&
+ dvmIsBitSet(cUnit->tempBlockV, bodyBB->taken->id)) {
+ return false;
+ }
+
+ if (bodyBB->fallThrough) {
+ if (bodyBB->fallThrough->iDom == bodyBB) {
+ bodyBB = bodyBB->fallThrough;
+ dvmCompilerSetBit(cUnit->tempBlockV, bodyBB->id);
+ /*
+ * Loop formation to be detected at the beginning of next
+ * iteration.
+ */
+ continue;
+ }
+ }
+ if (bodyBB->taken) {
+ if (bodyBB->taken->iDom == bodyBB) {
+ bodyBB = bodyBB->taken;
+ dvmCompilerSetBit(cUnit->tempBlockV, bodyBB->id);
+ /*
+ * Loop formation to be detected at the beginning of next
+ * iteration.
+ */
+ continue;
+ }
+ }
+ /*
+ * Current block is not the immediate dominator of either fallthrough
+ * nor taken block - bail out of loop formation.
+ */
+ return false;
+ }
+
+
+ /* Now mark blocks not included in the loop as hidden */
+ GrowableListIterator iterator;
+ dvmGrowableListIteratorInit(blockList, &iterator);
+ while (true) {
+ BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
+ if (bb == NULL) break;
+ if (!dvmIsBitSet(cUnit->tempBlockV, bb->id)) {
+ bb->hidden = true;
+ /* Clear the insn list */
+ bb->firstMIRInsn = bb->lastMIRInsn = NULL;
+ resetBlockEdges(bb);
+ }
+ }
+
+ dvmCompilerDataFlowAnalysisDispatcher(cUnit, clearPredecessorVector,
+ kAllNodes, false /* isIterative */);
+
+ dvmGrowableListIteratorInit(blockList, &iterator);
+ while (true) {
+ BasicBlock *bb = (BasicBlock *) dvmGrowableListIteratorNext(&iterator);
+ if (bb == NULL) break;
+ if (dvmIsBitSet(cUnit->tempBlockV, bb->id)) {
+ if (bb->taken) {
+ /*
+ * exit block means we run into control-flow that we don't want
+ * to handle.
+ */
+ if (bb->taken == cUnit->exitBlock) {
+ return false;
+ }
+ if (bb->taken->hidden) {
+ bb->taken->blockType = kChainingCellNormal;
+ bb->taken->hidden = false;
+ }
+ dvmCompilerSetBit(bb->taken->predecessors, bb->id);
+ }
+ if (bb->fallThrough) {
+ /*
+ * exit block means we run into control-flow that we don't want
+ * to handle.
+ */
+ if (bb->fallThrough == cUnit->exitBlock) {
+ return false;
+ }
+ if (bb->fallThrough->hidden) {
+ bb->fallThrough->blockType = kChainingCellNormal;
+ bb->fallThrough->hidden = false;
+ }
+ dvmCompilerSetBit(bb->fallThrough->predecessors, bb->id);
+ }
+ /* Loop blocks shouldn't contain any successor blocks (yet) */
+ assert(bb->successorBlockList.blockListType == kNotUsed);
+ }
+ }
+ return true;
+}
+
+/*
+ * Main entry point to do loop optimization.
+ * Return false if sanity checks for loop formation/optimization failed.
+ */
+bool dvmCompilerLoopOpt(CompilationUnit *cUnit)
+{
+ LoopAnalysis *loopAnalysis =
+ (LoopAnalysis *)dvmCompilerNew(sizeof(LoopAnalysis), true);
+ cUnit->loopAnalysis = loopAnalysis;
+
+ /* Constant propagation */
+ cUnit->isConstantV = dvmAllocBitVector(cUnit->numSSARegs, false);
+ cUnit->constantValues =
+ (int *)dvmCompilerNew(sizeof(int) * cUnit->numSSARegs,
+ true);
+ dvmCompilerDataFlowAnalysisDispatcher(cUnit,
+ dvmCompilerDoConstantPropagation,
+ kAllNodes,
+ false /* isIterative */);
+ DEBUG_LOOP(dumpConstants(cUnit);)
+
+ /* Find induction variables - basic and dependent */
+ loopAnalysis->ivList =
+ (GrowableList *)dvmCompilerNew(sizeof(GrowableList), true);
+ dvmInitGrowableList(loopAnalysis->ivList, 4);
+ loopAnalysis->isIndVarV = dvmAllocBitVector(cUnit->numSSARegs, false);
+ dvmCompilerDataFlowAnalysisDispatcher(cUnit,
+ dvmCompilerFindInductionVariables,
+ kAllNodes,
+ false /* isIterative */);
+ DEBUG_LOOP(dumpIVList(cUnit);)
+
+ /* Only optimize array accesses for simple counted loop for now */
+ if (!isSimpleCountedLoop(cUnit))
+ return false;
+
+ loopAnalysis->arrayAccessInfo =
+ (GrowableList *)dvmCompilerNew(sizeof(GrowableList), true);
+ dvmInitGrowableList(loopAnalysis->arrayAccessInfo, 4);
+ loopAnalysis->bodyIsClean = doLoopBodyCodeMotion(cUnit);
+ DEBUG_LOOP(dumpHoistedChecks(cUnit);)
+
+ /*
+ * Convert the array access information into extended MIR code in the loop
+ * header.
+ */
+ genHoistedChecks(cUnit);
+ return true;
+}
+
+/*
+ * Select the target block of the backward branch.
+ */
+void dvmCompilerInsertBackwardChaining(CompilationUnit *cUnit)
+{
+ /*
+ * If we are not in self-verification or profiling mode, the backward
+ * branch can go to the entryBlock->fallThrough directly. Suspend polling
+ * code will be generated along the backward branch to honor the suspend
+ * requests.
+ */
+#if !defined(WITH_SELF_VERIFICATION)
+ if (gDvmJit.profileMode != kTraceProfilingContinuous &&
+ gDvmJit.profileMode != kTraceProfilingPeriodicOn) {
+ return;
+ }
+#endif
+ /*
+ * In self-verification or profiling mode, the backward branch is altered
+ * to go to the backward chaining cell. Without using the backward chaining
+ * cell we won't be able to do check-pointing on the target PC, or count the
+ * number of iterations accurately.
+ */
+ BasicBlock *firstBB = cUnit->entryBlock->fallThrough;
+ BasicBlock *backBranchBB = findPredecessorBlock(cUnit, firstBB);
+ if (backBranchBB->taken == firstBB) {
+ backBranchBB->taken = cUnit->backChainBlock;
+ } else {
+ assert(backBranchBB->fallThrough == firstBB);
+ backBranchBB->fallThrough = cUnit->backChainBlock;
+ }
+ cUnit->backChainBlock->startOffset = firstBB->startOffset;
+}