Resolve single vs object in IRBuilder.
Bug: 72693244
Change-Id: Ibb9228144e2ff9dd92c88c1b20be88a8d3b52ebd
diff --git a/src/main/java/com/android/tools/r8/code/Format21t.java b/src/main/java/com/android/tools/r8/code/Format21t.java
index 40b7227..3b53e89 100644
--- a/src/main/java/com/android/tools/r8/code/Format21t.java
+++ b/src/main/java/com/android/tools/r8/code/Format21t.java
@@ -54,6 +54,8 @@
public abstract Type getType();
+ protected abstract ValueType getOperandType();
+
@Override
public int[] getTargets() {
return new int[]{BBBB, getSize()};
@@ -63,7 +65,7 @@
public void buildIR(IRBuilder builder) {
int offset = getOffset();
int size = getSize();
- builder.addIfZero(getType(), ValueType.INT_OR_FLOAT_OR_NULL, AA, offset + BBBB, offset + size);
+ builder.addIfZero(getType(), getOperandType(), AA, offset + BBBB, offset + size);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/IfEqz.java b/src/main/java/com/android/tools/r8/code/IfEqz.java
index fc39c31..3e622e6 100644
--- a/src/main/java/com/android/tools/r8/code/IfEqz.java
+++ b/src/main/java/com/android/tools/r8/code/IfEqz.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.code;
import com.android.tools.r8.ir.code.If.Type;
+import com.android.tools.r8.ir.code.ValueType;
public class IfEqz extends Format21t {
@@ -38,4 +39,9 @@
public Type getType() {
return Type.EQ;
}
+
+ @Override
+ protected ValueType getOperandType() {
+ return ValueType.INT_OR_FLOAT_OR_NULL;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/code/IfGez.java b/src/main/java/com/android/tools/r8/code/IfGez.java
index 1fa59ef..bf3fc1c 100644
--- a/src/main/java/com/android/tools/r8/code/IfGez.java
+++ b/src/main/java/com/android/tools/r8/code/IfGez.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.code;
import com.android.tools.r8.ir.code.If.Type;
+import com.android.tools.r8.ir.code.ValueType;
public class IfGez extends Format21t {
@@ -38,4 +39,9 @@
public Type getType() {
return Type.GE;
}
+
+ @Override
+ protected ValueType getOperandType() {
+ return ValueType.INT;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/code/IfGtz.java b/src/main/java/com/android/tools/r8/code/IfGtz.java
index a2807b9..353738e 100644
--- a/src/main/java/com/android/tools/r8/code/IfGtz.java
+++ b/src/main/java/com/android/tools/r8/code/IfGtz.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.code;
import com.android.tools.r8.ir.code.If.Type;
+import com.android.tools.r8.ir.code.ValueType;
public class IfGtz extends Format21t {
@@ -38,4 +39,9 @@
public Type getType() {
return Type.GT;
}
+
+ @Override
+ protected ValueType getOperandType() {
+ return ValueType.INT;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/code/IfLez.java b/src/main/java/com/android/tools/r8/code/IfLez.java
index 405af0a..aa094fe 100644
--- a/src/main/java/com/android/tools/r8/code/IfLez.java
+++ b/src/main/java/com/android/tools/r8/code/IfLez.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.code;
import com.android.tools.r8.ir.code.If.Type;
+import com.android.tools.r8.ir.code.ValueType;
public class IfLez extends Format21t {
@@ -38,4 +39,9 @@
public Type getType() {
return Type.LE;
}
+
+ @Override
+ protected ValueType getOperandType() {
+ return ValueType.INT;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/code/IfLtz.java b/src/main/java/com/android/tools/r8/code/IfLtz.java
index d79b1d2..236b35d 100644
--- a/src/main/java/com/android/tools/r8/code/IfLtz.java
+++ b/src/main/java/com/android/tools/r8/code/IfLtz.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.code;
import com.android.tools.r8.ir.code.If.Type;
+import com.android.tools.r8.ir.code.ValueType;
public class IfLtz extends Format21t {
@@ -38,4 +39,9 @@
public Type getType() {
return Type.LT;
}
+
+ @Override
+ protected ValueType getOperandType() {
+ return ValueType.INT;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/code/IfNez.java b/src/main/java/com/android/tools/r8/code/IfNez.java
index ddf4551..f638f35 100644
--- a/src/main/java/com/android/tools/r8/code/IfNez.java
+++ b/src/main/java/com/android/tools/r8/code/IfNez.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.code;
import com.android.tools.r8.ir.code.If.Type;
+import com.android.tools.r8.ir.code.ValueType;
public class IfNez extends Format21t {
@@ -38,4 +39,9 @@
public Type getType() {
return Type.NE;
}
+
+ @Override
+ protected ValueType getOperandType() {
+ return ValueType.INT_OR_FLOAT_OR_NULL;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/code/Move.java b/src/main/java/com/android/tools/r8/code/Move.java
index 90e44f4..0dc06f9 100644
--- a/src/main/java/com/android/tools/r8/code/Move.java
+++ b/src/main/java/com/android/tools/r8/code/Move.java
@@ -37,6 +37,6 @@
@Override
public void buildIR(IRBuilder builder) {
- builder.addMove(ValueType.INT_OR_FLOAT_OR_NULL, A, B);
+ builder.addMove(ValueType.INT_OR_FLOAT, A, B);
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Move16.java b/src/main/java/com/android/tools/r8/code/Move16.java
index 6772538..966d473 100644
--- a/src/main/java/com/android/tools/r8/code/Move16.java
+++ b/src/main/java/com/android/tools/r8/code/Move16.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRBuilder;
+
public class Move16 extends Format32x {
public static final int OPCODE = 0x3;
@@ -36,6 +37,6 @@
@Override
public void buildIR(IRBuilder builder) {
- builder.addMove(ValueType.INT_OR_FLOAT_OR_NULL, AAAA, BBBB);
+ builder.addMove(ValueType.INT_OR_FLOAT, AAAA, BBBB);
}
}
diff --git a/src/main/java/com/android/tools/r8/code/MoveFrom16.java b/src/main/java/com/android/tools/r8/code/MoveFrom16.java
index a81a8a0..351f60a 100644
--- a/src/main/java/com/android/tools/r8/code/MoveFrom16.java
+++ b/src/main/java/com/android/tools/r8/code/MoveFrom16.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRBuilder;
+
public class MoveFrom16 extends Format22x {
public static final int OPCODE = 0x2;
@@ -36,6 +37,6 @@
@Override
public void buildIR(IRBuilder builder) {
- builder.addMove(ValueType.INT_OR_FLOAT_OR_NULL, AA, BBBB);
+ builder.addMove(ValueType.INT_OR_FLOAT, AA, BBBB);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/constant/ConstLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/constant/ConstLatticeElement.java
index 18b2aca..65cbc0b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/constant/ConstLatticeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/constant/ConstLatticeElement.java
@@ -26,10 +26,6 @@
return Bottom.getInstance();
}
- public int getBranchCondition() {
- return value.getIntValue();
- }
-
@Override
public boolean isConst() {
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java b/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java
index 6c9f075..b4ff421 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java
@@ -179,7 +179,7 @@
if (theIf.isZeroTest()) {
LatticeElement element = getLatticeElement(theIf.inValues().get(0));
if (element.isConst()) {
- BasicBlock target = theIf.targetFromCondition(element.asConst().getBranchCondition());
+ BasicBlock target = theIf.targetFromCondition(element.asConst().getConstNumber());
if (!isExecutableEdge(jumpInstBlockNumber, target.getNumber())) {
setExecutableEdge(jumpInstBlockNumber, target.getNumber());
flowEdges.add(target);
@@ -190,9 +190,9 @@
LatticeElement leftElement = getLatticeElement(theIf.inValues().get(0));
LatticeElement rightElement = getLatticeElement(theIf.inValues().get(1));
if (leftElement.isConst() && rightElement.isConst()) {
- long leftValue = leftElement.asConst().getConstNumber().getIntValue();
- long rightValue = rightElement.asConst().getConstNumber().getIntValue();
- BasicBlock target = theIf.targetFromCondition(leftValue - rightValue);
+ ConstNumber leftNumber = leftElement.asConst().getConstNumber();
+ ConstNumber rightNumber = rightElement.asConst().getConstNumber();
+ BasicBlock target = theIf.targetFromCondition(leftNumber, rightNumber);
if (!isExecutableEdge(jumpInstBlockNumber, target.getNumber())) {
setExecutableEdge(jumpInstBlockNumber, target.getNumber());
flowEdges.add(target);
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index 1ec23d0..a5d3e4a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -376,6 +376,7 @@
for (Phi phi : block.getPhis()) {
assert !phi.isTrivialPhi();
assert phi.getOperands().size() == predecessorCount;
+ assert phi.outType() != ValueType.INT_OR_FLOAT_OR_NULL;
values.add(phi);
for (Value value : phi.getOperands()) {
values.add(value);
@@ -392,6 +393,7 @@
if (outValue != null) {
values.add(outValue);
assert outValue.definition == instruction;
+ assert outValue.outType() != ValueType.INT_OR_FLOAT_OR_NULL;
}
for (Value value : instruction.inValues()) {
values.add(value);
diff --git a/src/main/java/com/android/tools/r8/ir/code/If.java b/src/main/java/com/android/tools/r8/ir/code/If.java
index 2e1609d..266069b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/If.java
+++ b/src/main/java/com/android/tools/r8/ir/code/If.java
@@ -171,7 +171,29 @@
return 0;
}
- public BasicBlock targetFromCondition(long cond) {
+ public BasicBlock targetFromCondition(ConstNumber value) {
+ assert isZeroTest();
+ assert value.outType() == ValueType.INT
+ || (value.outType().isObjectOrSingle() && (type == Type.EQ || type == Type.NE));
+ return targetFromCondition(Long.signum(value.getRawValue()));
+ }
+
+ public BasicBlock targetFromCondition(ConstNumber left, ConstNumber right) {
+ assert !isZeroTest();
+ assert left.outType() == right.outType();
+ assert left.outType() == ValueType.INT
+ || (left.outType().isObjectOrSingle() && (type == Type.EQ || type == Type.NE));
+ return targetFromCondition(Long.signum(left.getRawValue() - right.getRawValue()));
+ }
+
+ public BasicBlock targetFromNonNullObject() {
+ assert isZeroTest();
+ assert inValues.get(0).outType().isObject();
+ return targetFromCondition(1);
+ }
+
+ public BasicBlock targetFromCondition(int cond) {
+ assert Integer.signum(cond) == cond;
switch (type) {
case EQ:
return cond == 0 ? getTrueTarget() : fallthroughBlock();
diff --git a/src/main/java/com/android/tools/r8/ir/code/Phi.java b/src/main/java/com/android/tools/r8/ir/code/Phi.java
index f5fab7d..70a9e11 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Phi.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Phi.java
@@ -65,6 +65,7 @@
EdgeType edgeType = pred.getEdgeType(block);
// Since this read has been delayed we must provide the local info for the value.
Value operand = builder.readRegister(register, type, pred, edgeType, getLocalInfo());
+ operand.constrainType(type);
canBeNull |= operand.canBeNull();
appendOperand(operand);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index 272b565..908e0d9 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -24,6 +24,10 @@
public class Value {
+ public void constrainType(ValueType constraint) {
+ type = type.meet(constraint);
+ }
+
// Lazily allocated internal data for the debug information of locals.
// This is wrapped in a class to avoid multiple pointers in the value structure.
private static class DebugData {
@@ -92,7 +96,7 @@
public static final Value UNDEFINED = new Value(UNDEFINED_NUMBER, ValueType.OBJECT, null);
protected final int number;
- protected final ValueType type;
+ protected ValueType type;
public Instruction definition = null;
private LinkedList<Instruction> users = new LinkedList<>();
private Set<Instruction> uniqueUsers = null;
diff --git a/src/main/java/com/android/tools/r8/ir/code/ValueType.java b/src/main/java/com/android/tools/r8/ir/code/ValueType.java
index bf67e23..e49cac6 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ValueType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ValueType.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.code;
+import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexType;
@@ -48,6 +49,64 @@
&& this != ValueType.INT_OR_FLOAT_OR_NULL;
}
+ public ValueType meet(ValueType other) {
+ if (this == other) {
+ return this;
+ }
+ if (other == INT_OR_FLOAT_OR_NULL) {
+ return other.meet(this);
+ }
+ switch (this) {
+ case OBJECT:
+ {
+ if (other.isObject()) {
+ return this;
+ }
+ break;
+ }
+ case INT:
+ case FLOAT:
+ {
+ if (other.isSingle()) {
+ return this;
+ }
+ break;
+ }
+ case LONG:
+ case DOUBLE:
+ {
+ if (other.isWide()) {
+ return this;
+ }
+ break;
+ }
+ case INT_OR_FLOAT_OR_NULL:
+ {
+ if (other.isObjectOrSingle()) {
+ return other;
+ }
+ break;
+ }
+ case INT_OR_FLOAT:
+ {
+ if (other.isSingle()) {
+ return other;
+ }
+ break;
+ }
+ case LONG_OR_DOUBLE:
+ {
+ if (other.isWide()) {
+ return other;
+ }
+ break;
+ }
+ default:
+ throw new Unreachable("Unexpected value-type in meet: " + this);
+ }
+ throw new CompilationError("Cannot compute meet of types: " + this + " and " + other);
+ }
+
public boolean compatible(ValueType other) {
return isWide() == other.isWide();
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 702218e..9fb873c 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -313,6 +313,9 @@
private int nextBlockNumber = 0;
+ // Flag indicating if the instructions define values with imprecise types.
+ private boolean hasImpreciseInstructionOutValueTypes = false;
+
public IRBuilder(DexEncodedMethod method, AppInfo appInfo,
SourceCode source, InternalOptions options) {
this(method, appInfo, source, options, new ValueNumberGenerator());
@@ -435,20 +438,40 @@
// necessary.
ir.splitCriticalEdges();
- // Clear the code so we don't build multiple times.
- source.clear();
- source = null;
-
for (BasicBlock block : blocks) {
block.deduplicatePhis();
}
ir.removeAllTrivialPhis();
+ if (hasImpreciseTypes()) {
+ TypeConstraintResolver resolver = new TypeConstraintResolver();
+ resolver.resolve(ir);
+ }
+
+ // Clear the code so we don't build multiple times.
+ source.clear();
+ source = null;
+
assert ir.isConsistentSSA();
return ir;
}
+ private boolean hasImpreciseTypes() {
+ if (hasImpreciseInstructionOutValueTypes) {
+ return true;
+ }
+ // TODO(zerny): Consider keeping track of the imprecise phi types during phi construction.
+ for (BasicBlock block : blocks) {
+ for (Phi phi : block.getPhis()) {
+ if (!phi.outType().isPreciseType()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
private boolean insertDebugPositions() {
boolean hasDebugPositions = false;
if (!options.debug) {
@@ -1344,8 +1367,10 @@
}
public void addReturn(ValueType type, int value) {
- Value in = readRegister(value, type);
- addReturn(new Return(in, type));
+ ValueType returnType = ValueType.fromDexType(method.method.proto.returnType);
+ assert returnType.compatible(type);
+ Value in = readRegister(value, returnType);
+ addReturn(new Return(in, returnType));
}
public void addReturn() {
@@ -1630,6 +1655,7 @@
assert !value.hasLocalInfo()
|| value.getDebugLocalEnds() != null
|| source.verifyLocalInScope(value.getLocalInfo());
+ value.constrainType(type);
return value;
}
@@ -1806,6 +1832,7 @@
}
private void addInstruction(Instruction ir, Position position) {
+ hasImpreciseInstructionOutValueTypes |= ir.outValue() != null && !ir.outType().isPreciseType();
ir.setPosition(position);
attachLocalValues(ir);
currentBlock.add(ir);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/TypeConstraintResolver.java b/src/main/java/com/android/tools/r8/ir/conversion/TypeConstraintResolver.java
new file mode 100644
index 0000000..3e693f3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/conversion/TypeConstraintResolver.java
@@ -0,0 +1,119 @@
+// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.conversion;
+
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.If;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.Phi;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.code.ValueType;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Type constraint resolver that ensures that all SSA values have a "precise" type, ie, every value
+ * must be an element of exactly one of: object, int, float, long or double.
+ *
+ * <p>The resolution is a union-find over the SSA values, linking any type with an imprecise type to
+ * a parent value that has either the same imprecise type or a precise one. SSA values are linked if
+ * there type is constrained to be the same. This happens in two places:
+ *
+ * <ul>
+ * <li>For phis, the out value and all operand values must have the same type
+ * <li>For if-{eq,ne} instructions, the input values must have the same type.
+ * </ul>
+ *
+ * <p>All other constraints on types have been computed duing IR construction where every call to
+ * readRegister(ValueType) will constrain the type of the SSA value that the read resolves to.
+ */
+public class TypeConstraintResolver {
+
+ private final Map<Value, Value> unificationParents = new HashMap<>();
+
+ public void resolve(IRCode code) {
+ List<Value> impreciseValues = new ArrayList<>();
+ for (BasicBlock block : code.blocks) {
+ for (Phi phi : block.getPhis()) {
+ if (!phi.outType().isPreciseType()) {
+ impreciseValues.add(phi);
+ }
+ for (Value value : phi.getOperands()) {
+ merge(phi, value);
+ }
+ }
+ for (Instruction instruction : block.getInstructions()) {
+ if (instruction.outValue() != null && !instruction.outType().isPreciseType()) {
+ impreciseValues.add(instruction.outValue());
+ }
+
+ if (instruction.isIf() && instruction.inValues().size() == 2) {
+ If ifInstruction = instruction.asIf();
+ assert !ifInstruction.isZeroTest();
+ If.Type type = ifInstruction.getType();
+ if (type == If.Type.EQ || type == If.Type.NE) {
+ merge(ifInstruction.inValues().get(0), ifInstruction.inValues().get(1));
+ }
+ }
+ }
+ }
+ for (Value value : impreciseValues) {
+ value.constrainType(getPreciseType(value));
+ }
+ }
+
+ private void merge(Value value1, Value value2) {
+ link(canonical(value1), canonical(value2));
+ }
+
+ private ValueType getPreciseType(Value value) {
+ ValueType type = canonical(value).outType();
+ return type != ValueType.INT_OR_FLOAT_OR_NULL ? type : ValueType.INT_OR_FLOAT;
+ }
+
+ private void link(Value canonical1, Value canonical2) {
+ if (canonical1 == canonical2) {
+ return;
+ }
+ ValueType type1 = canonical1.outType();
+ ValueType type2 = canonical2.outType();
+ if (type1.isPreciseType() && type2.isPreciseType()) {
+ if (type1 != type2) {
+ throw new CompilationError(
+ "Cannot unify types for values "
+ + canonical1
+ + ":"
+ + type1
+ + " and "
+ + canonical2
+ + ":"
+ + type2);
+ }
+ return;
+ }
+ if (type1.isPreciseType()) {
+ unificationParents.put(canonical2, canonical1);
+ } else {
+ unificationParents.put(canonical1, canonical2);
+ }
+ }
+
+ // Find root with path-compression.
+ private Value canonical(Value value) {
+ Value parent = value;
+ while (parent != null) {
+ Value grandparent = unificationParents.get(parent);
+ if (grandparent != null) {
+ unificationParents.put(value, grandparent);
+ }
+ value = parent;
+ parent = grandparent;
+ }
+ return value;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index e5c8962..692ac48 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -2161,12 +2161,14 @@
&& (theIf.isZeroTest() || inValues.get(1).isConstNumber())) {
// Zero test with a constant of comparison between between two constants.
if (theIf.isZeroTest()) {
- int cond = inValues.get(0).getConstInstruction().asConstNumber().getIntValue();
- simplifyIfWithKnownCondition(code, block, theIf, cond);
+ ConstNumber cond = inValues.get(0).getConstInstruction().asConstNumber();
+ BasicBlock target = theIf.targetFromCondition(cond);
+ simplifyIfWithKnownCondition(code, block, theIf, target);
} else {
- long left = (long) inValues.get(0).getConstInstruction().asConstNumber().getIntValue();
- long right = (long) inValues.get(1).getConstInstruction().asConstNumber().getIntValue();
- simplifyIfWithKnownCondition(code, block, theIf, Long.signum(left - right));
+ ConstNumber left = inValues.get(0).getConstInstruction().asConstNumber();
+ ConstNumber right = inValues.get(1).getConstInstruction().asConstNumber();
+ BasicBlock target = theIf.targetFromCondition(left, right);
+ simplifyIfWithKnownCondition(code, block, theIf, target);
}
} else if (inValues.get(0).hasValueRange()
&& (theIf.isZeroTest() || inValues.get(1).hasValueRange())) {
@@ -2193,7 +2195,6 @@
// TODO(b/72693244): annotate type lattice to value
TypeLatticeElement l = typeEnvironment.getLatticeElement(inValues.get(0));
if (!l.isPrimitive() && !l.isNullable()) {
- // Any non-zero value should work.
simplifyIfWithKnownCondition(code, block, theIf, 1);
}
}
@@ -2204,13 +2205,17 @@
assert code.isConsistentSSA();
}
- private void simplifyIfWithKnownCondition(IRCode code, BasicBlock block, If theIf, int cond) {
- BasicBlock target = theIf.targetFromCondition(cond);
+ private void simplifyIfWithKnownCondition(
+ IRCode code, BasicBlock block, If theIf, BasicBlock target) {
BasicBlock deadTarget =
target == theIf.getTrueTarget() ? theIf.fallthroughBlock() : theIf.getTrueTarget();
rewriteIfToGoto(code, block, theIf, target, deadTarget);
}
+ private void simplifyIfWithKnownCondition(IRCode code, BasicBlock block, If theIf, int cond) {
+ simplifyIfWithKnownCondition(code, block, theIf, theIf.targetFromCondition(cond));
+ }
+
// Find all method invocations that never returns normally, split the block
// after each such invoke instruction and follow it with a block throwing a
// null value (which should result in NPE). Note that this throw is not
@@ -2434,15 +2439,13 @@
Value rightValue = inValues.get(1);
if (leftValue.isConstNumber() || rightValue.isConstNumber()) {
if (leftValue.isConstNumber()) {
- int left = leftValue.getConstInstruction().asConstNumber().getIntValue();
- if (left == 0) {
+ if (leftValue.getConstInstruction().asConstNumber().isZero()) {
If ifz = new If(theIf.getType().forSwappedOperands(), rightValue);
block.replaceLastInstruction(ifz);
assert block.exit() == ifz;
}
} else {
- int right = rightValue.getConstInstruction().asConstNumber().getIntValue();
- if (right == 0) {
+ if (rightValue.getConstInstruction().asConstNumber().isZero()) {
If ifz = new If(theIf.getType(), leftValue);
block.replaceLastInstruction(ifz);
assert block.exit() == ifz;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
index 1a4b97d..94d4290 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
@@ -183,9 +183,9 @@
// ...
If theIf = block.exit().asIf();
Value knownToBeNonNullValue = theIf.inValues().get(0);
- // Avoid adding redundant non-null instruction.
- if (!knownToBeNonNullValue.isNeverNull()) {
- BasicBlock target = theIf.targetFromCondition(1L);
+ // Avoid adding redundant non-null instruction (or non-null of non-object types).
+ if (knownToBeNonNullValue.outType().isObject() && !knownToBeNonNullValue.isNeverNull()) {
+ BasicBlock target = theIf.targetFromNonNullObject();
// Ignore uncommon empty blocks.
if (!target.isEmpty()) {
DominatorTree dominatorTree = new DominatorTree(code);
diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
index b12eb2d..9c8193c 100644
--- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java
@@ -863,8 +863,24 @@
.put("121-modifiers", TestCondition.match(TestCondition.tools(DexTool.NONE)))
// This test uses register r1 in method that is declared to only use 1 register (r0).
.put("142-classloader2", TestCondition.match(TestCondition.R8DEX_COMPILER))
+ // Test with invalid register usage: invoke-static {v2,v2,v2} f(LIF)V
+ .put("457-regs", TestCondition.match(TestCondition.R8DEX_COMPILER))
// This test uses an uninitialized register.
.put("471-uninitialized-locals", TestCondition.match(TestCondition.R8DEX_COMPILER))
+ // Test which mixes int and float registers.
+ .put("459-dead-phi", TestCondition.match(TestCondition.R8DEX_COMPILER))
+ // Test for verification error: contains an aput-object with an single-valued input.
+ .put("506-verify-aput", TestCondition.match(TestCondition.R8DEX_COMPILER))
+ // Test with invalid register usage: returns a register of either long or double.
+ .put("510-checker-try-catch", TestCondition.match(TestCondition.R8DEX_COMPILER))
+ // Test with invalid register usage: contains an int-to-byte on the result of aget-object.
+ .put("518-null-array-get", TestCondition.match(TestCondition.R8DEX_COMPILER))
+ // Test with invalid register usage: phi of int and float.
+ .put("535-regression-const-val", TestCondition.match(TestCondition.R8DEX_COMPILER))
+ // Test with invalid register usage: phi of int and float.
+ .put("552-checker-primitive-typeprop", TestCondition.match(TestCondition.R8DEX_COMPILER))
+ // Test with invalid register usage: invoke-static {v0,v0}, foo(IL)V
+ .put("557-checker-ref-equivalent", TestCondition.match(TestCondition.R8DEX_COMPILER))
// This test is starting from invalid dex code. It splits up a double value and uses
// the first register of a double with the second register of another double.
.put("800-smali", TestCondition.match(TestCondition.R8DEX_COMPILER))
diff --git a/src/test/java/com/android/tools/r8/rewrite/switches/SwitchRewritingTest.java b/src/test/java/com/android/tools/r8/rewrite/switches/SwitchRewritingTest.java
index 3d921b6..2073ab9 100644
--- a/src/test/java/com/android/tools/r8/rewrite/switches/SwitchRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/switches/SwitchRewritingTest.java
@@ -152,7 +152,8 @@
assertTrue(code.instructions[0] instanceof PackedSwitch);
} else {
if (key1 == 0) {
- assertTrue(code.instructions[0] instanceof IfEqz);
+ // Const instruction may be before if.
+ assertTrue(code.instructions[0] instanceof IfEqz || code.instructions[1] instanceof IfEqz);
} else {
// Const instruction before if.
assertTrue(code.instructions[1] instanceof IfEq);