Implement OR abstract function
Bug: b/302483644
Change-Id: I83657149ae8defd3786ef4218534979dc870c058
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/arithmetic/AbstractCalculator.java b/src/main/java/com/android/tools/r8/ir/analysis/value/arithmetic/AbstractCalculator.java
new file mode 100644
index 0000000..741efd0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/arithmetic/AbstractCalculator.java
@@ -0,0 +1,174 @@
+// 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.ir.analysis.value.arithmetic;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.utils.BitUtils;
+
+public class AbstractCalculator {
+
+ public static AbstractValue andIntegers(
+ AbstractValue left, AbstractValue right, AppView<?> appView) {
+ if (left.isZero()) {
+ return left;
+ }
+ if (right.isZero()) {
+ return right;
+ }
+ if (left.isSingleNumberValue() && right.isSingleNumberValue()) {
+ int result =
+ left.asSingleNumberValue().getIntValue() & right.asSingleNumberValue().getIntValue();
+ return appView.abstractValueFactory().createUncheckedSingleNumberValue(result);
+ }
+ if (left.hasDefinitelySetAndUnsetBitsInformation()
+ && right.hasDefinitelySetAndUnsetBitsInformation()) {
+ return appView
+ .abstractValueFactory()
+ .createDefiniteBitsNumberValue(
+ left.getDefinitelySetIntBits() & right.getDefinitelySetIntBits(),
+ left.getDefinitelyUnsetIntBits() | right.getDefinitelyUnsetIntBits());
+ }
+ if (left.hasDefinitelySetAndUnsetBitsInformation()) {
+ return appView
+ .abstractValueFactory()
+ .createDefiniteBitsNumberValue(0, left.getDefinitelyUnsetIntBits());
+ }
+ if (right.hasDefinitelySetAndUnsetBitsInformation()) {
+ return appView
+ .abstractValueFactory()
+ .createDefiniteBitsNumberValue(0, right.getDefinitelyUnsetIntBits());
+ }
+ return AbstractValue.unknown();
+ }
+
+ public static AbstractValue orIntegers(
+ AbstractValue left, AbstractValue right, AppView<?> appView) {
+ if (left.isZero()) {
+ return right;
+ }
+ if (right.isZero()) {
+ return left;
+ }
+ if (left.isSingleNumberValue() && right.isSingleNumberValue()) {
+ int result =
+ left.asSingleNumberValue().getIntValue() | right.asSingleNumberValue().getIntValue();
+ return appView.abstractValueFactory().createUncheckedSingleNumberValue(result);
+ }
+ if (left.hasDefinitelySetAndUnsetBitsInformation()
+ && right.hasDefinitelySetAndUnsetBitsInformation()) {
+ return appView
+ .abstractValueFactory()
+ .createDefiniteBitsNumberValue(
+ left.getDefinitelySetIntBits() | right.getDefinitelySetIntBits(),
+ left.getDefinitelyUnsetIntBits() & right.getDefinitelyUnsetIntBits());
+ }
+ if (left.hasDefinitelySetAndUnsetBitsInformation()) {
+ return appView
+ .abstractValueFactory()
+ .createDefiniteBitsNumberValue(left.getDefinitelySetIntBits(), 0);
+ }
+ if (right.hasDefinitelySetAndUnsetBitsInformation()) {
+ return appView
+ .abstractValueFactory()
+ .createDefiniteBitsNumberValue(right.getDefinitelySetIntBits(), 0);
+ }
+ return AbstractValue.unknown();
+ }
+
+ public static AbstractValue shlIntegers(
+ AbstractValue left, AbstractValue right, AppView<?> appView) {
+ if (!right.isSingleNumberValue()) {
+ return AbstractValue.unknown();
+ }
+ int rightConst = right.asSingleNumberValue().getIntValue();
+ if (rightConst == 0) {
+ return left;
+ }
+ if (left.isSingleNumberValue()) {
+ int result = left.asSingleNumberValue().getIntValue() << rightConst;
+ return appView.abstractValueFactory().createUncheckedSingleNumberValue(result);
+ }
+ if (left.hasDefinitelySetAndUnsetBitsInformation() && rightConst > 0) {
+ // Shift the known bits and add that we now know that the lowermost n bits are definitely
+ // unset. Note that when rightConst is 31, 1 << rightConst is Integer.MIN_VALUE. When
+ // subtracting 1 we overflow and get 0111...111, as desired.
+ return appView
+ .abstractValueFactory()
+ .createDefiniteBitsNumberValue(
+ left.getDefinitelySetIntBits() << rightConst,
+ (left.getDefinitelyUnsetIntBits() << rightConst) | ((1 << rightConst) - 1));
+ }
+ return AbstractValue.unknown();
+ }
+
+ public static AbstractValue shrIntegers(
+ AbstractValue left, AbstractValue right, AppView<?> appView) {
+ if (!right.isSingleNumberValue()) {
+ return AbstractValue.unknown();
+ }
+ int rightConst = right.asSingleNumberValue().getIntValue();
+ if (rightConst == 0) {
+ return left;
+ }
+ if (left.isSingleNumberValue()) {
+ int result = left.asSingleNumberValue().getIntValue() >> rightConst;
+ return appView.abstractValueFactory().createUncheckedSingleNumberValue(result);
+ }
+ if (left.hasDefinitelySetAndUnsetBitsInformation()) {
+ return appView
+ .abstractValueFactory()
+ .createDefiniteBitsNumberValue(
+ left.getDefinitelySetIntBits() >> rightConst,
+ left.getDefinitelyUnsetIntBits() >> rightConst);
+ }
+ return AbstractValue.unknown();
+ }
+
+ public static AbstractValue ushrIntegers(
+ AbstractValue left, AbstractValue right, AppView<?> appView) {
+ if (!right.isSingleNumberValue()) {
+ return AbstractValue.unknown();
+ }
+ int rightConst = right.asSingleNumberValue().getIntValue();
+ if (rightConst == 0) {
+ return left;
+ }
+ if (left.isSingleNumberValue()) {
+ int result = left.asSingleNumberValue().getIntValue() >>> rightConst;
+ return appView.abstractValueFactory().createUncheckedSingleNumberValue(result);
+ }
+ if (left.hasDefinitelySetAndUnsetBitsInformation() && rightConst > 0) {
+ // Shift the known bits information and add that we now know that the uppermost n bits are
+ // definitely unset.
+ return appView
+ .abstractValueFactory()
+ .createDefiniteBitsNumberValue(
+ left.getDefinitelySetIntBits() >>> rightConst,
+ (left.getDefinitelyUnsetIntBits() >>> rightConst)
+ | (BitUtils.ONLY_SIGN_BIT_SET_MASK >> (rightConst - 1)));
+ }
+ return AbstractValue.unknown();
+ }
+
+ public static AbstractValue xorIntegers(
+ AbstractValue left, AbstractValue right, AppView<?> appView) {
+ if (left.isSingleNumberValue() && right.isSingleNumberValue()) {
+ int result =
+ left.asSingleNumberValue().getIntValue() ^ right.asSingleNumberValue().getIntValue();
+ return appView.abstractValueFactory().createUncheckedSingleNumberValue(result);
+ }
+ if (left.hasDefinitelySetAndUnsetBitsInformation()
+ && right.hasDefinitelySetAndUnsetBitsInformation()) {
+ return appView
+ .abstractValueFactory()
+ .createDefiniteBitsNumberValue(
+ (left.getDefinitelySetIntBits() & right.getDefinitelyUnsetIntBits())
+ | (left.getDefinitelyUnsetIntBits() & right.getDefinitelySetIntBits()),
+ (left.getDefinitelySetIntBits() & right.getDefinitelySetIntBits())
+ | (left.getDefinitelyUnsetIntBits() & right.getDefinitelyUnsetIntBits()));
+ }
+ return AbstractValue.unknown();
+ }
+}
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 2639a9d..08b399f 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
@@ -14,6 +14,7 @@
import com.android.tools.r8.dex.code.DexInstruction;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.arithmetic.AbstractCalculator;
import java.util.Set;
public class And extends LogicalBinop {
@@ -104,37 +105,7 @@
@Override
AbstractValue foldIntegers(AbstractValue left, AbstractValue right, AppView<?> appView) {
- if (left.isZero()) {
- return left;
- }
- if (right.isZero()) {
- return right;
- }
- if (left.isSingleNumberValue() && right.isSingleNumberValue()) {
- int result =
- foldIntegers(
- left.asSingleNumberValue().getIntValue(), right.asSingleNumberValue().getIntValue());
- return appView.abstractValueFactory().createSingleNumberValue(result, getOutType());
- }
- if (left.hasDefinitelySetAndUnsetBitsInformation()
- && right.hasDefinitelySetAndUnsetBitsInformation()) {
- return appView
- .abstractValueFactory()
- .createDefiniteBitsNumberValue(
- foldIntegers(left.getDefinitelySetIntBits(), right.getDefinitelySetIntBits()),
- left.getDefinitelyUnsetIntBits() | right.getDefinitelyUnsetIntBits());
- }
- if (left.hasDefinitelySetAndUnsetBitsInformation()) {
- return appView
- .abstractValueFactory()
- .createDefiniteBitsNumberValue(0, left.getDefinitelyUnsetIntBits());
- }
- if (right.hasDefinitelySetAndUnsetBitsInformation()) {
- return appView
- .abstractValueFactory()
- .createDefiniteBitsNumberValue(0, right.getDefinitelyUnsetIntBits());
- }
- return AbstractValue.unknown();
+ return AbstractCalculator.andIntegers(left, right, appView);
}
@Override
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 0cc297a..c098fe2 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
@@ -13,6 +13,7 @@
import com.android.tools.r8.dex.code.DexOrLong2Addr;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.arithmetic.AbstractCalculator;
import java.util.Set;
public class Or extends LogicalBinop {
@@ -103,37 +104,7 @@
@Override
AbstractValue foldIntegers(AbstractValue left, AbstractValue right, AppView<?> appView) {
- if (left.isZero()) {
- return right;
- }
- if (right.isZero()) {
- return left;
- }
- if (left.isSingleNumberValue() && right.isSingleNumberValue()) {
- int result =
- foldIntegers(
- left.asSingleNumberValue().getIntValue(), right.asSingleNumberValue().getIntValue());
- return appView.abstractValueFactory().createSingleNumberValue(result, getOutType());
- }
- if (left.hasDefinitelySetAndUnsetBitsInformation()
- && right.hasDefinitelySetAndUnsetBitsInformation()) {
- return appView
- .abstractValueFactory()
- .createDefiniteBitsNumberValue(
- foldIntegers(left.getDefinitelySetIntBits(), right.getDefinitelySetIntBits()),
- left.getDefinitelyUnsetIntBits() & right.getDefinitelyUnsetIntBits());
- }
- if (left.hasDefinitelySetAndUnsetBitsInformation()) {
- return appView
- .abstractValueFactory()
- .createDefiniteBitsNumberValue(left.getDefinitelySetIntBits(), 0);
- }
- if (right.hasDefinitelySetAndUnsetBitsInformation()) {
- return appView
- .abstractValueFactory()
- .createDefiniteBitsNumberValue(right.getDefinitelySetIntBits(), 0);
- }
- return AbstractValue.unknown();
+ return AbstractCalculator.orIntegers(left, right, appView);
}
@Override
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 a9d9ee4..5977cad 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
@@ -13,6 +13,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.arithmetic.AbstractCalculator;
public class Shl extends LogicalBinop {
@@ -98,28 +99,7 @@
@Override
AbstractValue foldIntegers(AbstractValue left, AbstractValue right, AppView<?> appView) {
- if (!right.isSingleNumberValue()) {
- return AbstractValue.unknown();
- }
- int rightConst = right.asSingleNumberValue().getIntValue();
- if (rightConst == 0) {
- return left;
- }
- if (left.isSingleNumberValue()) {
- int result = foldIntegers(left.asSingleNumberValue().getIntValue(), rightConst);
- return appView.abstractValueFactory().createSingleNumberValue(result, getOutType());
- }
- if (left.hasDefinitelySetAndUnsetBitsInformation() && rightConst > 0) {
- // Shift the known bits and add that we now know that the lowermost n bits are definitely
- // unset. Note that when rightConst is 31, 1 << rightConst is Integer.MIN_VALUE. When
- // subtracting 1 we overflow and get 0111...111, as desired.
- return appView
- .abstractValueFactory()
- .createDefiniteBitsNumberValue(
- foldIntegers(left.getDefinitelySetIntBits(), rightConst),
- foldIntegers(left.getDefinitelyUnsetIntBits(), rightConst) | ((1 << rightConst) - 1));
- }
- return AbstractValue.unknown();
+ return AbstractCalculator.shlIntegers(left, right, appView);
}
@Override
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 bc59c79..d1b6a1c 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
@@ -13,6 +13,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.arithmetic.AbstractCalculator;
public class Shr extends LogicalBinop {
@@ -98,25 +99,7 @@
@Override
AbstractValue foldIntegers(AbstractValue left, AbstractValue right, AppView<?> appView) {
- if (!right.isSingleNumberValue()) {
- return AbstractValue.unknown();
- }
- int rightConst = right.asSingleNumberValue().getIntValue();
- if (rightConst == 0) {
- return left;
- }
- if (left.isSingleNumberValue()) {
- int result = foldIntegers(left.asSingleNumberValue().getIntValue(), rightConst);
- return appView.abstractValueFactory().createSingleNumberValue(result, getOutType());
- }
- if (left.hasDefinitelySetAndUnsetBitsInformation()) {
- return appView
- .abstractValueFactory()
- .createDefiniteBitsNumberValue(
- foldIntegers(left.getDefinitelySetIntBits(), rightConst),
- foldIntegers(left.getDefinitelyUnsetIntBits(), rightConst));
- }
- return AbstractValue.unknown();
+ return AbstractCalculator.shrIntegers(left, right, appView);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Ushr.java b/src/main/java/com/android/tools/r8/ir/code/Ushr.java
index 104b90d..88eb857 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Ushr.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Ushr.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.utils.BitUtils;
+import com.android.tools.r8.ir.analysis.value.arithmetic.AbstractCalculator;
public class Ushr extends LogicalBinop {
@@ -99,28 +99,7 @@
@Override
AbstractValue foldIntegers(AbstractValue left, AbstractValue right, AppView<?> appView) {
- if (!right.isSingleNumberValue()) {
- return AbstractValue.unknown();
- }
- int rightConst = right.asSingleNumberValue().getIntValue();
- if (rightConst == 0) {
- return left;
- }
- if (left.isSingleNumberValue()) {
- int result = foldIntegers(left.asSingleNumberValue().getIntValue(), rightConst);
- return appView.abstractValueFactory().createSingleNumberValue(result, getOutType());
- }
- if (left.hasDefinitelySetAndUnsetBitsInformation() && rightConst > 0) {
- // Shift the known bits information and add that we now know that the uppermost n bits are
- // definitely unset.
- return appView
- .abstractValueFactory()
- .createDefiniteBitsNumberValue(
- foldIntegers(left.getDefinitelySetIntBits(), rightConst),
- foldIntegers(left.getDefinitelyUnsetIntBits(), rightConst)
- | (BitUtils.ONLY_SIGN_BIT_SET_MASK >> (rightConst - 1)));
- }
- return AbstractValue.unknown();
+ return AbstractCalculator.ushrIntegers(left, right, appView);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Xor.java b/src/main/java/com/android/tools/r8/ir/code/Xor.java
index 5116990..fff451f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Xor.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Xor.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.dex.code.DexXorLong2Addr;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.arithmetic.AbstractCalculator;
import java.util.Set;
public class Xor extends LogicalBinop {
@@ -98,23 +99,7 @@
@Override
AbstractValue foldIntegers(AbstractValue left, AbstractValue right, AppView<?> appView) {
- if (left.isSingleNumberValue() && right.isSingleNumberValue()) {
- int result =
- foldIntegers(
- left.asSingleNumberValue().getIntValue(), right.asSingleNumberValue().getIntValue());
- return appView.abstractValueFactory().createSingleNumberValue(result, getOutType());
- }
- if (left.hasDefinitelySetAndUnsetBitsInformation()
- && right.hasDefinitelySetAndUnsetBitsInformation()) {
- return appView
- .abstractValueFactory()
- .createDefiniteBitsNumberValue(
- (left.getDefinitelySetIntBits() & right.getDefinitelyUnsetIntBits())
- | (left.getDefinitelyUnsetIntBits() & right.getDefinitelySetIntBits()),
- (left.getDefinitelySetIntBits() & right.getDefinitelySetIntBits())
- | (left.getDefinitelyUnsetIntBits() & right.getDefinitelyUnsetIntBits()));
- }
- return AbstractValue.unknown();
+ return AbstractCalculator.xorIntegers(left, right, appView);
}
@Override
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
index 0893be8..7b390d6 100644
--- 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
@@ -3,6 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.optimize.argumentpropagation.codescanner;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+
public interface AbstractFunction extends InFlow {
static IdentityAbstractFunction identity() {
@@ -25,7 +28,10 @@
* {@param flowGraphStateProvider}. Attempting to lookup the state of a non-declared input is an
* error.
*/
- ValueState apply(FlowGraphStateProvider flowGraphStateProvider, ConcreteValueState state);
+ ValueState apply(
+ AppView<AppInfoWithLiveness> appView,
+ FlowGraphStateProvider flowGraphStateProvider,
+ ConcreteValueState inState);
/** Returns true if the given {@param inFlow} is a declared input of this abstract function. */
boolean containsBaseInFlow(BaseInFlow inFlow);
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePrimitiveTypeValueState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePrimitiveTypeValueState.java
index 2d53523..fbd733b 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePrimitiveTypeValueState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePrimitiveTypeValueState.java
@@ -29,16 +29,20 @@
assert !isEffectivelyUnknown() : "Must use UnknownParameterState instead";
}
- public static NonEmptyValueState create(AbstractValue abstractValue) {
- return abstractValue.isUnknown()
- ? ValueState.unknown()
- : new ConcretePrimitiveTypeValueState(abstractValue);
- }
-
public ConcretePrimitiveTypeValueState(InFlow inFlow) {
this(AbstractValue.bottom(), SetUtils.newHashSet(inFlow));
}
+ public static NonEmptyValueState create(AbstractValue abstractValue) {
+ return create(abstractValue, Collections.emptySet());
+ }
+
+ public static NonEmptyValueState create(AbstractValue abstractValue, Set<InFlow> inFlow) {
+ return abstractValue.isUnknown()
+ ? ValueState.unknown()
+ : new ConcretePrimitiveTypeValueState(abstractValue, inFlow);
+ }
+
@Override
public ValueState clearInFlow() {
if (hasInFlow()) {
@@ -52,7 +56,7 @@
}
@Override
- public ValueState mutableCopy() {
+ public ConcretePrimitiveTypeValueState mutableCopy() {
return new ConcretePrimitiveTypeValueState(abstractValue, copyInFlow());
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/IdentityAbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/IdentityAbstractFunction.java
index e3818a9..1545a75 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/IdentityAbstractFunction.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/IdentityAbstractFunction.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.optimize.argumentpropagation.codescanner;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
public class IdentityAbstractFunction implements AbstractFunction {
@@ -16,8 +18,11 @@
}
@Override
- public ValueState apply(FlowGraphStateProvider flowGraphStateProvider, ConcreteValueState state) {
- return state;
+ public ValueState apply(
+ AppView<AppInfoWithLiveness> appView,
+ FlowGraphStateProvider flowGraphStateProvider,
+ ConcreteValueState inState) {
+ return inState;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InstanceFieldReadAbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InstanceFieldReadAbstractFunction.java
index 59a3a7f..bd97c0b 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InstanceFieldReadAbstractFunction.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InstanceFieldReadAbstractFunction.java
@@ -3,8 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.optimize.argumentpropagation.codescanner;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.google.common.collect.Lists;
public class InstanceFieldReadAbstractFunction implements AbstractFunction {
@@ -19,7 +21,9 @@
@Override
public ValueState apply(
- FlowGraphStateProvider flowGraphStateProvider, ConcreteValueState predecessorState) {
+ AppView<AppInfoWithLiveness> appView,
+ FlowGraphStateProvider flowGraphStateProvider,
+ ConcreteValueState predecessorState) {
ValueState state = flowGraphStateProvider.getState(receiver, () -> ValueState.bottom(field));
if (state.isBottom()) {
return ValueState.bottom(field);
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/OrAbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/OrAbstractFunction.java
index 93ac577..3c02dd2 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/OrAbstractFunction.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/OrAbstractFunction.java
@@ -3,6 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.optimize.argumentpropagation.codescanner;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.SingleNumberValue;
+import com.android.tools.r8.ir.analysis.value.arithmetic.AbstractCalculator;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.IterableUtils;
import java.util.Objects;
@@ -14,18 +19,22 @@
public class OrAbstractFunction implements AbstractFunction {
public final BaseInFlow inFlow;
- public final long constant;
+ public final SingleNumberValue constant;
- public OrAbstractFunction(BaseInFlow inFlow, long constant) {
+ public OrAbstractFunction(BaseInFlow inFlow, SingleNumberValue constant) {
this.inFlow = inFlow;
this.constant = constant;
}
@Override
- public ValueState apply(FlowGraphStateProvider flowGraphStateProvider, ConcreteValueState state) {
- // TODO(b/302483644): Implement this abstract function to allow correct value propagation of
- // updateChangedFlags(x | 1).
- return state;
+ public ValueState apply(
+ AppView<AppInfoWithLiveness> appView,
+ FlowGraphStateProvider flowGraphStateProvider,
+ ConcreteValueState inState) {
+ ConcretePrimitiveTypeValueState inPrimitiveState = inState.asPrimitiveState();
+ AbstractValue result =
+ AbstractCalculator.orIntegers(inPrimitiveState.getAbstractValue(), constant, appView);
+ return ConcretePrimitiveTypeValueState.create(result, inPrimitiveState.copyInFlow());
}
@Override
@@ -55,7 +64,7 @@
return false;
}
OrAbstractFunction fn = (OrAbstractFunction) obj;
- return inFlow.equals(fn.inFlow) && constant == fn.constant;
+ return inFlow.equals(fn.inFlow) && constant.equals(fn.constant);
}
@Override
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
index 7ddc238..f9ffd98 100644
--- 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
@@ -4,6 +4,8 @@
package com.android.tools.r8.optimize.argumentpropagation.codescanner;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
public class UnknownAbstractFunction implements AbstractFunction {
@@ -16,7 +18,10 @@
}
@Override
- public ValueState apply(FlowGraphStateProvider flowGraphStateProvider, ConcreteValueState state) {
+ public ValueState apply(
+ AppView<AppInfoWithLiveness> appView,
+ FlowGraphStateProvider flowGraphStateProvider,
+ ConcreteValueState inState) {
return ValueState.unknown();
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagator.java
index 894a54c..952b3a2 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagator.java
@@ -149,7 +149,8 @@
for (AbstractFunction transferFunction : transferFunctions) {
FlowGraphStateProvider flowGraphStateProvider =
FlowGraphStateProvider.create(flowGraph, transferFunction);
- ValueState transferState = transferFunction.apply(flowGraphStateProvider, state);
+ ValueState transferState =
+ transferFunction.apply(appView, flowGraphStateProvider, state);
if (transferState.isBottom()) {
// Nothing to propagate.
} else if (transferState.isUnknown()) {
diff --git a/src/main/java/com/android/tools/r8/optimize/compose/ArgumentPropagatorComposeModeling.java b/src/main/java/com/android/tools/r8/optimize/compose/ArgumentPropagatorComposeModeling.java
index ebba6d5..332b695 100644
--- a/src/main/java/com/android/tools/r8/optimize/compose/ArgumentPropagatorComposeModeling.java
+++ b/src/main/java/com/android/tools/r8/optimize/compose/ArgumentPropagatorComposeModeling.java
@@ -13,6 +13,8 @@
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.lens.GraphLens;
+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.InstanceGet;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InvokeMethod;
@@ -203,9 +205,11 @@
argument = otherOperand;
// Update the model from bottom to a special value that effectively throws away any known
// information about the lowermost bit of $$changed.
+ SingleNumberValue one =
+ appView.abstractValueFactory().createSingleNumberValue(1, TypeElement.getInt());
inFlow =
new UpdateChangedFlagsAbstractFunction(
- new OrAbstractFunction(new FieldValue(expectedField), 1));
+ new OrAbstractFunction(new FieldValue(expectedField), one));
} else {
inFlow = new UpdateChangedFlagsAbstractFunction(new FieldValue(expectedField));
}
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
index 8bf3c0d..ee25e29 100644
--- a/src/main/java/com/android/tools/r8/optimize/compose/UpdateChangedFlagsAbstractFunction.java
+++ b/src/main/java/com/android/tools/r8/optimize/compose/UpdateChangedFlagsAbstractFunction.java
@@ -3,12 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.optimize.compose;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.AbstractFunction;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.BaseInFlow;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteValueState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.FlowGraphStateProvider;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlow;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.OrAbstractFunction;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ValueState;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.IterableUtils;
import java.util.Objects;
@@ -21,10 +24,21 @@
}
@Override
- public ValueState apply(FlowGraphStateProvider flowGraphStateProvider, ConcreteValueState state) {
+ public ValueState apply(
+ AppView<AppInfoWithLiveness> appView,
+ FlowGraphStateProvider flowGraphStateProvider,
+ ConcreteValueState baseInState) {
+ ValueState inState;
+ if (inFlow.isAbstractFunction()) {
+ AbstractFunction orFunction = inFlow.asAbstractFunction();
+ assert orFunction instanceof OrAbstractFunction;
+ inState = orFunction.apply(appView, flowGraphStateProvider, baseInState);
+ } else {
+ inState = baseInState;
+ }
// TODO(b/302483644): Implement this abstract function to allow correct value propagation of
// updateChangedFlags(x | 1).
- return state;
+ return inState;
}
@Override