Extend simple inlining constraint to const number arguments
Fixes: 176067541
Change-Id: I07cd7aa31d8133b88517b5f1ef40b8efc3f01bf7
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java
index a164607..93cdb16 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java
@@ -36,7 +36,8 @@
}
@Override
- public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
+ public SimpleInliningConstraint rewrittenWithUnboxedArguments(
+ IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
return this;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanFalseSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanFalseSimpleInliningConstraint.java
index 351d51d..2c88a60 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanFalseSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanFalseSimpleInliningConstraint.java
@@ -41,7 +41,8 @@
}
@Override
- public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
+ public SimpleInliningConstraint rewrittenWithUnboxedArguments(
+ IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
return this;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanTrueSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanTrueSimpleInliningConstraint.java
index bf3fde3..46c29b0 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanTrueSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanTrueSimpleInliningConstraint.java
@@ -41,7 +41,8 @@
}
@Override
- public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
+ public SimpleInliningConstraint rewrittenWithUnboxedArguments(
+ IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
return this;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/EqualToNumberSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/EqualToNumberSimpleInliningConstraint.java
new file mode 100644
index 0000000..a321670
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/EqualToNumberSimpleInliningConstraint.java
@@ -0,0 +1,46 @@
+// Copyright (c) 2021, 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.analysis.inlining;
+
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.Value;
+import it.unimi.dsi.fastutil.ints.IntList;
+
+public class EqualToNumberSimpleInliningConstraint extends SimpleInliningArgumentConstraint {
+
+ private final long rawValue;
+
+ private EqualToNumberSimpleInliningConstraint(int argumentIndex, long rawValue) {
+ super(argumentIndex);
+ this.rawValue = rawValue;
+ }
+
+ static EqualToNumberSimpleInliningConstraint create(
+ int argumentIndex, long rawValue, SimpleInliningConstraintFactory witness) {
+ assert witness != null;
+ return new EqualToNumberSimpleInliningConstraint(argumentIndex, rawValue);
+ }
+
+ @Override
+ public boolean isSatisfied(InvokeMethod invoke) {
+ Value argumentRoot = getArgument(invoke).getAliasedValue();
+ return argumentRoot.isDefinedByInstructionSatisfying(Instruction::isConstNumber)
+ && argumentRoot.getDefinition().asConstNumber().getRawValue() == rawValue;
+ }
+
+ @Override
+ public SimpleInliningConstraint fixupAfterRemovingThisParameter(
+ SimpleInliningConstraintFactory factory) {
+ assert getArgumentIndex() > 0;
+ return factory.createNumberConstraint(getArgumentIndex() - 1, rawValue);
+ }
+
+ @Override
+ public SimpleInliningConstraint rewrittenWithUnboxedArguments(
+ IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
+ return this;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java
index 4568e5f..809dbb9 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java
@@ -35,7 +35,8 @@
}
@Override
- public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
+ public SimpleInliningConstraint rewrittenWithUnboxedArguments(
+ IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
return this;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NotEqualToNumberSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NotEqualToNumberSimpleInliningConstraint.java
new file mode 100644
index 0000000..4739231
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NotEqualToNumberSimpleInliningConstraint.java
@@ -0,0 +1,46 @@
+// Copyright (c) 2021, 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.analysis.inlining;
+
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.Value;
+import it.unimi.dsi.fastutil.ints.IntList;
+
+public class NotEqualToNumberSimpleInliningConstraint extends SimpleInliningArgumentConstraint {
+
+ private final long rawValue;
+
+ private NotEqualToNumberSimpleInliningConstraint(int argumentIndex, long rawValue) {
+ super(argumentIndex);
+ this.rawValue = rawValue;
+ }
+
+ static NotEqualToNumberSimpleInliningConstraint create(
+ int argumentIndex, long rawValue, SimpleInliningConstraintFactory witness) {
+ assert witness != null;
+ return new NotEqualToNumberSimpleInliningConstraint(argumentIndex, rawValue);
+ }
+
+ @Override
+ public boolean isSatisfied(InvokeMethod invoke) {
+ Value argumentRoot = getArgument(invoke).getAliasedValue();
+ return argumentRoot.isDefinedByInstructionSatisfying(Instruction::isConstNumber)
+ && argumentRoot.getDefinition().asConstNumber().getRawValue() != rawValue;
+ }
+
+ @Override
+ public SimpleInliningConstraint fixupAfterRemovingThisParameter(
+ SimpleInliningConstraintFactory factory) {
+ assert getArgumentIndex() > 0;
+ return factory.createNotNumberConstraint(getArgumentIndex() - 1, rawValue);
+ }
+
+ @Override
+ public SimpleInliningConstraint rewrittenWithUnboxedArguments(
+ IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
+ return this;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NotNullSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NotNullSimpleInliningConstraint.java
index 0834cba..00288f8 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NotNullSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NotNullSimpleInliningConstraint.java
@@ -41,10 +41,10 @@
}
@Override
- public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
+ public SimpleInliningConstraint rewrittenWithUnboxedArguments(
+ IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
if (unboxedArgumentIndices.contains(getArgumentIndex())) {
- // TODO(b/176067541): Could be refined to an argument-equals-int constraint.
- return NeverSimpleInliningConstraint.getInstance();
+ return factory.createNotNumberConstraint(getArgumentIndex(), 0);
}
return this;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java
index 19607ee..5a0d3cf 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java
@@ -45,10 +45,10 @@
}
@Override
- public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
+ public SimpleInliningConstraint rewrittenWithUnboxedArguments(
+ IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
if (unboxedArgumentIndices.contains(getArgumentIndex())) {
- // TODO(b/176067541): Could be refined to an argument-equals-int constraint.
- return NeverSimpleInliningConstraint.getInstance();
+ return factory.createNumberConstraint(getArgumentIndex(), 0);
}
return this;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java
index df108ac..82c3f7d 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java
@@ -110,5 +110,5 @@
SimpleInliningConstraintFactory factory);
public abstract SimpleInliningConstraint rewrittenWithUnboxedArguments(
- IntList unboxedArgumentIndices);
+ IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory);
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintAnalysis.java
index 1a7e997..6d79b82 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintAnalysis.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.Sets;
+import java.util.OptionalLong;
import java.util.Set;
/**
@@ -105,43 +106,46 @@
switch (instruction.opcode()) {
case IF:
If ifInstruction = instruction.asIf();
- if (ifInstruction.isZeroTest()) {
- Value lhs = ifInstruction.lhs().getAliasedValue();
- if (lhs.isArgument() && !lhs.isThis()) {
- int argumentIndex = lhs.getDefinition().asArgument().getIndex();
- DexType argumentType = method.getDefinition().getArgumentType(argumentIndex);
- int currentDepth = instructionDepth;
-
- // Compute the constraint for which paths through the true target are guaranteed to exit
- // early.
- SimpleInliningConstraint trueTargetConstraint =
- computeConstraintFromIfZeroTest(
- argumentIndex, argumentType, ifInstruction.getType())
- // Only recurse into the true target if the constraint from the if-instruction
- // is not 'never'.
- .lazyMeet(
- () ->
- analyzeInstructionsInBlock(
- ifInstruction.getTrueTarget(), currentDepth));
-
- // Compute the constraint for which paths through the false target are guaranteed to
- // exit early.
- SimpleInliningConstraint fallthroughTargetConstraint =
- computeConstraintFromIfZeroTest(
- argumentIndex, argumentType, ifInstruction.getType().inverted())
- // Only recurse into the false target if the constraint from the if-instruction
- // is not 'never'.
- .lazyMeet(
- () ->
- analyzeInstructionsInBlock(
- ifInstruction.fallthroughBlock(), currentDepth));
-
- // Paths going through this basic block are guaranteed to exit early if the true target
- // is guaranteed to exit early or the false target is.
- return trueTargetConstraint.join(fallthroughTargetConstraint);
- }
+ Value singleArgumentOperand = getSingleArgumentOperand(ifInstruction);
+ if (singleArgumentOperand == null || singleArgumentOperand.isThis()) {
+ break;
}
- break;
+
+ Value otherOperand =
+ ifInstruction.isZeroTest()
+ ? null
+ : ifInstruction.getOperand(
+ 1 - ifInstruction.inValues().indexOf(singleArgumentOperand));
+
+ int argumentIndex =
+ singleArgumentOperand.getAliasedValue().getDefinition().asArgument().getIndex();
+ DexType argumentType = method.getDefinition().getArgumentType(argumentIndex);
+ int currentDepth = instructionDepth;
+
+ // Compute the constraint for which paths through the true target are guaranteed to exit
+ // early.
+ SimpleInliningConstraint trueTargetConstraint =
+ computeConstraintFromIfTest(
+ argumentIndex, argumentType, otherOperand, ifInstruction.getType())
+ // Only recurse into the true target if the constraint from the if-instruction
+ // is not 'never'.
+ .lazyMeet(
+ () -> analyzeInstructionsInBlock(ifInstruction.getTrueTarget(), currentDepth));
+
+ // Compute the constraint for which paths through the false target are guaranteed to
+ // exit early.
+ SimpleInliningConstraint fallthroughTargetConstraint =
+ computeConstraintFromIfTest(
+ argumentIndex, argumentType, otherOperand, ifInstruction.getType().inverted())
+ // Only recurse into the false target if the constraint from the if-instruction
+ // is not 'never'.
+ .lazyMeet(
+ () ->
+ analyzeInstructionsInBlock(ifInstruction.fallthroughBlock(), currentDepth));
+
+ // Paths going through this basic block are guaranteed to exit early if the true target
+ // is guaranteed to exit early or the false target is.
+ return trueTargetConstraint.join(fallthroughTargetConstraint);
case GOTO:
return analyzeInstructionsInBlock(instruction.asGoto().getTarget(), instructionDepth);
@@ -162,24 +166,39 @@
return NeverSimpleInliningConstraint.getInstance();
}
- private SimpleInliningConstraint computeConstraintFromIfZeroTest(
- int argumentIndex, DexType argumentType, If.Type type) {
+ private SimpleInliningConstraint computeConstraintFromIfTest(
+ int argumentIndex, DexType argumentType, Value otherOperand, If.Type type) {
+ boolean isZeroTest = otherOperand == null;
switch (type) {
case EQ:
- if (argumentType.isReferenceType()) {
- return factory.createNullConstraint(argumentIndex);
- }
- if (argumentType.isBooleanType()) {
- return factory.createBooleanFalseConstraint(argumentIndex);
+ if (isZeroTest) {
+ if (argumentType.isReferenceType()) {
+ return factory.createNullConstraint(argumentIndex);
+ }
+ if (argumentType.isBooleanType()) {
+ return factory.createBooleanFalseConstraint(argumentIndex);
+ }
+ } else if (argumentType.isPrimitiveType()) {
+ OptionalLong rawValue = getRawNumberValue(otherOperand);
+ if (rawValue.isPresent()) {
+ return factory.createNumberConstraint(argumentIndex, rawValue.getAsLong());
+ }
}
return NeverSimpleInliningConstraint.getInstance();
case NE:
- if (argumentType.isReferenceType()) {
- return factory.createNotNullConstraint(argumentIndex);
- }
- if (argumentType.isBooleanType()) {
- return factory.createBooleanTrueConstraint(argumentIndex);
+ if (isZeroTest) {
+ if (argumentType.isReferenceType()) {
+ return factory.createNotNullConstraint(argumentIndex);
+ }
+ if (argumentType.isBooleanType()) {
+ return factory.createBooleanTrueConstraint(argumentIndex);
+ }
+ } else if (argumentType.isPrimitiveType()) {
+ OptionalLong rawValue = getRawNumberValue(otherOperand);
+ if (rawValue.isPresent()) {
+ return factory.createNotNumberConstraint(argumentIndex, rawValue.getAsLong());
+ }
}
return NeverSimpleInliningConstraint.getInstance();
@@ -187,4 +206,33 @@
return NeverSimpleInliningConstraint.getInstance();
}
}
+
+ private OptionalLong getRawNumberValue(Value value) {
+ Value root = value.getAliasedValue();
+ if (root.isDefinedByInstructionSatisfying(Instruction::isConstNumber)) {
+ return OptionalLong.of(root.getDefinition().asConstNumber().getRawValue());
+ }
+ return OptionalLong.empty();
+ }
+
+ private Value getSingleArgumentOperand(If ifInstruction) {
+ Value singleArgumentOperand = null;
+
+ Value lhs = ifInstruction.lhs();
+ if (lhs.getAliasedValue().isArgument()) {
+ singleArgumentOperand = lhs;
+ }
+
+ if (!ifInstruction.isZeroTest()) {
+ Value rhs = ifInstruction.rhs();
+ if (rhs.getAliasedValue().isArgument()) {
+ if (singleArgumentOperand != null) {
+ return null;
+ }
+ singleArgumentOperand = rhs;
+ }
+ }
+
+ return singleArgumentOperand;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java
index c993b12..ae2e07b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java
@@ -77,11 +77,12 @@
}
@Override
- public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
+ public SimpleInliningConstraint rewrittenWithUnboxedArguments(
+ IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
List<SimpleInliningConstraint> rewrittenConstraints =
ListUtils.mapOrElse(
constraints,
- constraint -> constraint.rewrittenWithUnboxedArguments(unboxedArgumentIndices),
+ constraint -> constraint.rewrittenWithUnboxedArguments(unboxedArgumentIndices, factory),
null);
return rewrittenConstraints != null
? new SimpleInliningConstraintConjunction(rewrittenConstraints)
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java
index a6b418d..42bcaf6 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java
@@ -77,11 +77,12 @@
}
@Override
- public SimpleInliningConstraint rewrittenWithUnboxedArguments(IntList unboxedArgumentIndices) {
+ public SimpleInliningConstraint rewrittenWithUnboxedArguments(
+ IntList unboxedArgumentIndices, SimpleInliningConstraintFactory factory) {
List<SimpleInliningConstraint> rewrittenConstraints =
ListUtils.mapOrElse(
constraints,
- constraint -> constraint.rewrittenWithUnboxedArguments(unboxedArgumentIndices),
+ constraint -> constraint.rewrittenWithUnboxedArguments(unboxedArgumentIndices, factory),
null);
return rewrittenConstraints != null
? new SimpleInliningConstraintDisjunction(rewrittenConstraints)
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintFactory.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintFactory.java
index 99603e8..ed3cd55 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintFactory.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintFactory.java
@@ -77,6 +77,16 @@
() -> NullSimpleInliningConstraint.create(argumentIndex, this));
}
+ public NotEqualToNumberSimpleInliningConstraint createNotNumberConstraint(
+ int argumentIndex, long rawValue) {
+ return NotEqualToNumberSimpleInliningConstraint.create(argumentIndex, rawValue, this);
+ }
+
+ public EqualToNumberSimpleInliningConstraint createNumberConstraint(
+ int argumentIndex, long rawValue) {
+ return EqualToNumberSimpleInliningConstraint.create(argumentIndex, rawValue, this);
+ }
+
private <T extends SimpleInliningArgumentConstraint> T createArgumentConstraint(
int argumentIndex, T[] lowConstraints, Map<Integer, T> highConstraints, Supplier<T> fn) {
return argumentIndex < lowConstraints.length
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index 3ac5e73b..5517fb8 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -98,6 +98,10 @@
return position == null ? "???" : position.toString();
}
+ public Value getOperand(int index) {
+ return inValues().get(index);
+ }
+
public List<Value> inValues() {
return inValues;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
index fe45c93..b11c440 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
@@ -411,7 +411,8 @@
return method
.getOptimizationInfo()
.getSimpleInliningConstraint()
- .rewrittenWithUnboxedArguments(unboxedArgumentIndices);
+ .rewrittenWithUnboxedArguments(
+ unboxedArgumentIndices, appView.simpleInliningConstraintFactory());
}
private DexMethod ensureUniqueMethod(DexEncodedMethod encodedMethod, DexMethod newMethod) {