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)) {