Lens code rewriting for Argument instructions
Change-Id: Idd84efbe168e13c959d068e38dbda034bfacd0a3
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 c3fd49f..5f318cd 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
@@ -120,9 +120,7 @@
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.code.ValueTypeConstraint;
import com.android.tools.r8.ir.code.Xor;
-import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
-import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagatorIROptimizer;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.Pair;
@@ -748,26 +746,6 @@
new TypeAnalysis(appView).narrowing(ir);
}
- // Update the IR code if collected call site optimization info has something useful.
- // While aggregation of parameter information at call sites would be more precise than static
- // types, those could be still less precise at one single call site, where specific arguments
- // will be passed during (double) inlining. Instead of adding assumptions and removing invalid
- // ones, it's better not to insert assumptions for inlinee in the beginning.
- CallSiteOptimizationInfo callSiteOptimizationInfo =
- getMethod().getOptimizationInfo().getArgumentInfos();
- if (callSiteOptimizationInfo.isConcreteCallSiteOptimizationInfo() && method == context) {
- // TODO(b/190154391): Consider pruning all argument information from the optimization info
- // after the second optimization pass. That way we save memory and can assert here that
- // !appView.hasLiveness() (which currently may happen due to the reflective behavior
- // handling in the final round of tree shaking).
- if (appView.hasLiveness()) {
- ArgumentPropagatorIROptimizer.optimize(
- appView.withLiveness(),
- ir,
- callSiteOptimizationInfo.asConcreteCallSiteOptimizationInfo());
- }
- }
-
if (appView.options().isStringSwitchConversionEnabled()) {
StringSwitchConverter.convertToStringSwitchInstructions(ir, appView.dexItemFactory());
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index c30c8b6..c4dba5e 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -81,6 +81,7 @@
import com.android.tools.r8.ir.optimize.classinliner.ClassInliner;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxer;
import com.android.tools.r8.ir.optimize.enums.EnumValueOptimizer;
+import com.android.tools.r8.ir.optimize.info.CallSiteOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoCollector;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
@@ -96,6 +97,7 @@
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.naming.IdentifierNameStringMarker;
import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
+import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagatorIROptimizer;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.KeepMethodInfo;
@@ -1213,6 +1215,20 @@
previous = printMethod(code, "IR after disable assertions (SSA)", previous);
+ // Update the IR code if collected call site optimization info has something useful.
+ // While aggregation of parameter information at call sites would be more precise than static
+ // types, those could be still less precise at one single call site, where specific arguments
+ // will be passed during (double) inlining. Instead of adding assumptions and removing invalid
+ // ones, it's better not to insert assumptions for inlinee in the beginning.
+ CallSiteOptimizationInfo callSiteOptimizationInfo =
+ context.getOptimizationInfo().getArgumentInfos();
+ if (callSiteOptimizationInfo.isConcreteCallSiteOptimizationInfo() && appView.hasLiveness()) {
+ ArgumentPropagatorIROptimizer.optimize(
+ appView.withLiveness(),
+ code,
+ callSiteOptimizationInfo.asConcreteCallSiteOptimizationInfo());
+ }
+
if (assumeInserter != null) {
assumeInserter.insertAssumeInstructions(code, timing);
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index 3dc74b2..31f99e5 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.graph.UseRegistry.MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY;
import static com.android.tools.r8.ir.code.Invoke.Type.STATIC;
import static com.android.tools.r8.ir.code.Invoke.Type.VIRTUAL;
+import static com.android.tools.r8.ir.code.Opcodes.ARGUMENT;
import static com.android.tools.r8.ir.code.Opcodes.ASSUME;
import static com.android.tools.r8.ir.code.Opcodes.CHECK_CAST;
import static com.android.tools.r8.ir.code.Opcodes.CONST_CLASS;
@@ -60,7 +61,7 @@
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.SingleNumberValue;
-import com.android.tools.r8.ir.code.Assume;
+import com.android.tools.r8.ir.code.Argument;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.BasicBlockIterator;
import com.android.tools.r8.ir.code.CatchHandlers;
@@ -685,49 +686,30 @@
}
break;
- case ASSUME:
+ case ARGUMENT:
{
- // TODO(b/174543992): It's not clear we should rewrite the assumes here. The code
- // present fixes the problem for enum unboxing, but not for lambda merging.
- // The LensCodeRewriter is run before most assume instructions are inserted, however,
- // the call site optimization may propagate assumptions at IR building time, and such
- // assumes are already present.
- // R8 clears the assumes if the type is rewritten to a primitive type.
- Assume assume = current.asAssume();
- if (assume.hasOutValue()) {
- TypeElement type = assume.getOutType();
- TypeElement substituted = type.rewrittenWithLens(appView, graphLens);
- if (substituted != type) {
- assert type.isArrayType() || type.isClassType();
- affectedPhis.addAll(assume.outValue().uniquePhiUsers());
- if (substituted.isPrimitiveType()) {
- assert type.isClassType();
- assert appView.unboxedEnums().isUnboxedEnum(type.asClassType().getClassType());
- // Any assumption of a class type being converted to a primitive type is
- // invalid. Dynamic type is irrelevant and non null is incorrect.
- assume.outValue().replaceUsers(assume.src());
- iterator.removeOrReplaceByDebugLocalRead();
- } else if (substituted.isPrimitiveArrayType()) {
- assert type.isArrayType();
- // Non-null assumptions on a class array type being converted to a primitive
- // array type remains, but dynamic type becomes irrelevant.
- assume.unsetDynamicTypeAssumption();
- if (assume.hasNonNullAssumption()) {
- assume.outValue().setType(substituted);
- } else {
- assume.outValue().replaceUsers(assume.src());
- iterator.removeOrReplaceByDebugLocalRead();
- }
- } else {
- assert !substituted.isPrimitiveType();
- assert !substituted.isPrimitiveArrayType();
- current.outValue().setType(substituted);
- }
- }
+ Argument argument = current.asArgument();
+ TypeElement currentArgumentType = argument.getOutType();
+ TypeElement newArgumentType =
+ method
+ .getArgumentType(argument.getIndex())
+ .toTypeElement(appView, currentArgumentType.nullability());
+ if (!newArgumentType.equals(currentArgumentType)) {
+ affectedPhis.addAll(argument.outValue().uniquePhiUsers());
+ iterator.replaceCurrentInstruction(
+ Argument.builder()
+ .setIndex(argument.getIndex())
+ .setFreshOutValue(code, newArgumentType)
+ .setPosition(argument)
+ .build());
}
}
break;
+ case ASSUME:
+ assert false;
+ break;
+
default:
if (current.hasOutValue()) {
// For all other instructions, substitute any changed type.
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveInterfaceBridgeWithSubTypeTest.java b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveInterfaceBridgeWithSubTypeTest.java
index f1fc86d..25674a2 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveInterfaceBridgeWithSubTypeTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingRemoveInterfaceBridgeWithSubTypeTest.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.NoParameterTypeStrengthening;
import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -51,6 +52,7 @@
.addKeepClassAndMembersRules(I.class)
.enableInliningAnnotations()
.enableNoHorizontalClassMergingAnnotations()
+ .enableNoParameterTypeStrengtheningAnnotations()
.enableNoVerticalClassMergingAnnotations()
.addHorizontallyMergedClassesInspector(
HorizontallyMergedClassesInspector::assertNoClassesMerged)
@@ -94,6 +96,7 @@
}
@NeverInline
+ @NoParameterTypeStrengthening
private static void callJ(A a) {
a.foo();
}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfPackagePrivateMethodsTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfPackagePrivateMethodsTest.java
index 951a2b6..4eff919 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfPackagePrivateMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfPackagePrivateMethodsTest.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoParameterTypeStrengthening;
import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -31,6 +32,7 @@
.apply(this::configureRepackaging)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
+ .enableNoParameterTypeStrengtheningAnnotations()
.enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
@@ -52,11 +54,13 @@
}
@NeverInline
+ @NoParameterTypeStrengthening
static void greet(HelloGreeterBase greeter) {
greeter.greet();
}
@NeverInline
+ @NoParameterTypeStrengthening
static void greet(WorldGreeterBase greeter) {
greeter.greet();
}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfProtectedMethodsTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfProtectedMethodsTest.java
index 7747cbd..56f6a41 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfProtectedMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithOverridesOfProtectedMethodsTest.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoParameterTypeStrengthening;
import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -31,6 +32,7 @@
.apply(this::configureRepackaging)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
+ .enableNoParameterTypeStrengtheningAnnotations()
.enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
@@ -52,11 +54,13 @@
}
@NeverInline
+ @NoParameterTypeStrengthening
static void greet(HelloGreeterBase greeter) {
greeter.greet();
}
@NeverInline
+ @NoParameterTypeStrengthening
static void greet(WorldGreeterBase greeter) {
greeter.greet();
}