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;
         }