/* * Dump the liveness bits to the log. * * "curIdx" is for display only. */ static void dumpLiveState(const VerifierData* vdata, u4 curIdx, const BitVector* workBits) { u4 insnRegCount = vdata->insnRegCount; size_t regCharSize = insnRegCount + (insnRegCount-1)/4 + 2 +1; #ifndef __GNUC__ char* regChars = (char*)alloca(regCharSize +1); #else char regChars[regCharSize +1]; #endif unsigned int idx; memset(regChars, ' ', regCharSize); regChars[0] = '['; if (insnRegCount == 0) regChars[1] = ']'; else regChars[1 + (insnRegCount-1) + (insnRegCount-1)/4 +1] = ']'; regChars[regCharSize] = '\0'; for (idx = 0; idx < insnRegCount; idx++) { char ch = dvmIsBitSet(workBits, idx) ? '+' : '-'; regChars[1 + idx + (idx/4)] = ch; } ALOGI("0x%04x %s", curIdx, regChars); }
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; } }
/* * Perform null-check on a register. sReg is the ssa register being checked, * and mReg is the machine register holding the actual value. If internal state * indicates that sReg has been checked before the check request is ignored. */ static ArmLIR *genNullCheck(CompilationUnit *cUnit, int sReg, int mReg, int dOffset, ArmLIR *pcrLabel) { /* This particular Dalvik register has been null-checked */ if (dvmIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) { return pcrLabel; } dvmSetBit(cUnit->regPool->nullCheckedRegs, sReg); return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel); }
/* 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]); } } }
/* Worker function to compute the idom */ static bool computeImmediateDominator(CompilationUnit *cUnit, BasicBlock *bb) { GrowableList *blockList = &cUnit->blockList; BitVector *tempBlockV = cUnit->tempBlockV; BitVectorIterator bvIterator; BasicBlock *iDom; if (bb == cUnit->entryBlock) return false; dvmCopyBitVector(tempBlockV, bb->dominators); dvmClearBit(tempBlockV, bb->id); dvmBitVectorIteratorInit(tempBlockV, &bvIterator); /* Should not see any dead block */ assert(dvmCountSetBits(tempBlockV) != 0); if (dvmCountSetBits(tempBlockV) == 1) { iDom = (BasicBlock *) dvmGrowableListGetElement( blockList, dvmBitVectorIteratorNext(&bvIterator)); bb->iDom = iDom; } else { int iDomIdx = dvmBitVectorIteratorNext(&bvIterator); assert(iDomIdx != -1); while (true) { int nextDom = dvmBitVectorIteratorNext(&bvIterator); if (nextDom == -1) break; BasicBlock *nextDomBB = (BasicBlock *) dvmGrowableListGetElement(blockList, nextDom); /* iDom dominates nextDom - set new iDom */ if (dvmIsBitSet(nextDomBB->dominators, iDomIdx)) { iDomIdx = nextDom; } } iDom = (BasicBlock *) dvmGrowableListGetElement(blockList, iDomIdx); /* Set the immediate dominator block for bb */ bb->iDom = iDom; } /* Add bb to the iDominated set of the immediate dominator block */ dvmCompilerSetBit(iDom->iDominated, bb->id); return true; }
/* Compute the post-order traversal of the CFG */ static void computeDomPostOrderTraversal(CompilationUnit *cUnit, BasicBlock *bb) { BitVectorIterator bvIterator; dvmBitVectorIteratorInit(bb->iDominated, &bvIterator); GrowableList *blockList = &cUnit->blockList; /* Iterate through the dominated blocks first */ while (true) { int bbIdx = dvmBitVectorIteratorNext(&bvIterator); if (bbIdx == -1) break; BasicBlock *dominatedBB = (BasicBlock *) dvmGrowableListGetElement(blockList, bbIdx); computeDomPostOrderTraversal(cUnit, dominatedBB); } /* Enter the current block id */ dvmInsertGrowableList(&cUnit->domPostOrderTraversal, bb->id); /* hacky loop detection */ if (bb->taken && dvmIsBitSet(bb->dominators, bb->taken->id)) { cUnit->hasLoop = true; } }
/* * 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; }
/* Insert phi nodes to for each variable to the dominance frontiers */ static void insertPhiNodes(CompilationUnit *cUnit) { int dalvikReg; const GrowableList *blockList = &cUnit->blockList; BitVector *phiBlocks = dvmCompilerAllocBitVector(cUnit->numBlocks, false); BitVector *tmpBlocks = dvmCompilerAllocBitVector(cUnit->numBlocks, false); BitVector *inputBlocks = dvmCompilerAllocBitVector(cUnit->numBlocks, false); cUnit->tempDalvikRegisterV = dvmCompilerAllocBitVector(cUnit->numDalvikRegisters, false); dvmCompilerDataFlowAnalysisDispatcher(cUnit, computeBlockLiveIns, kPostOrderDFSTraversal, true /* isIterative */); /* Iterate through each Dalvik register */ for (dalvikReg = 0; dalvikReg < cUnit->numDalvikRegisters; dalvikReg++) { bool change; BitVectorIterator iterator; dvmCopyBitVector(inputBlocks, cUnit->defBlockMatrix[dalvikReg]); dvmClearAllBits(phiBlocks); /* Calculate the phi blocks for each Dalvik register */ do { change = false; dvmClearAllBits(tmpBlocks); dvmBitVectorIteratorInit(inputBlocks, &iterator); while (true) { int idx = dvmBitVectorIteratorNext(&iterator); if (idx == -1) break; BasicBlock *defBB = (BasicBlock *) dvmGrowableListGetElement(blockList, idx); /* Merge the dominance frontier to tmpBlocks */ dvmUnifyBitVectors(tmpBlocks, tmpBlocks, defBB->domFrontier); } if (dvmCompareBitVectors(phiBlocks, tmpBlocks)) { change = true; dvmCopyBitVector(phiBlocks, tmpBlocks); /* * Iterate through the original blocks plus the new ones in * the dominance frontier. */ dvmCopyBitVector(inputBlocks, phiBlocks); dvmUnifyBitVectors(inputBlocks, inputBlocks, cUnit->defBlockMatrix[dalvikReg]); } } while (change); /* * Insert a phi node for dalvikReg in the phiBlocks if the Dalvik * register is in the live-in set. */ dvmBitVectorIteratorInit(phiBlocks, &iterator); while (true) { int idx = dvmBitVectorIteratorNext(&iterator); if (idx == -1) break; BasicBlock *phiBB = (BasicBlock *) dvmGrowableListGetElement(blockList, idx); /* Variable will be clobbered before being used - no need for phi */ if (!dvmIsBitSet(phiBB->dataFlowInfo->liveInV, dalvikReg)) continue; MIR *phi = (MIR *) dvmCompilerNew(sizeof(MIR), true); phi->dalvikInsn.opcode = (Opcode) kMirOpPhi; phi->dalvikInsn.vA = dalvikReg; phi->offset = phiBB->startOffset; dvmCompilerPrependMIR(phiBB, phi); } } }