summaryrefslogtreecommitdiffstats
path: root/vm/compiler/codegen/arm/LocalOptimizations.c
diff options
context:
space:
mode:
Diffstat (limited to 'vm/compiler/codegen/arm/LocalOptimizations.c')
-rw-r--r--vm/compiler/codegen/arm/LocalOptimizations.c148
1 files changed, 142 insertions, 6 deletions
diff --git a/vm/compiler/codegen/arm/LocalOptimizations.c b/vm/compiler/codegen/arm/LocalOptimizations.c
index 159c2aae5..9f616b836 100644
--- a/vm/compiler/codegen/arm/LocalOptimizations.c
+++ b/vm/compiler/codegen/arm/LocalOptimizations.c
@@ -26,12 +26,18 @@ ArmLIR* dvmCompilerGenCopy(CompilationUnit *cUnit, int rDest, int rSrc);
/* Is this a Dalvik register access? */
static inline bool isDalvikLoad(ArmLIR *lir)
{
- return (lir->useMask != ~0ULL) && (lir->useMask & ENCODE_DALVIK_REG);
+ return (lir->useMask != ENCODE_ALL) && (lir->useMask & ENCODE_DALVIK_REG);
+}
+
+/* Is this a load from the literal pool? */
+static inline bool isLiteralLoad(ArmLIR *lir)
+{
+ return (lir->useMask != ENCODE_ALL) && (lir->useMask & ENCODE_LITERAL);
}
static inline bool isDalvikStore(ArmLIR *lir)
{
- return (lir->defMask != ~0ULL) && (lir->defMask & ENCODE_DALVIK_REG);
+ return (lir->defMask != ENCODE_ALL) && (lir->defMask & ENCODE_DALVIK_REG);
}
static inline bool isDalvikRegisterClobbered(ArmLIR *lir1, ArmLIR *lir2)
@@ -169,6 +175,12 @@ static void applyLoadHoisting(CompilationUnit *cUnit,
ArmLIR *tailLIR)
{
ArmLIR *thisLIR;
+ /*
+ * Don't want to hoist in front of first load following a barrier (or
+ * first instruction of the block.
+ */
+ bool firstLoad = true;
+ int maxHoist = dvmCompilerTargetOptHint(kMaxHoistDistance);
cUnit->optRound++;
for (thisLIR = headLIR;
@@ -179,6 +191,18 @@ static void applyLoadHoisting(CompilationUnit *cUnit,
thisLIR->isNop == true) {
continue;
}
+
+ if (firstLoad && (EncodingMap[thisLIR->opCode].flags & IS_LOAD)) {
+ /*
+ * Ensure nothing will be hoisted in front of this load because
+ * it's result will likely be needed soon.
+ */
+ thisLIR->defMask |= ENCODE_MEM_USE;
+ firstLoad = false;
+ }
+
+ firstLoad |= (thisLIR->defMask == ENCODE_ALL);
+
if (isDalvikLoad(thisLIR)) {
int dRegId = DECODE_ALIAS_INFO_REG(thisLIR->aliasInfo);
int dRegIdHi = dRegId + DECODE_ALIAS_INFO_WIDE(thisLIR->aliasInfo);
@@ -186,8 +210,8 @@ static void applyLoadHoisting(CompilationUnit *cUnit,
ArmLIR *checkLIR;
int hoistDistance = 0;
u8 stopUseMask = (ENCODE_REG_PC | thisLIR->useMask) &
- ~ENCODE_DALVIK_REG;
- u8 stopDefMask = thisLIR->defMask & ~ENCODE_DALVIK_REG;
+ ~ENCODE_FRAME_REF;
+ u8 stopDefMask = thisLIR->defMask & ~ENCODE_FRAME_REF;
/* First check if the load can be completely elinimated */
for (checkLIR = PREV_LIR(thisLIR);
@@ -243,8 +267,15 @@ static void applyLoadHoisting(CompilationUnit *cUnit,
if (checkLIR->isNop) continue;
- /* Check if the current load is redundant */
- if ((isDalvikLoad(checkLIR) || isDalvikStore(checkLIR)) &&
+ /*
+ * Check if the "thisLIR" load is redundant
+ * NOTE: At one point, we also triggered if the checkLIR
+ * instruction was a load. However, that tended to insert
+ * a load/use dependency because the full scheduler is
+ * not yet complete. When it is, we chould also trigger
+ * on loads.
+ */
+ if (isDalvikStore(checkLIR) &&
(checkLIR->aliasInfo == thisLIR->aliasInfo) &&
(REGTYPE(checkLIR->operands[0]) == REGTYPE(nativeRegId))) {
/* Insert a move to replace the load */
@@ -301,6 +332,9 @@ static void applyLoadHoisting(CompilationUnit *cUnit,
}
}
+ /* Don't go too far */
+ stopHere |= (hoistDistance >= maxHoist);
+
/* Found a new place to put the load - move it here */
if (stopHere == true) {
DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
@@ -331,6 +365,108 @@ static void applyLoadHoisting(CompilationUnit *cUnit,
}
}
}
+ } else if (isLiteralLoad(thisLIR)) {
+ int litVal = thisLIR->aliasInfo;
+ int nativeRegId = thisLIR->operands[0];
+ ArmLIR *checkLIR;
+ int hoistDistance = 0;
+ u8 stopUseMask = (ENCODE_REG_PC | thisLIR->useMask) &
+ ~ENCODE_LITPOOL_REF;
+ u8 stopDefMask = thisLIR->defMask & ~ENCODE_LITPOOL_REF;
+
+ /* First check if the load can be completely elinimated */
+ for (checkLIR = PREV_LIR(thisLIR);
+ checkLIR != headLIR;
+ checkLIR = PREV_LIR(checkLIR)) {
+
+ if (checkLIR->isNop) continue;
+
+ /* Reloading same literal into same tgt reg? Eliminate if so */
+ if (isLiteralLoad(checkLIR) &&
+ (checkLIR->aliasInfo == litVal) &&
+ (checkLIR->operands[0] == nativeRegId)) {
+ thisLIR->isNop = true;
+ break;
+ }
+
+ /*
+ * No earlier use/def can reach this load if:
+ * 1) Head instruction is reached
+ * 2) load target register is clobbered
+ * 3) A branch is seen (stopUseMask has the PC bit set).
+ */
+ if ((checkLIR == headLIR) ||
+ (stopUseMask | stopDefMask) & checkLIR->defMask) {
+ break;
+ }
+ }
+
+ /* The load has been eliminated */
+ if (thisLIR->isNop) continue;
+
+ /*
+ * The load cannot be eliminated. See if it can be hoisted to an
+ * earlier spot.
+ */
+ for (checkLIR = PREV_LIR(thisLIR);
+ /* empty by intention */;
+ checkLIR = PREV_LIR(checkLIR)) {
+
+ if (checkLIR->isNop) continue;
+
+ /*
+ * TUNING: once a full scheduler exists, check here
+ * for conversion of a redundant load into a copy similar
+ * to the way redundant loads are handled above.
+ */
+
+ /* Find out if the load can be yanked past the checkLIR */
+
+ /* Last instruction reached */
+ bool stopHere = (checkLIR == headLIR);
+
+ /* Base address is clobbered by checkLIR */
+ stopHere |= ((stopUseMask & checkLIR->defMask) != 0);
+
+ /* Load target clobbers use/def in checkLIR */
+ stopHere |= ((stopDefMask &
+ (checkLIR->useMask | checkLIR->defMask)) != 0);
+
+ /* Avoid re-ordering literal pool loads */
+ stopHere |= isLiteralLoad(checkLIR);
+
+ /* Don't go too far */
+ stopHere |= (hoistDistance >= maxHoist);
+
+ /* Found a new place to put the load - move it here */
+ if (stopHere == true) {
+ DEBUG_OPT(dumpDependentInsnPair(thisLIR, checkLIR,
+ "HOIST LOAD"));
+ /* The store can be hoisted for at least one cycle */
+ if (hoistDistance != 0) {
+ ArmLIR *newLoadLIR =
+ dvmCompilerNew(sizeof(ArmLIR), true);
+ *newLoadLIR = *thisLIR;
+ newLoadLIR->age = cUnit->optRound;
+ /*
+ * Insertion is guaranteed to succeed since checkLIR
+ * is never the first LIR on the list
+ */
+ dvmCompilerInsertLIRAfter((LIR *) checkLIR,
+ (LIR *) newLoadLIR);
+ thisLIR->isNop = true;
+ }
+ break;
+ }
+
+ /*
+ * Saw a real instruction that hosting the load is
+ * beneficial
+ */
+ if (!isPseudoOpCode(checkLIR->opCode)) {
+ hoistDistance++;
+ }
+ }
}
}
}