Allow dx to properly generate sub-const and rsub-const insns.
Dx can now handle instructions of the form "reg - const" by converting
it into an equivalent add-const with negative constant. Also, dx can
handle instructions of the form "const - reg" by creating an rsub-const
instruction, which was previously unused.
Change-Id: I67d869b5e14b65f6bbd1daae8bf0c662296af5de
diff --git a/dx/src/com/android/dx/cf/code/RopperMachine.java b/dx/src/com/android/dx/cf/code/RopperMachine.java
index 0768cc8..5da2588 100644
--- a/dx/src/com/android/dx/cf/code/RopperMachine.java
+++ b/dx/src/com/android/dx/cf/code/RopperMachine.java
@@ -32,6 +32,7 @@
import com.android.dx.rop.code.TranslationAdvice;
import com.android.dx.rop.cst.Constant;
import com.android.dx.rop.cst.CstFieldRef;
+import com.android.dx.rop.cst.CstInteger;
import com.android.dx.rop.cst.CstMethodRef;
import com.android.dx.rop.cst.CstNat;
import com.android.dx.rop.cst.CstType;
@@ -517,19 +518,40 @@
*/
cst = CstType.intern(rop.getResult());
} else if ((cst == null) && (sourceCount == 2)) {
+ TypeBearer firstType = sources.get(0).getTypeBearer();
TypeBearer lastType = sources.get(1).getTypeBearer();
- if (lastType.isConstant()
- && advice.hasConstantOperation(rop,
- sources.get(0), sources.get(1))) {
- /*
- * The target architecture has an instruction that can
- * build in the constant found in the second argument,
- * so pull it out of the sources and just use it as a
- * constant here.
- */
- cst = (Constant) lastType;
- sources = sources.withoutLast();
+ if ((lastType.isConstant() || firstType.isConstant()) &&
+ advice.hasConstantOperation(rop, sources.get(0),
+ sources.get(1))) {
+
+ if (lastType.isConstant()) {
+ /*
+ * The target architecture has an instruction that can
+ * build in the constant found in the second argument,
+ * so pull it out of the sources and just use it as a
+ * constant here.
+ */
+ cst = (Constant) lastType;
+ sources = sources.withoutLast();
+
+ // For subtraction, change to addition and invert constant
+ if (rop.getOpcode() == RegOps.SUB) {
+ ropOpcode = RegOps.ADD;
+ CstInteger cstInt = (CstInteger) lastType;
+ cst = CstInteger.make(-cstInt.getValue());
+ }
+ } else {
+ /*
+ * The target architecture has an instruction that can
+ * build in the constant found in the first argument,
+ * so pull it out of the sources and just use it as a
+ * constant here.
+ */
+ cst = (Constant) firstType;
+ sources = sources.withoutFirst();
+ }
+
rop = Rops.ropFor(ropOpcode, destType, sources, cst);
}
}
diff --git a/dx/src/com/android/dx/dex/code/RopToDop.java b/dx/src/com/android/dx/dex/code/RopToDop.java
index 856386b..6b92126 100644
--- a/dx/src/com/android/dx/dex/code/RopToDop.java
+++ b/dx/src/com/android/dx/dex/code/RopToDop.java
@@ -318,10 +318,10 @@
MAP.put(Rops.ADD_CONST_INT, Dops.ADD_INT_LIT8);
// Note: No dalvik ops for other types of add_const.
+ MAP.put(Rops.SUB_CONST_INT, Dops.RSUB_INT_LIT8);
/*
- * Note: No dalvik ops for any type of sub_const; there's a
- * *reverse* sub (constant - reg) for ints, though, but that
- * should end up getting handled at optimization time.
+ * Note: No dalvik ops for any type of sub_const; instead
+ * there's a *reverse* sub (constant - reg) for ints only.
*/
MAP.put(Rops.MUL_CONST_INT, Dops.MUL_INT_LIT8);
diff --git a/dx/src/com/android/dx/rop/code/DexTranslationAdvice.java b/dx/src/com/android/dx/rop/code/DexTranslationAdvice.java
index 8dbc00b..35ce2f2 100644
--- a/dx/src/com/android/dx/rop/code/DexTranslationAdvice.java
+++ b/dx/src/com/android/dx/rop/code/DexTranslationAdvice.java
@@ -60,13 +60,20 @@
return false;
}
+ // Return false if second source isn't a constant
if (! (sourceB.getTypeBearer() instanceof CstInteger)) {
- return false;
+ // Except for rsub-int (reverse sub) where first source is constant
+ if (sourceA.getTypeBearer() instanceof CstInteger &&
+ opcode.getOpcode() == RegOps.SUB) {
+ CstInteger cst = (CstInteger) sourceA.getTypeBearer();
+ return cst.fitsIn16Bits();
+ } else {
+ return false;
+ }
}
CstInteger cst = (CstInteger) sourceB.getTypeBearer();
- // TODO handle rsub
switch (opcode.getOpcode()) {
// These have 8 and 16 bit cst representations
case RegOps.REM:
@@ -82,6 +89,10 @@
case RegOps.SHR:
case RegOps.USHR:
return cst.fitsIn8Bits();
+ // No sub-const insn, so check if equivalent add-const fits
+ case RegOps.SUB:
+ CstInteger cst2 = CstInteger.make(-cst.getValue());
+ return cst2.fitsIn16Bits();
default:
return false;
}