/* Debugging utility routine */ static void dumpDependentInsnPair(MipsLIR *thisLIR, MipsLIR *checkLIR, const char *optimization) { LOGD("************ %s ************", optimization); dvmDumpLIRInsn((LIR *) thisLIR, 0); dvmDumpLIRInsn((LIR *) checkLIR, 0); }
__attribute__((weak)) void dumpBothLIRs(CompilationUnit *cUnit, ArmLIR *thisLIR, ArmLIR *checkLIR) { if(cUnit->printMe) { ALOGD("thisLIR"); dvmDumpLIRInsn((LIR*)thisLIR,0); ALOGD("checkLIR"); dvmDumpLIRInsn((LIR*)checkLIR,0); } }
/* * Perform a pass to hoist all frame pointer load instructions that * are independent, outside the loop. */ static void applyLoopLoadHoisting(CompilationUnit *cUnit) { ArmLIR *thisLIR, *labelLIR, *lastLIR, *insertLIR; ArmLIR *loadLIR[MAX_LOAD_HOISTS]; ArmLIR *regLIR[MAX_REGISTER_OPS]; u8 defLoadMask = 0; u8 defMask = 0; u8 masterDefMask = ~((1ULL << kRegEnd) - 1); bool isValidLoop = false; int loadCount = 0; int regCount = 0; int loadindex; int hoistCount = 0; #ifdef LOOP_LOAD_HOIST_VERBOSE ALOGD("GlobalOpts LoopLoadHoisting applied on '%s'", cUnit->method->name); cUnit->printMe = true; #endif labelLIR = (ArmLIR *) cUnit->firstLIRInsn; lastLIR = (ArmLIR *) cUnit->lastLIRInsn; insertLIR = NULL; /* Find the insert point */ while ((labelLIR != lastLIR) && (labelLIR->flags.isNop || (labelLIR->opcode != kArmPseudoNormalBlockLabel))) { if ((cUnit->loopAnalysis->branchesAdded) && (labelLIR->opcode == kThumbBUncond) && (insertLIR == NULL) && (!labelLIR->flags.isNop)) insertLIR = labelLIR; labelLIR = NEXT_LIR(labelLIR); } if (labelLIR->opcode != kArmPseudoNormalBlockLabel) { #ifdef LOOP_LOAD_HOIST_VERBOSE ALOGD("Can't hoist - no loop label found!"); #endif return; } if (insertLIR == NULL) { insertLIR = labelLIR; } else if ((ArmLIR *) insertLIR->generic.target != labelLIR) { #ifdef LOOP_LOAD_HOIST_VERBOSE ALOGD("Can't hoist - branch target does not match!"); #endif return; } /* Search for eligible load instructions to hoist */ for (thisLIR = labelLIR; thisLIR != lastLIR; thisLIR = NEXT_LIR(thisLIR)) { bool handled = false; int flags; /* Skip non-interesting instructions */ if (thisLIR->flags.isNop || isPseudoOpcode(thisLIR->opcode)) continue; flags = EncodingMap[thisLIR->opcode].flags; /* If it's a load instruction, check if it's a hoist candidate. */ if (((flags & IS_LOAD) != 0) && ((thisLIR->useMask & ENCODE_DALVIK_REG) != 0)) { if (regCount >= MAX_REGISTER_OPS) { #ifdef LOOP_LOAD_HOIST_VERBOSE ALOGD("Out of register list space!"); #endif return; } regLIR[regCount++] = thisLIR; if ((((defLoadMask | defMask) & thisLIR->defMask) == 0) && (loadCount < MAX_LOAD_HOISTS)) { defLoadMask |= thisLIR->defMask; loadLIR[loadCount++] = thisLIR; handled = true; } else { masterDefMask |= thisLIR->defMask; } /* If it's a store instruction, check if it matches a previous hoistable load instruction. If so, reset the global def-flag to indicate that the load is still hoistable. */ } else if (((flags & IS_STORE) != 0) && ((thisLIR->defMask & ENCODE_DALVIK_REG) != 0)) { if (regCount >= MAX_REGISTER_OPS) { #ifdef LOOP_LOAD_HOIST_VERBOSE ALOGD("Out of register list space!"); #endif return; } regLIR[regCount++] = thisLIR; if ((thisLIR->useMask & defLoadMask) != 0) { handled = true; for (int i = loadCount - 1; i >= 0; i--) { if ((thisLIR->aliasInfo == loadLIR[i]->aliasInfo) && (thisLIR->operands[0] == loadLIR[i]->operands[0])) { defMask &= ~(loadLIR[i]->defMask); break; } } } /* If it's a branch instruction, check if it's the loop branch. If it matches the label, mark it as a valid loop. */ } else if ((flags & IS_BRANCH) != 0) { handled = true; if (labelLIR == (ArmLIR *) thisLIR->generic.target) { isValidLoop = true; } else if ((thisLIR->opcode >= kThumbBlx1) && (thisLIR->opcode <= kThumbBlxR)) { #ifdef LOOP_LOAD_HOIST_VERBOSE ALOGD("Trace contains branch to subroutine!"); #endif return; } } else if (thisLIR->opcode == kThumbUndefined) { break; } /* If it's not a 'special' instruction, accumulate into def-flags. */ if (!handled) defMask |= thisLIR->defMask; } defLoadMask &= ~(defMask | masterDefMask); if (!isValidLoop || (defLoadMask == 0)) { #ifdef LOOP_LOAD_HOIST_VERBOSE ALOGD("Loop not valid, or defLoadMask (0x%llx) was zero!", defLoadMask); #endif return; } #ifdef LOOP_LOAD_HOIST_VERBOSE ALOGD("Masks: masterDef: 0x%llx, def: 0x%llx, final defLoad: 0x%llx", masterDefMask, defMask, defLoadMask); #endif /* Try to hoist the load operations */ for (loadindex = 0; loadindex < loadCount; loadindex++) { thisLIR = loadLIR[loadindex]; /* Host this load? */ if ((thisLIR->defMask & defLoadMask) == thisLIR->defMask) { int i; bool foundAlias = false; for (i = 0; i < regCount; i++) { if ((thisLIR->aliasInfo == regLIR[i]->aliasInfo) && (thisLIR->operands[0] != regLIR[i]->operands[0])) { foundAlias = true; for (int k = loadindex; k < loadCount; k++) { if (loadLIR[k] == regLIR[i]) { loadLIR[k]->defMask = -1; break; } } #ifdef LOOP_LOAD_HOIST_VERBOSE ALOGD("Register alias found between these two load ops:"); dvmDumpLIRInsn((LIR*)thisLIR, NULL); dvmDumpLIRInsn((LIR*)regLIR[i], NULL); #endif break; } } if (!foundAlias) { #ifdef LOOP_LOAD_HOIST_VERBOSE ALOGD("Hoisting this load op:"); dvmDumpLIRInsn((LIR*)thisLIR, NULL); #endif ArmLIR *newLoadLIR = (ArmLIR *) dvmCompilerNew(sizeof(ArmLIR), true); *newLoadLIR = *thisLIR; dvmCompilerInsertLIRBefore((LIR *) insertLIR, (LIR *) newLoadLIR); thisLIR->flags.isNop = true; hoistCount++; } } } if (cUnit->printMe) ALOGD("GlobalOpt LoopLoadHoist hoisted %d load ops.", hoistCount); }