aboutsummaryrefslogtreecommitdiff
path: root/vm/compiler/codegen/arm/GlobalOptimizations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vm/compiler/codegen/arm/GlobalOptimizations.cpp')
-rw-r--r--vm/compiler/codegen/arm/GlobalOptimizations.cpp208
1 files changed, 208 insertions, 0 deletions
diff --git a/vm/compiler/codegen/arm/GlobalOptimizations.cpp b/vm/compiler/codegen/arm/GlobalOptimizations.cpp
index 45a063105..b6c81851a 100644
--- a/vm/compiler/codegen/arm/GlobalOptimizations.cpp
+++ b/vm/compiler/codegen/arm/GlobalOptimizations.cpp
@@ -17,6 +17,16 @@
#include "Dalvik.h"
#include "vm/compiler/CompilerInternals.h"
#include "ArmLIR.h"
+#include "vm/compiler/Loop.h"
+
+/* Max number of hoistable loop load operations. */
+#define MAX_LOAD_HOISTS 25 // Should be more than enough, considering ARM only has 16 registers.
+/* Max number of operations that access dalvik registers. */
+#define MAX_REGISTER_OPS 50
+
+/* Enable verbose prints for loop load hoisting by setting this define.
+#define LOOP_LOAD_HOIST_VERBOSE
+ */
/*
* Identify unconditional branches that jump to the immediate successor of the
@@ -59,7 +69,205 @@ static void applyRedundantBranchElimination(CompilationUnit *cUnit)
}
}
+/*
+ * 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);
+}
+
void dvmCompilerApplyGlobalOptimizations(CompilationUnit *cUnit)
{
applyRedundantBranchElimination(cUnit);
+
+ if (cUnit->jitMode == kJitLoop) {
+ applyLoopLoadHoisting(cUnit);
+ }
}