Added support for integer division to SCCP.

Division generates a result that must be fetched with a
move-result-pseudo instruction. SCCP originally had no way of tying the
division with the result it generates. This change should allow proper
constant propagation when division of integers is involved.

Change-Id: Ib7c5d2dd26eea3ab6545b613a540f0161a8e1642
diff --git a/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java b/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java
index bac1d2c..e36c6ff 100644
--- a/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java
+++ b/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java
@@ -30,6 +30,7 @@
 import com.android.dx.rop.type.Type;
 import com.android.dx.rop.type.TypeBearer;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -97,16 +98,7 @@
                 RegisterSpecList sources = insn.getSources();
 
                 // Replace insns with constant results with const insns
-                if (insn.getResult() != null &&
-                        opcode.getOpcode() != RegOps.CONST) {
-                    TypeBearer type = insn.getResult().getTypeBearer();
-                    if (type.isConstant() &&
-                            type.getBasicType() == Type.BT_INT) {
-                        replacePlainInsn(insn, RegisterSpecList.EMPTY,
-                                RegOps.CONST, (Constant) type);
-                        return;
-                    }
-                }
+                if (tryReplacingWithConstant(insn)) return;
 
                 if (sources.size() != 2 ) {
                     // We're only dealing with two-source insns here.
@@ -145,6 +137,40 @@
     }
 
     /**
+     * Tries to replace an instruction with a const instruction. The given
+     * instruction must have a constant result for it to be replaced.
+     *
+     * @param insn {@code non-null;} instruction to try to replace
+     * @return true if the instruction was replaced
+     */
+    private boolean tryReplacingWithConstant(NormalSsaInsn insn) {
+        Insn originalRopInsn = insn.getOriginalRopInsn();
+        Rop opcode = originalRopInsn.getOpcode();
+
+        if (insn.getResult() != null && opcode.getOpcode() != RegOps.CONST) {
+            TypeBearer type = insn.getResult().getTypeBearer();
+            if (type.isConstant() && type.getBasicType() == Type.BT_INT) {
+                // Replace the instruction with a constant
+                replacePlainInsn(insn, RegisterSpecList.EMPTY,
+                        RegOps.CONST, (Constant) type);
+
+                // Remove the source as well if this is a move-result-pseudo
+                if (opcode.getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
+                    int pred = insn.getBlock().getPredecessors().nextSetBit(0);
+                    ArrayList<SsaInsn> predInsns =
+                            ssaMeth.getBlocks().get(pred).getInsns();
+                    NormalSsaInsn sourceInsn =
+                            (NormalSsaInsn) predInsns.get(predInsns.size()-1);
+                    replacePlainInsn(sourceInsn, RegisterSpecList.EMPTY,
+                            RegOps.GOTO, null);
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Replaces an SsaInsn containing a PlainInsn with a new PlainInsn. The
      * new PlainInsn is constructed with a new RegOp and new sources.
      *
diff --git a/dx/src/com/android/dx/ssa/SCCP.java b/dx/src/com/android/dx/ssa/SCCP.java
index d158030..edc1923 100644
--- a/dx/src/com/android/dx/ssa/SCCP.java
+++ b/dx/src/com/android/dx/ssa/SCCP.java
@@ -358,9 +358,10 @@
      * Simulates math insns, if possible.
      *
      * @param insn non-null insn to simulate
+     * @param resultType basic type of the result
      * @return constant result or null if not simulatable.
      */
-    private Constant simulateMath(SsaInsn insn) {
+    private Constant simulateMath(SsaInsn insn, int resultType) {
         Insn ropInsn = insn.getOriginalRopInsn();
         int opcode = insn.getOpcode().getOpcode();
         RegisterSpecList sources = insn.getSources();
@@ -391,7 +392,7 @@
             return null;
         }
 
-        switch (insn.getResult().getBasicType()) {
+        switch (resultType) {
             case Type.BT_INT:
                 int vR;
                 boolean skip=false;
@@ -470,11 +471,26 @@
             return;
         }
 
-        /* TODO: Simplify statements when possible using the constants. */
         int resultReg = insn.getResult().getReg();
+        int resultType = insn.getResult().getBasicType();
         int resultValue = VARYING;
         Constant resultConstant = null;
         int opcode = insn.getOpcode().getOpcode();
+
+        // TODO: Handle non-int arithmetic.
+        if (resultType != Type.BT_INT) {
+            return;
+        }
+
+        // Find defining instruction for move-result-pseudo instructions
+        if (opcode == RegOps.MOVE_RESULT_PSEUDO) {
+            int pred = insn.getBlock().getPredecessors().nextSetBit(0);
+            ArrayList<SsaInsn> predInsns;
+            predInsns = ssaMeth.getBlocks().get(pred).getInsns();
+            insn = predInsns.get(predInsns.size()-1);
+            opcode = insn.getOpcode().getOpcode();
+        }
+
         switch (opcode) {
             case RegOps.CONST: {
                 CstInsn cstInsn = (CstInsn)ropInsn;
@@ -503,7 +519,7 @@
             case RegOps.USHR:
             case RegOps.REM:
 
-                resultConstant = simulateMath(insn);
+                resultConstant = simulateMath(insn, resultType);
 
                 if (resultConstant == null) {
                     resultValue = VARYING;
@@ -511,8 +527,7 @@
                     resultValue = CONSTANT;
                 }
             break;
-            /* TODO: Handle non-int arithmetic.
-               TODO: Eliminate check casts that we can prove the type of. */
+            // TODO: Eliminate check casts that we can prove the type of.
             default: {}
         }
         if (setLatticeValueTo(resultReg, resultValue, resultConstant)) {