Add abstract function to optimization info of updateChangedFlags method
Change-Id: Iaad8f4a45c3cfa1518ec15262072ab28cf97da79
diff --git a/src/main/java/com/android/tools/r8/ir/code/And.java b/src/main/java/com/android/tools/r8/ir/code/And.java
index 03085c1..2639a9d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/And.java
+++ b/src/main/java/com/android/tools/r8/ir/code/And.java
@@ -53,6 +53,11 @@
}
@Override
+ public And asAnd(Value leftValue, Value rightValue) {
+ return leftValue == leftValue() && rightValue == rightValue() ? this : null;
+ }
+
+ @Override
public boolean isCommutative() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
index eb88d9d..634225b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstNumber.java
@@ -308,6 +308,11 @@
}
@Override
+ public ConstNumber asConstNumber(long value) {
+ return this.value == value ? this : null;
+ }
+
+ @Override
public DexType computeVerificationType(AppView<?> appView, TypeVerificationHelper helper) {
assert outType().isObject();
return appView.dexItemFactory().nullValueType;
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldGet.java b/src/main/java/com/android/tools/r8/ir/code/FieldGet.java
index 4d4a55b..6b7f62c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FieldGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldGet.java
@@ -4,7 +4,11 @@
package com.android.tools.r8.ir.code;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.FieldResolutionResult;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
public interface FieldGet {
@@ -20,4 +24,7 @@
boolean hasUsedOutValue();
Value outValue();
+
+ FieldResolutionResult resolveField(
+ AppView<? extends AppInfoWithClassHierarchy> appView, ProgramMethod context);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
index 99a3fe7..0fbadd1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
@@ -41,6 +41,11 @@
this.field = field;
}
+ public FieldResolutionResult resolveField(
+ AppView<? extends AppInfoWithClassHierarchy> appView, ProgramMethod context) {
+ return appView.appInfo().resolveField(field, context);
+ }
+
public abstract Value value();
public FieldMemberType getType() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldPut.java b/src/main/java/com/android/tools/r8/ir/code/FieldPut.java
index 991a263..488e60a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FieldPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldPut.java
@@ -4,7 +4,11 @@
package com.android.tools.r8.ir.code;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.FieldResolutionResult;
+import com.android.tools.r8.graph.ProgramMethod;
public interface FieldPut {
@@ -27,4 +31,7 @@
boolean isStaticPut();
StaticPut asStaticPut();
+
+ FieldResolutionResult resolveField(
+ AppView<? extends AppInfoWithClassHierarchy> appView, ProgramMethod context);
}
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 2bd7ab1..e81b4d0 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
@@ -868,6 +868,10 @@
return null;
}
+ public ConstNumber asConstNumber(long value) {
+ return null;
+ }
+
public boolean isResourceConstNumber() {
return false;
}
@@ -1240,6 +1244,10 @@
return null;
}
+ public Shl asShl(Value leftValue, Value rightValue) {
+ return null;
+ }
+
public boolean isShr() {
return false;
}
@@ -1248,6 +1256,10 @@
return null;
}
+ public Shr asShr(Value leftValue, Value rightValue) {
+ return null;
+ }
+
public boolean isUshr() {
return false;
}
@@ -1264,6 +1276,10 @@
return null;
}
+ public And asAnd(Value leftValue, Value rightValue) {
+ return null;
+ }
+
public boolean isOr() {
return false;
}
@@ -1272,6 +1288,10 @@
return null;
}
+ public Or asOr(Value leftValue, Value rightValue) {
+ return null;
+ }
+
public boolean isXor() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java
index e3ac085..63c5c94 100644
--- a/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java
@@ -29,6 +29,10 @@
private InstructionListIterator currentBlockIterator;
private Set<BasicBlock> seenBlocks = Sets.newIdentityHashSet();
+ public LinearFlowInstructionListIterator(IRCode code) {
+ this(code, code.entryBlock(), 0);
+ }
+
public LinearFlowInstructionListIterator(IRCode code, BasicBlock block) {
this(code, block, 0);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Or.java b/src/main/java/com/android/tools/r8/ir/code/Or.java
index bca7903..0cc297a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Or.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Or.java
@@ -52,6 +52,11 @@
}
@Override
+ public Or asOr(Value leftValue, Value rightValue) {
+ return leftValue == leftValue() && rightValue == rightValue() ? this : null;
+ }
+
+ @Override
public boolean isCommutative() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Shl.java b/src/main/java/com/android/tools/r8/ir/code/Shl.java
index 747daf6..a9d9ee4 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Shl.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Shl.java
@@ -52,6 +52,11 @@
}
@Override
+ public Shl asShl(Value leftValue, Value rightValue) {
+ return leftValue == leftValue() && rightValue == rightValue() ? this : null;
+ }
+
+ @Override
public DexInstruction CreateInt(int dest, int left, int right) {
return new DexShlInt(dest, left, right);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Shr.java b/src/main/java/com/android/tools/r8/ir/code/Shr.java
index e18a846..bc59c79 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Shr.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Shr.java
@@ -47,6 +47,11 @@
}
@Override
+ public Shr asShr(Value leftValue, Value rightValue) {
+ return leftValue == leftValue() && rightValue == rightValue() ? this : null;
+ }
+
+ @Override
public boolean isCommutative() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
index c2fb0e6..f22f61a 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.AbstractFunction;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.BitSetUtils;
import java.util.BitSet;
@@ -35,6 +36,8 @@
void methodReturnsAbstractValue(
DexEncodedMethod method, AppView<AppInfoWithLiveness> appView, AbstractValue abstractValue);
+ void setAbstractFunction(DexEncodedMethod method, AbstractFunction abstractFunction);
+
default void setDynamicReturnType(
ProgramMethod method, AppView<?> appView, DynamicType dynamicType) {
setDynamicReturnType(method.getDefinition(), appView, dynamicType);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
index 36c1bce..6c10cc6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.DefaultInstanceInitializerInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.AbstractFunction;
import com.android.tools.r8.shaking.MaximumRemovedAndroidLogLevelRule;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OptionalBool;
@@ -136,6 +137,11 @@
}
@Override
+ public AbstractFunction getAbstractFunction() {
+ return AbstractFunction.unknown();
+ }
+
+ @Override
public AbstractValue getAbstractReturnValue() {
return UNKNOWN_ABSTRACT_RETURN_VALUE;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
index fadb852..9c7fb22 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.AbstractFunction;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OptionalBool;
import java.util.BitSet;
@@ -82,6 +83,8 @@
public abstract boolean isInitializerEnablingJavaVmAssertions();
+ public abstract AbstractFunction getAbstractFunction();
+
public abstract AbstractValue getAbstractReturnValue();
public abstract SimpleInliningConstraint getNopInliningConstraint(InternalOptions options);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index 9b9b529..382be09 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -100,6 +100,9 @@
import com.android.tools.r8.ir.optimize.typechecks.CheckCastAndInstanceOfMethodSpecialization;
import com.android.tools.r8.kotlin.Kotlin;
import com.android.tools.r8.kotlin.Kotlin.Intrinsics;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameter;
+import com.android.tools.r8.optimize.compose.ComposeUtils;
+import com.android.tools.r8.optimize.compose.UpdateChangedFlagsAbstractFunction;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -142,6 +145,7 @@
DexEncodedMethod definition = method.getDefinition();
identifyBridgeInfo(method, code, feedback, timing);
analyzeReturns(code, feedback, methodProcessor, timing);
+ computeAbstractFunction(code, feedback);
if (options.enableClassInlining) {
computeClassInlinerMethodConstraint(method, code, feedback, timing);
}
@@ -745,6 +749,16 @@
return true;
}
+ private void computeAbstractFunction(IRCode code, OptimizationFeedback feedback) {
+ if (ComposeUtils.isUpdateChangedFlags(code, appView.dexItemFactory())) {
+ MethodParameter methodParameter = new MethodParameter(code.context().getReference(), 0);
+ UpdateChangedFlagsAbstractFunction updateChangedFlagsAbstractFunction =
+ new UpdateChangedFlagsAbstractFunction(methodParameter);
+ feedback.setAbstractFunction(
+ code.context().getDefinition(), updateChangedFlagsAbstractFunction);
+ }
+ }
+
private void computeClassInlinerMethodConstraint(
ProgramMethod method,
IRCode code,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodResolutionOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodResolutionOptimizationInfo.java
index 2139f0f..4831f7f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodResolutionOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodResolutionOptimizationInfo.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.AbstractFunction;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OptionalBool;
import java.util.BitSet;
@@ -75,6 +76,11 @@
}
@Override
+ public AbstractFunction getAbstractFunction() {
+ return AbstractFunction.unknown();
+ }
+
+ @Override
public AbstractValue getAbstractReturnValue() {
return abstractReturnValue;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
index f2a5336..9987a33 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MutableMethodOptimizationInfo.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.AbstractFunction;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.MaximumRemovedAndroidLogLevelRule;
import com.android.tools.r8.utils.BitSetUtils;
@@ -42,6 +43,7 @@
private Set<DexType> initializedClassesOnNormalExit =
DefaultMethodOptimizationInfo.UNKNOWN_INITIALIZED_CLASSES_ON_NORMAL_EXIT;
private int returnedArgument = DefaultMethodOptimizationInfo.UNKNOWN_RETURNED_ARGUMENT;
+ private AbstractFunction abstractFunction = AbstractFunction.unknown();
private AbstractValue abstractReturnValue =
DefaultMethodOptimizationInfo.UNKNOWN_ABSTRACT_RETURN_VALUE;
private ClassInlinerMethodConstraint classInlinerConstraint =
@@ -134,6 +136,7 @@
// Copy constructor used to create a mutable copy. Do not forget to copy from template when a new
// field is added.
private MutableMethodOptimizationInfo(MutableMethodOptimizationInfo template) {
+ abstractFunction = template.abstractFunction;
argumentInfos = template.argumentInfos;
flags = template.flags;
initializedClassesOnNormalExit = template.initializedClassesOnNormalExit;
@@ -473,6 +476,11 @@
}
@Override
+ public AbstractFunction getAbstractFunction() {
+ return abstractFunction;
+ }
+
+ @Override
public AbstractValue getAbstractReturnValue() {
return abstractReturnValue;
}
@@ -699,6 +707,10 @@
abstractReturnValue = UnknownValue.getInstance();
}
+ void setAbstractFunction(AbstractFunction abstractFunction) {
+ this.abstractFunction = abstractFunction;
+ }
+
void setDynamicType(AppView<?> appView, DynamicType newDynamicType, DexEncodedMethod method) {
setDynamicType(appView, newDynamicType, method.getReturnType().toTypeElement(appView));
}
@@ -780,6 +792,7 @@
return argumentInfos == top.getArgumentInfos()
&& initializedClassesOnNormalExit == top.getInitializedClassesOnNormalExit()
&& returnedArgument == top.getReturnedArgument()
+ && abstractFunction == top.getAbstractFunction()
&& abstractReturnValue == top.getAbstractReturnValue()
&& classInlinerConstraint == top.getClassInlinerMethodConstraint()
&& convertCheckNotNull == top.isConvertCheckNotNull()
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
index 8add480..413d343 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.AbstractFunction;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.AppInfoWithLivenessModifier;
import com.android.tools.r8.threading.ThreadingModule;
@@ -192,6 +193,11 @@
}
@Override
+ public void setAbstractFunction(DexEncodedMethod method, AbstractFunction abstractFunction) {
+ getMethodOptimizationInfoForUpdating(method).setAbstractFunction(abstractFunction);
+ }
+
+ @Override
public synchronized void setDynamicReturnType(
DexEncodedMethod method, AppView<?> appView, DynamicType dynamicType) {
getMethodOptimizationInfoForUpdating(method).setDynamicType(appView, dynamicType, method);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
index bb8f841..61fe21d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.AbstractFunction;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.BitSet;
import java.util.Set;
@@ -72,6 +73,11 @@
DexEncodedMethod method, AppView<AppInfoWithLiveness> appView, AbstractValue value) {}
@Override
+ public void setAbstractFunction(DexEncodedMethod method, AbstractFunction abstractFunction) {
+ assert false;
+ }
+
+ @Override
public void setDynamicReturnType(
DexEncodedMethod method, AppView<?> appView, DynamicType dynamicType) {}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
index 34bb23b..9edabc2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.ir.optimize.enums.classification.EnumUnboxerMethodClassification;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.AbstractFunction;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.OptionalBool;
import java.util.BitSet;
@@ -110,6 +111,11 @@
}
@Override
+ public void setAbstractFunction(DexEncodedMethod method, AbstractFunction abstractFunction) {
+ assert false;
+ }
+
+ @Override
public void setDynamicReturnType(
DexEncodedMethod method, AppView<?> appView, DynamicType dynamicType) {
method.getMutableOptimizationInfo().setDynamicType(appView, dynamicType, method);
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/AbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/AbstractFunction.java
new file mode 100644
index 0000000..da529db
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/AbstractFunction.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2024, 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.optimize.argumentpropagation.codescanner;
+
+public interface AbstractFunction extends InFlow {
+
+ static UnknownAbstractFunction unknown() {
+ return UnknownAbstractFunction.get();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/UnknownAbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/UnknownAbstractFunction.java
new file mode 100644
index 0000000..07a87b5
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/UnknownAbstractFunction.java
@@ -0,0 +1,15 @@
+// Copyright (c) 2024, 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.optimize.argumentpropagation.codescanner;
+
+public class UnknownAbstractFunction implements AbstractFunction {
+
+ private static final UnknownAbstractFunction INSTANCE = new UnknownAbstractFunction();
+
+ private UnknownAbstractFunction() {}
+
+ static UnknownAbstractFunction get() {
+ return INSTANCE;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/compose/ComposeUtils.java b/src/main/java/com/android/tools/r8/optimize/compose/ComposeUtils.java
new file mode 100644
index 0000000..f539cd4
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/compose/ComposeUtils.java
@@ -0,0 +1,120 @@
+// Copyright (c) 2024, 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.optimize.compose;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.code.And;
+import com.android.tools.r8.ir.code.Argument;
+import com.android.tools.r8.ir.code.ConstNumber;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.LinearFlowInstructionListIterator;
+import com.android.tools.r8.ir.code.Or;
+import com.android.tools.r8.ir.code.Return;
+import com.android.tools.r8.ir.code.Shl;
+import com.android.tools.r8.ir.code.Shr;
+
+public class ComposeUtils {
+
+ /**
+ * Checks if the given code object executes the following instructions.
+ *
+ * <pre>
+ * private const val changedLowBitMask = 0b001_001_001_001_001_001_001_001_001_001_0
+ * private const val changedHighBitMask = changedLowBitMask shl 1
+ * private const val changedMask = (changedLowBitMask or changedHighBitMask).inv()
+ *
+ * internal fun updateChangedFlags(flags: Int): Int {
+ * val lowBits = flags and changedLowBitMask
+ * val highBits = flags and changedHighBitMask
+ * return ((flags and changedMask) or
+ * (lowBits or (highBits shr 1)) or ((lowBits shl 1) and highBits))
+ * }
+ * </pre>
+ */
+ public static boolean isUpdateChangedFlags(IRCode code, DexItemFactory factory) {
+ ProgramMethod method = code.context();
+ if (!method.getAccessFlags().isStatic()
+ || method.getArity() != 1
+ || method.getParameter(0).isNotIdenticalTo(factory.intType)
+ || method.getReturnType().isNotIdenticalTo(factory.intType)) {
+ return false;
+ }
+ LinearFlowInstructionListIterator instructionIterator =
+ new LinearFlowInstructionListIterator(code);
+ Argument argument = instructionIterator.next().asArgument();
+ assert argument != null;
+ ConstNumber changedLowBitMask =
+ instructionIterator.next().asConstNumber(0b001_001_001_001_001_001_001_001_001_001_0);
+ if (changedLowBitMask == null) {
+ return false;
+ }
+ And lowBits =
+ instructionIterator.next().asAnd(argument.outValue(), changedLowBitMask.outValue());
+ if (lowBits == null) {
+ return false;
+ }
+ ConstNumber changedHighBitMask =
+ instructionIterator.next().asConstNumber(0b010_010_010_010_010_010_010_010_010_010_0);
+ if (changedHighBitMask == null) {
+ return false;
+ }
+ And highBits =
+ instructionIterator.next().asAnd(argument.outValue(), changedHighBitMask.outValue());
+ if (highBits == null) {
+ return false;
+ }
+ ConstNumber changedMask =
+ instructionIterator.next().asConstNumber(0b1_100_100_100_100_100_100_100_100_100_100_1);
+ if (changedMask == null) {
+ return false;
+ }
+ And changedBits = instructionIterator.next().asAnd(argument.outValue(), changedMask.outValue());
+ if (changedBits == null) {
+ return false;
+ }
+ ConstNumber one = instructionIterator.next().asConstNumber(1);
+ if (one == null) {
+ return false;
+ }
+ Shr highBitsShrOne = instructionIterator.next().asShr(highBits.outValue(), one.outValue());
+ if (highBitsShrOne == null) {
+ return false;
+ }
+ Or lowBitsOrHighBitsShrOne =
+ instructionIterator.next().asOr(lowBits.outValue(), highBitsShrOne.outValue());
+ if (lowBitsOrHighBitsShrOne == null) {
+ return false;
+ }
+ Or changedBitsOrLowBitsOrHighBitsShrOne =
+ instructionIterator.next().asOr(changedBits.outValue(), lowBitsOrHighBitsShrOne.outValue());
+ if (changedBitsOrLowBitsOrHighBitsShrOne == null) {
+ return false;
+ }
+ ConstNumber oneAgain = instructionIterator.next().asConstNumber(1);
+ if (oneAgain == null) {
+ return false;
+ }
+ Shl lowBitsShlOne = instructionIterator.next().asShl(lowBits.outValue(), oneAgain.outValue());
+ if (lowBitsShlOne == null) {
+ return false;
+ }
+ And lowBitsShlOneAndHighBits =
+ instructionIterator.next().asAnd(lowBitsShlOne.outValue(), highBits.outValue());
+ if (lowBitsShlOneAndHighBits == null) {
+ return false;
+ }
+ Or result =
+ instructionIterator
+ .next()
+ .asOr(
+ changedBitsOrLowBitsOrHighBitsShrOne.outValue(),
+ lowBitsShlOneAndHighBits.outValue());
+ if (result == null) {
+ return false;
+ }
+ Return theReturn = instructionIterator.next().asReturn();
+ return theReturn != null && theReturn.returnValue() == result.outValue();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/compose/UpdateChangedFlagsAbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/compose/UpdateChangedFlagsAbstractFunction.java
new file mode 100644
index 0000000..5ae767a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/compose/UpdateChangedFlagsAbstractFunction.java
@@ -0,0 +1,17 @@
+// Copyright (c) 2024, 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.optimize.compose;
+
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.AbstractFunction;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlow;
+
+public class UpdateChangedFlagsAbstractFunction implements AbstractFunction {
+
+ @SuppressWarnings("UnusedVariable")
+ private final InFlow inFlow;
+
+ public UpdateChangedFlagsAbstractFunction(InFlow inFlow) {
+ this.inFlow = inFlow;
+ }
+}