Add new @NoRedundantFieldLoadElimination testing annotation
Change-Id: I1d7bf5601ede3e4dfd28720c5360c92d14ff9bba
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
index 178c021..09fa213 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
@@ -648,8 +648,10 @@
FieldAndObject fieldAndObject = new FieldAndObject(field.getReference(), object);
FieldValue replacement = activeState.getInstanceFieldValue(fieldAndObject);
if (replacement != null) {
- markAssumeDynamicTypeUsersForRemoval(instanceGet, replacement, assumeRemover);
- replacement.eliminateRedundantRead(it, instanceGet);
+ if (isRedundantFieldLoadEliminationAllowed(field)) {
+ markAssumeDynamicTypeUsersForRemoval(instanceGet, replacement, assumeRemover);
+ replacement.eliminateRedundantRead(it, instanceGet);
+ }
return;
}
@@ -658,6 +660,15 @@
clearMostRecentInstanceFieldWrite(instanceGet, field);
}
+ private boolean isRedundantFieldLoadEliminationAllowed(DexClassAndField field) {
+ // Always allowed in D8 since D8 does not support @NoRedundantFieldLoadElimination.
+ return !appView.enableWholeProgramOptimizations()
+ || !field.isProgramField()
+ || appView
+ .getKeepInfo(field.asProgramField())
+ .isRedundantFieldLoadEliminationAllowed(appView.options());
+ }
+
private void handleNewInstance(NewInstance newInstance) {
markClassAsInitialized(newInstance.getType());
markMostRecentInitClassForRemoval(newInstance.getType());
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepFieldInfo.java b/src/main/java/com/android/tools/r8/shaking/KeepFieldInfo.java
index 312b61e..db53845 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepFieldInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepFieldInfo.java
@@ -25,10 +25,12 @@
}
private final boolean allowFieldTypeStrengthening;
+ private final boolean allowRedundantFieldLoadElimination;
private KeepFieldInfo(Builder builder) {
super(builder);
this.allowFieldTypeStrengthening = builder.isFieldTypeStrengtheningAllowed();
+ this.allowRedundantFieldLoadElimination = builder.isRedundantFieldLoadEliminationAllowed();
}
// This builder is not private as there are known instances where it is safe to modify keep info
@@ -46,6 +48,14 @@
return allowFieldTypeStrengthening;
}
+ public boolean isRedundantFieldLoadEliminationAllowed(GlobalKeepInfoConfiguration configuration) {
+ return internalIsRedundantFieldLoadEliminationAllowed();
+ }
+
+ boolean internalIsRedundantFieldLoadEliminationAllowed() {
+ return allowRedundantFieldLoadElimination;
+ }
+
public Joiner joiner() {
assert !isTop();
return new Joiner(this);
@@ -64,6 +74,7 @@
public static class Builder extends KeepInfo.Builder<Builder, KeepFieldInfo> {
private boolean allowFieldTypeStrengthening;
+ private boolean allowRedundantFieldLoadElimination;
private Builder() {
super();
@@ -72,16 +83,20 @@
private Builder(KeepFieldInfo original) {
super(original);
allowFieldTypeStrengthening = original.internalIsFieldTypeStrengtheningAllowed();
+ allowRedundantFieldLoadElimination =
+ original.internalIsRedundantFieldLoadEliminationAllowed();
}
@Override
public Builder makeTop() {
- return super.makeTop().disallowFieldTypeStrengthening();
+ return super.makeTop()
+ .disallowFieldTypeStrengthening()
+ .disallowRedundantFieldLoadElimination();
}
@Override
public Builder makeBottom() {
- return super.makeBottom().allowFieldTypeStrengthening();
+ return super.makeBottom().allowFieldTypeStrengthening().allowRedundantFieldLoadElimination();
}
public boolean isFieldTypeStrengtheningAllowed() {
@@ -101,6 +116,24 @@
return setAllowFieldTypeStrengthening(false);
}
+ public boolean isRedundantFieldLoadEliminationAllowed() {
+ return allowRedundantFieldLoadElimination;
+ }
+
+ public Builder setAllowRedundantFieldLoadElimination(
+ boolean allowRedundantFieldLoadElimination) {
+ this.allowRedundantFieldLoadElimination = allowRedundantFieldLoadElimination;
+ return self();
+ }
+
+ public Builder allowRedundantFieldLoadElimination() {
+ return setAllowRedundantFieldLoadElimination(true);
+ }
+
+ public Builder disallowRedundantFieldLoadElimination() {
+ return setAllowRedundantFieldLoadElimination(false);
+ }
+
@Override
public KeepFieldInfo getTopInfo() {
return TOP;
@@ -124,7 +157,9 @@
@Override
boolean internalIsEqualTo(KeepFieldInfo other) {
return super.internalIsEqualTo(other)
- && isFieldTypeStrengtheningAllowed() == other.internalIsFieldTypeStrengtheningAllowed();
+ && isFieldTypeStrengtheningAllowed() == other.internalIsFieldTypeStrengtheningAllowed()
+ && isRedundantFieldLoadEliminationAllowed()
+ == other.internalIsRedundantFieldLoadEliminationAllowed();
}
@Override
@@ -144,6 +179,11 @@
return self();
}
+ public Joiner disallowRedundantFieldLoadElimination() {
+ builder.disallowRedundantFieldLoadElimination();
+ return self();
+ }
+
@Override
public Joiner asFieldJoiner() {
return this;
@@ -155,7 +195,10 @@
return super.merge(joiner)
.applyIf(
!joiner.builder.isFieldTypeStrengtheningAllowed(),
- KeepFieldInfo.Joiner::disallowFieldTypeStrengthening);
+ KeepFieldInfo.Joiner::disallowFieldTypeStrengthening)
+ .applyIf(
+ !joiner.builder.isRedundantFieldLoadEliminationAllowed(),
+ KeepFieldInfo.Joiner::disallowRedundantFieldLoadElimination);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/shaking/NoRedundantFieldLoadEliminationRule.java b/src/main/java/com/android/tools/r8/shaking/NoRedundantFieldLoadEliminationRule.java
new file mode 100644
index 0000000..87c5ee0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/shaking/NoRedundantFieldLoadEliminationRule.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2023, 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.shaking;
+
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
+import java.util.List;
+
+public class NoRedundantFieldLoadEliminationRule
+ extends NoOptimizationBaseRule<NoRedundantFieldLoadEliminationRule> {
+
+ public static final String RULE_NAME = "noredundantfieldloadelimination";
+
+ public static class Builder
+ extends NoOptimizationBaseRule.Builder<NoRedundantFieldLoadEliminationRule, Builder> {
+
+ Builder() {
+ super();
+ }
+
+ @Override
+ public NoRedundantFieldLoadEliminationRule.Builder self() {
+ return this;
+ }
+
+ @Override
+ public NoRedundantFieldLoadEliminationRule build() {
+ return new NoRedundantFieldLoadEliminationRule(
+ origin,
+ getPosition(),
+ source,
+ buildClassAnnotations(),
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ buildInheritanceAnnotations(),
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
+ }
+ }
+
+ NoRedundantFieldLoadEliminationRule(
+ Origin origin,
+ Position position,
+ String source,
+ List<ProguardTypeMatcher> classAnnotations,
+ ProguardAccessFlags classAccessFlags,
+ ProguardAccessFlags negatedClassAccessFlags,
+ boolean classTypeNegated,
+ ProguardClassType classType,
+ ProguardClassNameList classNames,
+ List<ProguardTypeMatcher> inheritanceAnnotations,
+ ProguardTypeMatcher inheritanceClassName,
+ boolean inheritanceIsExtends,
+ List<ProguardMemberRule> memberRules) {
+ super(
+ origin,
+ position,
+ source,
+ classAnnotations,
+ classAccessFlags,
+ negatedClassAccessFlags,
+ classTypeNegated,
+ classType,
+ classNames,
+ inheritanceAnnotations,
+ inheritanceClassName,
+ inheritanceIsExtends,
+ memberRules);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ String typeString() {
+ return RULE_NAME;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index c1de766..b050658 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -599,6 +599,12 @@
configurationBuilder.addRule(rule);
return true;
}
+ if (acceptString(NoRedundantFieldLoadEliminationRule.RULE_NAME)) {
+ ProguardConfigurationRule rule =
+ parseNoOptimizationRule(optionStart, NoRedundantFieldLoadEliminationRule.builder());
+ configurationBuilder.addRule(rule);
+ return true;
+ }
if (acceptString(NoReturnTypeStrengtheningRule.RULE_NAME)) {
ProguardConfigurationRule rule =
parseNoOptimizationRule(optionStart, NoReturnTypeStrengtheningRule.builder());
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index 2b6c654..2b36aec 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -288,7 +288,8 @@
markMatchingOverriddenMethods(clazz, memberKeepRules, rule, null, true, ifRule);
markMatchingVisibleFields(clazz, memberKeepRules, rule, null, true, ifRule);
}
- } else if (rule instanceof NoFieldTypeStrengtheningRule) {
+ } else if (rule instanceof NoFieldTypeStrengtheningRule
+ || rule instanceof NoRedundantFieldLoadEliminationRule) {
markMatchingFields(clazz, memberKeepRules, rule, null, ifRule);
} else if (rule instanceof InlineRule
|| rule instanceof KeepConstantArgumentRule
@@ -1237,6 +1238,13 @@
.asFieldJoiner()
.disallowFieldTypeStrengthening();
context.markAsUsed();
+ } else if (context instanceof NoRedundantFieldLoadEliminationRule) {
+ assert item.isProgramField();
+ dependentMinimumKeepInfo
+ .getOrCreateUnconditionalMinimumKeepInfoFor(item.getReference())
+ .asFieldJoiner()
+ .disallowRedundantFieldLoadElimination();
+ context.markAsUsed();
} else if (context instanceof NoUnusedInterfaceRemovalRule) {
noUnusedInterfaceRemoval.add(item.asClass().type);
context.markAsUsed();
diff --git a/src/test/java/com/android/tools/r8/NoRedundantFieldLoadElimination.java b/src/test/java/com/android/tools/r8/NoRedundantFieldLoadElimination.java
new file mode 100644
index 0000000..16b6ebe
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/NoRedundantFieldLoadElimination.java
@@ -0,0 +1,10 @@
+// Copyright (c) 2023, 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;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target({ElementType.FIELD})
+public @interface NoRedundantFieldLoadElimination {}
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index b9c6c781..194d921 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.shaking.NoMethodStaticizingRule;
import com.android.tools.r8.shaking.NoParameterReorderingRule;
import com.android.tools.r8.shaking.NoParameterTypeStrengtheningRule;
+import com.android.tools.r8.shaking.NoRedundantFieldLoadEliminationRule;
import com.android.tools.r8.shaking.NoReturnTypeStrengtheningRule;
import com.android.tools.r8.shaking.NoUnusedInterfaceRemovalRule;
import com.android.tools.r8.shaking.NoVerticalClassMergingRule;
@@ -573,6 +574,12 @@
NoParameterTypeStrengtheningRule.RULE_NAME, NoParameterTypeStrengthening.class);
}
+ public T enableNoRedundantFieldLoadEliminationAnnotations() {
+ return addNoRedundantFieldLoadEliminationAnnotation()
+ .addInternalMatchAnnotationOnFieldRule(
+ NoRedundantFieldLoadEliminationRule.RULE_NAME, NoRedundantFieldLoadElimination.class);
+ }
+
public T enableNoReturnTypeStrengtheningAnnotations() {
return addNoReturnTypeStrengtheningAnnotation()
.addInternalMatchAnnotationOnMethodRule(
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 704ce16..7f96c42 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -532,6 +532,10 @@
return addTestingAnnotation(NoParameterTypeStrengthening.class);
}
+ public final T addNoRedundantFieldLoadEliminationAnnotation() {
+ return addTestingAnnotation(NoRedundantFieldLoadElimination.class);
+ }
+
public final T addNoReturnTypeStrengtheningAnnotation() {
return addTestingAnnotation(NoReturnTypeStrengthening.class);
}