Refactor SparseConditionalConstantPropagation to use AbstractValue
Change-Id: I742e8a08e9e57c6e9275dfd477baec4d95f2a69a
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index e0cc79c..259fc15 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.ir.analysis.proto.GeneratedMessageLiteShrinker;
import com.android.tools.r8.ir.analysis.proto.ProtoShrinker;
import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
+import com.android.tools.r8.ir.analysis.value.AbstractValueJoiner.AbstractValueConstantPropagationJoiner;
import com.android.tools.r8.ir.analysis.value.AbstractValueJoiner.AbstractValueFieldJoiner;
import com.android.tools.r8.ir.analysis.value.AbstractValueJoiner.AbstractValueParameterJoiner;
import com.android.tools.r8.ir.desugar.TypeRewriter;
@@ -102,6 +103,7 @@
private KeepInfoCollection keepInfo = null;
private final AbstractValueFactory abstractValueFactory = new AbstractValueFactory();
+ private final AbstractValueConstantPropagationJoiner abstractValueConstantPropagationJoiner;
private final AbstractValueFieldJoiner abstractValueFieldJoiner;
private final AbstractValueParameterJoiner abstractValueParameterJoiner;
private final InstanceFieldInitializationInfoFactory instanceFieldInitializationInfoFactory =
@@ -175,6 +177,7 @@
timing.time(
"Compilation context", () -> CompilationContext.createInitialContext(options()));
this.wholeProgramOptimizations = wholeProgramOptimizations;
+ abstractValueConstantPropagationJoiner = new AbstractValueConstantPropagationJoiner(this);
if (enableWholeProgramOptimizations()) {
abstractValueFieldJoiner = new AbstractValueFieldJoiner(withClassHierarchy());
abstractValueParameterJoiner = new AbstractValueParameterJoiner(withClassHierarchy());
@@ -325,6 +328,10 @@
return abstractValueFactory;
}
+ public AbstractValueConstantPropagationJoiner getAbstractValueConstantPropagationJoiner() {
+ return abstractValueConstantPropagationJoiner;
+ }
+
public AbstractValueFieldJoiner getAbstractValueFieldJoiner() {
return abstractValueFieldJoiner;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/constant/Bottom.java b/src/main/java/com/android/tools/r8/ir/analysis/constant/Bottom.java
deleted file mode 100644
index 2f6e36e..0000000
--- a/src/main/java/com/android/tools/r8/ir/analysis/constant/Bottom.java
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2017, 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.constant;
-
-public class Bottom extends LatticeElement {
- private static final Bottom INSTANCE = new Bottom();
-
- private Bottom() {
- }
-
- public static Bottom getInstance() {
- return INSTANCE;
- }
-
- @Override
- public LatticeElement meet(LatticeElement other) {
- return this;
- }
-
- @Override
- public boolean isBottom() {
- return true;
- }
-
- @Override
- public String toString() {
- return "BOTTOM";
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/constant/ConstLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/constant/ConstLatticeElement.java
deleted file mode 100644
index 982f883..0000000
--- a/src/main/java/com/android/tools/r8/ir/analysis/constant/ConstLatticeElement.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2017, 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.constant;
-
-import com.android.tools.r8.ir.code.ConstNumber;
-
-public class ConstLatticeElement extends LatticeElement {
- private final ConstNumber value;
-
- public ConstLatticeElement(ConstNumber value) {
- this.value = value;
- }
-
- @Override
- public LatticeElement meet(LatticeElement other) {
- if (other.isTop()) {
- return this;
- }
- if (other.isBottom()) {
- return other;
- }
- if (other.isConst()) {
- if (value.identicalNonValueNonPositionParts(other.asConst().value)) {
- return this;
- }
- }
- return Bottom.getInstance();
- }
-
- @Override
- public boolean isConst() {
- return true;
- }
-
- @Override
- public ConstLatticeElement asConst() {
- return this;
- }
-
- @Override
- public String toString() {
- return value.toString();
- }
-
- public ConstNumber getConstNumber() {
- return value;
- }
-
- public int getIntValue() {
- return value.getIntValue();
- }
-
- public long getLongValue() {
- return value.getLongValue();
- }
-
- public float getFloatValue() {
- return value.getFloatValue();
- }
-
- public double getDoubleValue() {
- return value.getDoubleValue();
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/constant/ConstRangeLatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/constant/ConstRangeLatticeElement.java
deleted file mode 100644
index b6365e1..0000000
--- a/src/main/java/com/android/tools/r8/ir/analysis/constant/ConstRangeLatticeElement.java
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) 2017, 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.constant;
-
-import com.android.tools.r8.ir.code.Value;
-
-public class ConstRangeLatticeElement extends LatticeElement {
- private final Value value;
-
- public ConstRangeLatticeElement(Value value) {
- assert value.hasValueRange();
- this.value = value;
- }
-
- @Override
- public LatticeElement meet(LatticeElement other) {
- if (other.isTop()) {
- return this;
- }
- if (other.isBottom()) {
- return other;
- }
- if (other.isValueRange()) {
- ConstRangeLatticeElement otherRange = other.asConstRange();
- if (getConstRange().getValueRange().equals(otherRange.getConstRange().getValueRange())) {
- return this;
- }
- }
- return Bottom.getInstance();
- }
-
- @Override
- public boolean isValueRange() {
- return true;
- }
-
- @Override
- public String toString() {
- return value.toString();
- }
-
- public Value getConstRange() {
- return value;
- }
-
- @Override
- public ConstRangeLatticeElement asConstRange() {
- return this;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/constant/LatticeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/constant/LatticeElement.java
deleted file mode 100644
index 320425f..0000000
--- a/src/main/java/com/android/tools/r8/ir/analysis/constant/LatticeElement.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2017, 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.constant;
-
-abstract public class LatticeElement {
- abstract public LatticeElement meet(LatticeElement other);
-
- public boolean isConst() {
- return false;
- }
-
- public boolean isValueRange() {
- return false;
- }
-
- public ConstLatticeElement asConst() {
- return null;
- }
-
- public ConstRangeLatticeElement asConstRange() {
- return null;
- }
-
- public boolean isTop() {
- return false;
- }
-
- public boolean isBottom() {
- return false;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java b/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java
index de4cf6a..95f1b45 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/constant/SparseConditionalConstantPropagation.java
@@ -5,6 +5,9 @@
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.AbstractValueJoiner.AbstractValueConstantPropagationJoiner;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.IRCode;
@@ -21,9 +24,11 @@
import com.android.tools.r8.ir.optimize.AffectedValues;
import com.android.tools.r8.utils.BooleanBox;
import com.android.tools.r8.utils.WorkList;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
import java.util.ArrayList;
import java.util.BitSet;
-import java.util.HashMap;
+import java.util.Comparator;
+import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
@@ -34,8 +39,11 @@
*/
public class SparseConditionalConstantPropagation extends CodeRewriterPass<AppInfo> {
+ private final AbstractValueConstantPropagationJoiner joiner;
+
public SparseConditionalConstantPropagation(AppView<?> appView) {
super(appView);
+ joiner = appView.getAbstractValueConstantPropagationJoiner();
}
@Override
@@ -56,7 +64,7 @@
private class SparseConditionalConstantPropagationOnCode {
private final IRCode code;
- private final Map<Value, LatticeElement> mapping = new HashMap<>();
+ private final Map<Value, AbstractValue> mapping = new IdentityHashMap<>();
private final WorkList<Value> ssaEdges = WorkList.newIdentityWorkList();
@@ -65,6 +73,11 @@
private final BitSet[] executableFlowEdges;
private final BitSet visitedBlocks;
+ private final Map<IntSwitch, Int2ReferenceSortedMap<BasicBlock>> intSwitchKeyToTargetMapCache =
+ new IdentityHashMap<>();
+ private final Map<StringSwitch, Map<DexString, BasicBlock>> stringSwitchKeyToTargetMapCache =
+ new IdentityHashMap<>();
+
private SparseConditionalConstantPropagationOnCode(IRCode code) {
this.code = code;
int maxBlockNumber = code.getCurrentBlockNumber() + 1;
@@ -108,36 +121,50 @@
List<BasicBlock> blockToAnalyze = new ArrayList<>();
BooleanBox hasChanged = new BooleanBox(false);
mapping.entrySet().stream()
- .filter(entry -> entry.getValue().isConst())
+ .filter(entry -> isConstNumber(entry.getKey(), entry.getValue()))
+ .sorted(Comparator.comparingInt(entry -> entry.getKey().getNumber()))
.forEach(
entry -> {
Value value = entry.getKey();
- ConstNumber evaluatedConst = entry.getValue().asConst().getConstNumber();
- if (value.definition != evaluatedConst) {
- if (value.isPhi()) {
- // D8 relies on dead code removal to get rid of the dead phi itself.
- if (value.hasAnyUsers()) {
- BasicBlock block = value.asPhi().getBlock();
- blockToAnalyze.add(block);
- // Create a new constant, because it can be an existing constant that flow
- // directly
- // into the phi.
- ConstNumber newConst = ConstNumber.copyOf(code, evaluatedConst);
- InstructionListIterator iterator = block.listIterator(code);
- Instruction inst = iterator.nextUntil(i -> !i.isMoveException());
- newConst.setPosition(inst.getPosition());
- if (!inst.isDebugPosition()) {
- iterator.previous();
- }
- iterator.add(newConst);
- value.replaceUsers(newConst.outValue(), affectedValues);
- hasChanged.set();
- }
- } else {
- BasicBlock block = value.definition.getBlock();
- InstructionListIterator iterator = block.listIterator(code);
- iterator.nextUntil(i -> i == value.definition);
- iterator.replaceCurrentInstruction(evaluatedConst, affectedValues);
+ if (!value.hasAnyUsers()) {
+ return;
+ }
+ long constValue = entry.getValue().asSingleNumberValue().getValue();
+ if (value.isDefinedByInstructionSatisfying(Instruction::isConstNumber)) {
+ assert value.getDefinition().asConstNumber().getRawValue() == constValue;
+ return;
+ }
+ if (value.isPhi()) {
+ // D8 relies on dead code removal to get rid of the dead phi itself.
+ BasicBlock block = value.asPhi().getBlock();
+ blockToAnalyze.add(block);
+ InstructionListIterator iterator = block.listIterator(code);
+ Instruction inst = iterator.nextUntil(i -> !i.isMoveException());
+ if (!inst.isDebugPosition()) {
+ iterator.previous();
+ }
+ // Create a new constant, because it can be an existing constant that flow
+ // directly into the phi.
+ ConstNumber newConst =
+ ConstNumber.builder()
+ .setFreshOutValue(code, value.getType(), value.getLocalInfo())
+ .setPosition(inst.getPosition())
+ .setValue(constValue)
+ .build();
+ iterator.add(newConst);
+ value.replaceUsers(newConst.outValue(), affectedValues);
+ hasChanged.set();
+ } else {
+ Instruction definition = value.getDefinition();
+ BasicBlock block = definition.getBlock();
+ InstructionListIterator iterator = block.listIterator(code);
+ iterator.nextUntil(i -> i == definition);
+ if (!definition.isArgument()
+ && !definition.instructionMayHaveSideEffects(
+ appView, code.context(), this::getCachedAbstractValue)) {
+ ConstNumber replacement =
+ ConstNumber.builder().setOutValue(value).setValue(constValue).build();
+ iterator.replaceCurrentInstruction(replacement, affectedValues);
hasChanged.set();
}
}
@@ -154,36 +181,40 @@
return changed;
}
- private LatticeElement getLatticeElement(Value value) {
- return mapping.getOrDefault(value, Top.getInstance());
+ private AbstractValue getCachedAbstractValue(Value value) {
+ return mapping.getOrDefault(value, AbstractValue.bottom());
}
- private void setLatticeElement(Value value, LatticeElement element) {
- mapping.put(value, element);
+ private void setAbstractValue(Value value, AbstractValue abstractValue) {
+ mapping.put(value, abstractValue);
+ }
+
+ private boolean isConstNumber(Value value, AbstractValue abstractValue) {
+ return value.getType().isPrimitiveType() && abstractValue.isSingleNumberValue();
}
private void visitPhi(Phi phi) {
BasicBlock phiBlock = phi.getBlock();
int phiBlockNumber = phiBlock.getNumber();
- LatticeElement element = Top.getInstance();
+ AbstractValue phiValue = AbstractValue.bottom();
List<BasicBlock> predecessors = phiBlock.getPredecessors();
int size = predecessors.size();
for (int i = 0; i < size; i++) {
BasicBlock predecessor = predecessors.get(i);
if (isExecutableEdge(predecessor.getNumber(), phiBlockNumber)) {
- element = element.meet(getLatticeElement(phi.getOperand(i)));
- // bottom lattice can no longer be changed, thus no need to continue
- if (element.isBottom()) {
+ phiValue =
+ joiner.join(phiValue, getCachedAbstractValue(phi.getOperand(i)), phi.getType());
+ // Top lattice element can no longer be changed, thus no need to continue.
+ if (phiValue.isUnknown()) {
break;
}
}
}
- if (!element.isTop()) {
- LatticeElement currentPhiElement = getLatticeElement(phi);
- if (currentPhiElement.meet(element) != currentPhiElement) {
- ssaEdges.addIfNotSeen(phi);
- setLatticeElement(phi, element);
- }
+ AbstractValue previousPhiValue = getCachedAbstractValue(phi);
+ assert joiner.lessThanOrEqualTo(previousPhiValue, phiValue, phi.getType());
+ if (!phiValue.equals(previousPhiValue)) {
+ ssaEdges.addIfNotSeen(phi);
+ setAbstractValue(phi, phiValue);
}
}
@@ -196,10 +227,12 @@
private void visitInstruction(Instruction instruction) {
if (instruction.hasOutValue() && !instruction.isDebugLocalUninitialized()) {
- LatticeElement element = instruction.evaluate(code, this::getLatticeElement);
- LatticeElement currentLattice = getLatticeElement(instruction.outValue());
- if (currentLattice.meet(element) != currentLattice) {
- setLatticeElement(instruction.outValue(), element);
+ AbstractValue value =
+ instruction.getAbstractValue(appView, code.context(), this::getCachedAbstractValue);
+ AbstractValue previousValue = getCachedAbstractValue(instruction.outValue());
+ assert joiner.lessThanOrEqualTo(previousValue, value, instruction.getOutType());
+ if (!value.equals(previousValue)) {
+ setAbstractValue(instruction.outValue(), value);
ssaEdges.addIfNotSeen(instruction.outValue());
}
}
@@ -213,10 +246,11 @@
int jumpInstBlockNumber = jumpInstBlock.getNumber();
if (jumpInstruction.isIf()) {
If theIf = jumpInstruction.asIf();
+ AbstractValue lhsValue = getCachedAbstractValue(theIf.lhs());
if (theIf.isZeroTest()) {
- LatticeElement element = getLatticeElement(theIf.inValues().get(0));
- if (element.isConst()) {
- BasicBlock target = theIf.targetFromCondition(element.asConst().getConstNumber());
+ if (isConstNumber(theIf.lhs(), lhsValue)) {
+ int intValue = lhsValue.asSingleNumberValue().getIntValue();
+ BasicBlock target = theIf.targetFromCondition(Integer.signum(intValue));
if (!isExecutableEdge(jumpInstBlockNumber, target.getNumber())) {
setExecutableEdge(jumpInstBlockNumber, target.getNumber());
flowEdges.addIfNotSeen(target);
@@ -224,30 +258,27 @@
return;
}
} else {
- LatticeElement leftElement = getLatticeElement(theIf.inValues().get(0));
- LatticeElement rightElement = getLatticeElement(theIf.inValues().get(1));
- if (leftElement.isConst() && rightElement.isConst()) {
- ConstNumber leftNumber = leftElement.asConst().getConstNumber();
- ConstNumber rightNumber = rightElement.asConst().getConstNumber();
- BasicBlock target = theIf.targetFromCondition(leftNumber, rightNumber);
+ AbstractValue rhsValue = getCachedAbstractValue(theIf.rhs());
+ if (isConstNumber(theIf.lhs(), lhsValue) && isConstNumber(theIf.rhs(), rhsValue)) {
+ long leftValue = lhsValue.asSingleNumberValue().getValue();
+ long rightValue = rhsValue.asSingleNumberValue().getValue();
+ BasicBlock target = theIf.targetFromCondition(leftValue, rightValue);
if (!isExecutableEdge(jumpInstBlockNumber, target.getNumber())) {
setExecutableEdge(jumpInstBlockNumber, target.getNumber());
flowEdges.addIfNotSeen(target);
}
return;
}
- assert !leftElement.isTop();
- assert !rightElement.isTop();
}
} else if (jumpInstruction.isIntSwitch()) {
IntSwitch switchInst = jumpInstruction.asIntSwitch();
- LatticeElement switchElement = getLatticeElement(switchInst.value());
- if (switchElement.isConst()) {
+ AbstractValue value = getCachedAbstractValue(switchInst.value());
+ if (isConstNumber(switchInst.value(), value)) {
+ int intValue = value.asSingleNumberValue().getIntValue();
BasicBlock target =
- switchInst.getKeyToTargetMap().get(switchElement.asConst().getIntValue());
- if (target == null) {
- target = switchInst.fallthroughBlock();
- }
+ intSwitchKeyToTargetMapCache
+ .computeIfAbsent(switchInst, IntSwitch::getKeyToTargetMap)
+ .getOrDefault(intValue, switchInst.fallthroughBlock());
assert target != null;
setExecutableEdge(jumpInstBlockNumber, target.getNumber());
flowEdges.addIfNotSeen(target);
@@ -255,11 +286,18 @@
}
} else if (jumpInstruction.isStringSwitch()) {
StringSwitch switchInst = jumpInstruction.asStringSwitch();
- LatticeElement switchElement = getLatticeElement(switchInst.value());
- if (switchElement.isConst()) {
- // There is currently no constant propagation for strings, so it must be null.
- assert switchElement.asConst().getConstNumber().isZero();
- BasicBlock target = switchInst.fallthroughBlock();
+ AbstractValue value = getCachedAbstractValue(switchInst.value());
+ BasicBlock target = null;
+ if (value.isSingleStringValue()) {
+ DexString stringValue = value.asSingleStringValue().getDexString();
+ target =
+ stringSwitchKeyToTargetMapCache
+ .computeIfAbsent(switchInst, StringSwitch::getKeyToTargetMap)
+ .getOrDefault(stringValue, switchInst.fallthroughBlock());
+ } else if (value.isNull()) {
+ target = switchInst.fallthroughBlock();
+ }
+ if (target != null) {
setExecutableEdge(jumpInstBlockNumber, target.getNumber());
flowEdges.addIfNotSeen(target);
return;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/constant/Top.java b/src/main/java/com/android/tools/r8/ir/analysis/constant/Top.java
deleted file mode 100644
index 4e08a73..0000000
--- a/src/main/java/com/android/tools/r8/ir/analysis/constant/Top.java
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) 2017, 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.constant;
-
-public class Top extends LatticeElement {
- private static final Top INSTANCE = new Top();
-
- private Top() {
- }
-
- public static Top getInstance() {
- return INSTANCE;
- }
-
- @Override
- public LatticeElement meet(LatticeElement other) {
- return other;
- }
-
- @Override
- public boolean isTop() {
- return true;
- }
-
- @Override
- public String toString() {
- return "TOP";
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
index 0f47d7e..8d90411 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
@@ -304,10 +304,9 @@
assert !abstractValue.isBottom();
// When approximating the possible values for the $r8$classId fields from horizontal
- // class
- // merging, give up if the set of possible values equals the size of the merge group. In
- // this case, the information is useless.
- if (abstractValue.isNonConstantNumberValue()) {
+ // class merging, give up if the set of possible values equals the size of the merge
+ // group. In this case, the information is useless.
+ if (abstractValue.isNumberFromSetValue()) {
assert HorizontalClassMergerUtils.isClassIdField(appView, field);
NonConstantNumberValue initialAbstractValue =
field.getOptimizationInfo().getAbstractValue().asNonConstantNumberValue();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueJoiner.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueJoiner.java
index 0c49fca..7b7d239 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueJoiner.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueJoiner.java
@@ -11,12 +11,14 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.horizontalclassmerging.HorizontalClassMergerUtils;
+import com.android.tools.r8.ir.analysis.type.PrimitiveTypeElement;
+import com.android.tools.r8.ir.analysis.type.TypeElement;
public abstract class AbstractValueJoiner {
- protected final AppView<? extends AppInfoWithClassHierarchy> appView;
+ protected final AppView<?> appView;
- private AbstractValueJoiner(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ private AbstractValueJoiner(AppView<?> appView) {
this.appView = appView;
}
@@ -28,7 +30,7 @@
AbstractValue abstractValue,
AbstractValue otherAbstractValue,
AbstractValueJoinerConfig config,
- DexType type) {
+ TypeElement type) {
if (abstractValue.isBottom() || otherAbstractValue.isUnknown()) {
return otherAbstractValue;
}
@@ -37,16 +39,19 @@
|| abstractValue.equals(otherAbstractValue)) {
return abstractValue;
}
- return type.isReferenceType()
- ? joinReference(abstractValue, otherAbstractValue)
- : joinPrimitive(abstractValue, otherAbstractValue, config, type);
+ if (type.isReferenceType()) {
+ return joinReference(abstractValue, otherAbstractValue);
+ } else {
+ assert type.isPrimitiveType();
+ return joinPrimitive(abstractValue, otherAbstractValue, config, type.asPrimitiveType());
+ }
}
private AbstractValue joinPrimitive(
AbstractValue abstractValue,
AbstractValue otherAbstractValue,
AbstractValueJoinerConfig config,
- DexType type) {
+ PrimitiveTypeElement type) {
assert !abstractValue.isNullOrAbstractValue();
assert !otherAbstractValue.isNullOrAbstractValue();
@@ -77,8 +82,8 @@
}
private AbstractValue joinPrimitiveToDefiniteBitsNumberValue(
- AbstractValue abstractValue, AbstractValue otherAbstractValue, DexType type) {
- assert type.isIntType();
+ AbstractValue abstractValue, AbstractValue otherAbstractValue, PrimitiveTypeElement type) {
+ assert type.isInt();
if (!abstractValue.hasDefinitelySetAndUnsetBitsInformation()
|| !otherAbstractValue.hasDefinitelySetAndUnsetBitsInformation()) {
return unknown();
@@ -135,6 +140,26 @@
return unknown();
}
+ public static class AbstractValueConstantPropagationJoiner extends AbstractValueJoiner {
+
+ public AbstractValueConstantPropagationJoiner(AppView<?> appView) {
+ super(appView);
+ }
+
+ public AbstractValue join(
+ AbstractValue abstractValue, AbstractValue otherAbstractValue, TypeElement type) {
+ AbstractValueJoinerConfig config = AbstractValueJoinerConfig.getDefaultConfig();
+ AbstractValue result = internalJoin(abstractValue, otherAbstractValue, config, type);
+ assert result.equals(internalJoin(otherAbstractValue, abstractValue, config, type));
+ return result;
+ }
+
+ public boolean lessThanOrEqualTo(
+ AbstractValue abstractValue, AbstractValue otherAbstractValue, TypeElement type) {
+ return join(abstractValue, otherAbstractValue, type).equals(otherAbstractValue);
+ }
+ }
+
public static class AbstractValueFieldJoiner extends AbstractValueJoiner {
public AbstractValueFieldJoiner(AppView<? extends AppInfoWithClassHierarchy> appView) {
@@ -144,10 +169,9 @@
public AbstractValue join(
AbstractValue abstractValue, AbstractValue otherAbstractValue, ProgramField field) {
AbstractValueJoinerConfig config = getConfig(field);
- AbstractValue result =
- internalJoin(abstractValue, otherAbstractValue, config, field.getType());
- assert result.equals(
- internalJoin(otherAbstractValue, abstractValue, config, field.getType()));
+ TypeElement type = field.getType().toTypeElement(appView);
+ AbstractValue result = internalJoin(abstractValue, otherAbstractValue, config, type);
+ assert result.equals(internalJoin(otherAbstractValue, abstractValue, config, type));
return result;
}
@@ -170,8 +194,9 @@
// TODO(b/196017578): Use a config that allows the definite bits abstraction for parameters
// used in bitwise operations.
AbstractValueJoinerConfig config = AbstractValueJoinerConfig.getDefaultConfig();
- AbstractValue result = internalJoin(abstractValue, otherAbstractValue, config, type);
- assert result.equals(internalJoin(otherAbstractValue, abstractValue, config, type));
+ TypeElement typeElement = type.toTypeElement(appView);
+ AbstractValue result = internalJoin(abstractValue, otherAbstractValue, config, typeElement);
+ assert result.equals(internalJoin(otherAbstractValue, abstractValue, config, typeElement));
return result;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/ConstantOrNonConstantNumberValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/ConstantOrNonConstantNumberValue.java
index 4c6cf04..1afea03 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/ConstantOrNonConstantNumberValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/ConstantOrNonConstantNumberValue.java
@@ -8,12 +8,18 @@
public interface ConstantOrNonConstantNumberValue {
- boolean containsInt(int value);
+ boolean maybeContainsInt(int value);
+
+ long getMinInclusive();
OptionalBool isSubsetOf(int[] values);
ConstantOrNonConstantNumberValue asConstantOrNonConstantNumberValue();
+ boolean isDefiniteBitsNumberValue();
+
+ DefiniteBitsNumberValue asDefiniteBitsNumberValue();
+
boolean isSingleNumberValue();
SingleNumberValue asSingleNumberValue();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/DefiniteBitsNumberValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/DefiniteBitsNumberValue.java
index b081050..2ba6158 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/DefiniteBitsNumberValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/DefiniteBitsNumberValue.java
@@ -22,8 +22,16 @@
}
@Override
- public boolean containsInt(int value) {
- return false;
+ public boolean maybeContainsInt(int value) {
+ // If a definitely set bit is unset in value, then no.
+ if ((definitelySetBits & ~value) != 0) {
+ return false;
+ }
+ // If a definitely unset bit is set in value, then no.
+ if ((definitelyUnsetBits & value) != 0) {
+ return false;
+ }
+ return true;
}
@Override
@@ -31,6 +39,15 @@
return Long.MAX_VALUE;
}
+ public int getDefinitelySetIntBits() {
+ return definitelySetBits;
+ }
+
+ @Override
+ public long getMinInclusive() {
+ return Integer.MIN_VALUE;
+ }
+
@Override
public boolean hasDefinitelySetAndUnsetBitsInformation() {
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromIntervalValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromIntervalValue.java
index 11f395b..997a5ba 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromIntervalValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromIntervalValue.java
@@ -22,7 +22,7 @@
}
@Override
- public boolean containsInt(int value) {
+ public boolean maybeContainsInt(int value) {
return minInclusive <= value && value <= maxInclusive;
}
@@ -31,6 +31,7 @@
return maxInclusive - minInclusive + 1;
}
+ @Override
public long getMinInclusive() {
return minInclusive;
}
@@ -62,8 +63,12 @@
@Override
public boolean mayOverlapWith(ConstantOrNonConstantNumberValue other) {
+ if (other.isDefiniteBitsNumberValue()) {
+ // Conservatively return true.
+ return true;
+ }
if (other.isSingleNumberValue()) {
- return containsInt(other.asSingleNumberValue().getIntValue());
+ return maybeContainsInt(other.asSingleNumberValue().getIntValue());
}
if (other.isNumberFromIntervalValue()) {
return mayOverlapWith(other.asNumberFromIntervalValue());
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromSetValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromSetValue.java
index 629ebf1..dcdcc7e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromSetValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/NumberFromSetValue.java
@@ -19,9 +19,16 @@
private static final int MAX_SIZE = 30;
private final IntSet numbers;
+ private final int min;
private NumberFromSetValue(IntSet numbers) {
+ assert !numbers.isEmpty();
this.numbers = numbers;
+ int min = Integer.MAX_VALUE;
+ for (int number : numbers) {
+ min = Math.min(min, number);
+ }
+ this.min = min;
}
static Builder builder() {
@@ -37,7 +44,7 @@
}
@Override
- public boolean containsInt(int value) {
+ public boolean maybeContainsInt(int value) {
return numbers.contains(value);
}
@@ -47,6 +54,11 @@
}
@Override
+ public long getMinInclusive() {
+ return min;
+ }
+
+ @Override
public boolean isNumberFromSetValue() {
return true;
}
@@ -74,12 +86,15 @@
@Override
public boolean mayOverlapWith(ConstantOrNonConstantNumberValue other) {
- if (other.isSingleNumberValue()) {
- return containsInt(other.asSingleNumberValue().getIntValue());
+ if (other.isDefiniteBitsNumberValue()) {
+ return true;
}
- assert other.isNonConstantNumberValue();
+ if (other.isSingleNumberValue()) {
+ return maybeContainsInt(other.asSingleNumberValue().getIntValue());
+ }
+ assert other.isNumberFromIntervalValue() || other.isNumberFromSetValue();
for (int number : numbers) {
- if (other.containsInt(number)) {
+ if (other.maybeContainsInt(number)) {
return true;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
index e29e468..ff302c8 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
@@ -32,11 +32,16 @@
}
@Override
- public boolean containsInt(int value) {
+ public boolean maybeContainsInt(int value) {
return value == getIntValue();
}
@Override
+ public long getMinInclusive() {
+ return value;
+ }
+
+ @Override
public boolean hasDefinitelySetAndUnsetBitsInformation() {
return true;
}
@@ -116,11 +121,14 @@
@Override
public boolean mayOverlapWith(ConstantOrNonConstantNumberValue other) {
+ if (other.isDefiniteBitsNumberValue()) {
+ return true;
+ }
if (other.isSingleNumberValue()) {
return equals(other.asSingleNumberValue());
}
- assert other.isNonConstantNumberValue();
- return other.asNonConstantNumberValue().containsInt(getIntValue());
+ assert other.isNumberFromIntervalValue() || other.isNumberFromSetValue();
+ return other.asNonConstantNumberValue().maybeContainsInt(getIntValue());
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java b/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java
index 92f7380..a926e50 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ArithmeticBinop.java
@@ -6,14 +6,13 @@
import com.android.tools.r8.cf.code.CfArithmeticBinop;
import com.android.tools.r8.dex.code.DexInstruction;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.ir.analysis.constant.Bottom;
-import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
-import com.android.tools.r8.ir.analysis.constant.LatticeElement;
-import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.SingleNumberValue;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.lightir.LirBuilder;
-import java.util.function.Function;
public abstract class ArithmeticBinop extends Binop {
@@ -132,34 +131,32 @@
}
@Override
- public LatticeElement evaluate(IRCode code, Function<Value, LatticeElement> getLatticeElement) {
- LatticeElement leftLattice = getLatticeElement.apply(leftValue());
- LatticeElement rightLattice = getLatticeElement.apply(rightValue());
- if (leftLattice.isConst() && rightLattice.isConst()) {
- ConstNumber leftConst = leftLattice.asConst().getConstNumber();
- ConstNumber rightConst = rightLattice.asConst().getConstNumber();
- ConstNumber newConst;
+ public AbstractValue getAbstractValue(
+ AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
+ if (outValue.hasLocalInfo()) {
+ return AbstractValue.unknown();
+ }
+ AbstractValue leftAbstractValue = abstractValueSupplier.getAbstractValue(leftValue());
+ AbstractValue rightAbstractValue = abstractValueSupplier.getAbstractValue(rightValue());
+ if (leftAbstractValue.isSingleNumberValue() && rightAbstractValue.isSingleNumberValue()) {
+ SingleNumberValue leftConst = leftAbstractValue.asSingleNumberValue();
+ SingleNumberValue rightConst = rightAbstractValue.asSingleNumberValue();
+ long newConst;
if (type == NumericType.INT) {
- int result = foldIntegers(leftConst.getIntValue(), rightConst.getIntValue());
- Value value = code.createValue(TypeElement.getInt(), getLocalInfo());
- newConst = new ConstNumber(value, result);
+ newConst = foldIntegers(leftConst.getIntValue(), rightConst.getIntValue());
} else if (type == NumericType.LONG) {
- long result = foldLongs(leftConst.getLongValue(), rightConst.getLongValue());
- Value value = code.createValue(TypeElement.getLong(), getLocalInfo());
- newConst = new ConstNumber(value, result);
+ newConst = foldLongs(leftConst.getLongValue(), rightConst.getLongValue());
} else if (type == NumericType.FLOAT) {
float result = foldFloat(leftConst.getFloatValue(), rightConst.getFloatValue());
- Value value = code.createValue(TypeElement.getFloat(), getLocalInfo());
- newConst = new ConstNumber(value, Float.floatToIntBits(result));
+ newConst = Float.floatToIntBits(result);
} else {
assert type == NumericType.DOUBLE;
double result = foldDouble(leftConst.getDoubleValue(), rightConst.getDoubleValue());
- Value value = code.createValue(TypeElement.getDouble(), getLocalInfo());
- newConst = new ConstNumber(value, Double.doubleToLongBits(result));
+ newConst = Double.doubleToLongBits(result);
}
- return new ConstLatticeElement(newConst);
+ return appView.abstractValueFactory().createSingleNumberValue(newConst);
}
- return Bottom.getInstance();
+ return AbstractValue.unknown();
}
abstract CfArithmeticBinop.Opcode getCfOpcode();
diff --git a/src/main/java/com/android/tools/r8/ir/code/Cmp.java b/src/main/java/com/android/tools/r8/ir/code/Cmp.java
index bc4cf73..5c64fc6 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Cmp.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Cmp.java
@@ -13,17 +13,16 @@
import com.android.tools.r8.dex.code.DexInstruction;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.ir.analysis.constant.Bottom;
-import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
-import com.android.tools.r8.ir.analysis.constant.LatticeElement;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.ConstantOrNonConstantNumberValue;
+import com.android.tools.r8.ir.analysis.value.SingleNumberValue;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.lightir.LirBuilder;
-import com.android.tools.r8.utils.LongInterval;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.StringUtils.BraceType;
-import java.util.function.Function;
public class Cmp extends Binop {
@@ -161,12 +160,16 @@
}
@Override
- public LatticeElement evaluate(IRCode code, Function<Value, LatticeElement> getLatticeElement) {
- LatticeElement leftLattice = getLatticeElement.apply(leftValue());
- LatticeElement rightLattice = getLatticeElement.apply(rightValue());
- if (leftLattice.isConst() && rightLattice.isConst()) {
- ConstNumber leftConst = leftLattice.asConst().getConstNumber();
- ConstNumber rightConst = rightLattice.asConst().getConstNumber();
+ public AbstractValue getAbstractValue(
+ AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
+ if (outValue.hasLocalInfo()) {
+ return AbstractValue.unknown();
+ }
+ AbstractValue leftAbstractValue = abstractValueSupplier.getAbstractValue(leftValue());
+ AbstractValue rightAbstractValue = abstractValueSupplier.getAbstractValue(rightValue());
+ if (leftAbstractValue.isSingleNumberValue() && rightAbstractValue.isSingleNumberValue()) {
+ SingleNumberValue leftConst = leftAbstractValue.asSingleNumberValue();
+ SingleNumberValue rightConst = rightAbstractValue.asSingleNumberValue();
int result;
if (type == NumericType.LONG) {
result = Integer.signum(Long.compare(leftConst.getLongValue(), rightConst.getLongValue()));
@@ -188,37 +191,28 @@
result = (int) Math.signum(left - right);
}
}
- Value value = code.createValue(TypeElement.getInt(), getLocalInfo());
- ConstNumber newConst = new ConstNumber(value, result);
- return new ConstLatticeElement(newConst);
- } else if (leftLattice.isValueRange() && rightLattice.isConst()) {
- Value leftValueRange = leftLattice.asConstRange().getConstRange();
- ConstNumber rightConst = rightLattice.asConst().getConstNumber();
- return buildLatticeResult(code, leftValueRange.getValueRange(),
- rightConst.outValue().getValueRange());
- } else if (leftLattice.isConst() && rightLattice.isValueRange()) {
- Value rigthValueRange = rightLattice.asConstRange().getConstRange();
- ConstNumber leftConst = leftLattice.asConst().getConstNumber();
- return buildLatticeResult(code, leftConst.outValue().getValueRange(),
- rigthValueRange.getValueRange());
- } else if (leftLattice.isValueRange() && rightLattice.isValueRange()) {
- Value rigthValueRange = rightLattice.asConstRange().getConstRange();
- Value leftValueRange = leftLattice.asConstRange().getConstRange();
- return buildLatticeResult(code, leftValueRange.getValueRange(),
- rigthValueRange.getValueRange());
+ return appView.abstractValueFactory().createSingleNumberValue(result);
+ } else if (leftAbstractValue.isConstantOrNonConstantNumberValue()
+ && rightAbstractValue.isConstantOrNonConstantNumberValue()) {
+ return buildLatticeResult(
+ appView,
+ leftAbstractValue.asConstantOrNonConstantNumberValue(),
+ rightAbstractValue.asConstantOrNonConstantNumberValue());
}
- return Bottom.getInstance();
+ return AbstractValue.unknown();
}
- private LatticeElement buildLatticeResult(IRCode code, LongInterval leftRange,
- LongInterval rightRange) {
- if (leftRange.overlapsWith(rightRange)) {
- return Bottom.getInstance();
+ private AbstractValue buildLatticeResult(
+ AppView<?> appView,
+ ConstantOrNonConstantNumberValue leftRange,
+ ConstantOrNonConstantNumberValue rightRange) {
+ if (leftRange.mayOverlapWith(rightRange)) {
+ return AbstractValue.unknown();
}
- int result = Integer.signum(Long.compare(leftRange.getMin(), rightRange.getMin()));
- Value value = code.createValue(TypeElement.getInt(), getLocalInfo());
- ConstNumber newConst = new ConstNumber(value, result);
- return new ConstLatticeElement(newConst);
+ // Use min value as representative when values cannot overlap.
+ int result =
+ Integer.signum(Long.compare(leftRange.getMinInclusive(), rightRange.getMinInclusive()));
+ return appView.abstractValueFactory().createSingleNumberValue(result);
}
@Override
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 ec520fb..72b2952 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
@@ -20,9 +20,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.VerifyTypesHelper;
-import com.android.tools.r8.ir.analysis.constant.Bottom;
-import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
-import com.android.tools.r8.ir.analysis.constant.LatticeElement;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.conversion.CfBuilder;
@@ -31,7 +28,6 @@
import com.android.tools.r8.utils.InternalOutputMode;
import com.android.tools.r8.utils.NumberUtils;
import java.util.Set;
-import java.util.function.Function;
public class ConstNumber extends ConstInstruction {
@@ -318,14 +314,6 @@
}
@Override
- public LatticeElement evaluate(IRCode code, Function<Value, LatticeElement> getLatticeElement) {
- if (outValue.hasLocalInfo()) {
- return Bottom.getInstance();
- }
- return new ConstLatticeElement(this);
- }
-
- @Override
public TypeElement evaluate(AppView<?> appView) {
return getOutType();
}
@@ -346,6 +334,9 @@
@Override
public AbstractValue getAbstractValue(
AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
+ if (outValue.hasLocalInfo()) {
+ return AbstractValue.unknown();
+ }
return appView.abstractValueFactory().createSingleNumberValue(value);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Div.java b/src/main/java/com/android/tools/r8/ir/code/Div.java
index a7e9822..6325179 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Div.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Div.java
@@ -15,10 +15,10 @@
import com.android.tools.r8.dex.code.DexDivLong;
import com.android.tools.r8.dex.code.DexDivLong2Addr;
import com.android.tools.r8.dex.code.DexInstruction;
-import com.android.tools.r8.ir.analysis.constant.Bottom;
-import com.android.tools.r8.ir.analysis.constant.LatticeElement;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.lightir.LirBuilder;
-import java.util.function.Function;
public class Div extends ArithmeticBinop {
@@ -132,17 +132,38 @@
}
@Override
+ public boolean instructionInstanceCanThrow(
+ AppView<?> appView,
+ ProgramMethod context,
+ AbstractValueSupplier abstractValueSupplier,
+ SideEffectAssumption assumption) {
+ if (!instructionTypeCanThrow()) {
+ return false;
+ }
+ AbstractValue rightAbstractValue = abstractValueSupplier.getAbstractValue(rightValue());
+ if (rightAbstractValue.isSingleNumberValue() && !rightAbstractValue.isZero()) {
+ return false;
+ }
+ if (rightAbstractValue.isDefiniteBitsNumberValue()
+ && rightAbstractValue.asDefiniteBitsNumberValue().getDefinitelySetIntBits() != 0) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
public boolean instructionTypeCanThrow() {
return type != NumericType.DOUBLE && type != NumericType.FLOAT;
}
@Override
- public LatticeElement evaluate(IRCode code, Function<Value, LatticeElement> getLatticeElement) {
- LatticeElement rightLattice = getLatticeElement.apply(rightValue());
- if (rightLattice.isConst() && !rightLattice.asConst().getConstNumber().isZero()) {
- return super.evaluate(code, getLatticeElement);
+ public AbstractValue getAbstractValue(
+ AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
+ AbstractValue rightAbstractValue = abstractValueSupplier.getAbstractValue(rightValue());
+ if (!rightAbstractValue.isZero()) {
+ return super.getAbstractValue(appView, context, abstractValueSupplier);
}
- return Bottom.getInstance();
+ return AbstractValue.unknown();
}
@Override
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 1b21caa..99a3fe7 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
@@ -23,7 +23,6 @@
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.SingleFieldValue;
-import com.android.tools.r8.ir.analysis.value.UnknownValue;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.Collections;
import java.util.List;
@@ -218,9 +217,14 @@
appView.withClassHierarchy();
DexEncodedField field =
appViewWithClassHierarchy.appInfo().resolveField(getField()).getResolvedField();
- if (field != null) {
- return field.getOptimizationInfo().getAbstractValue();
+ if (field == null) {
+ return AbstractValue.unknown();
}
- return UnknownValue.getInstance();
+ AbstractValue assumeValue =
+ appView.getAssumeInfoCollection().get(field.getReference()).getAssumeValue();
+ if (!assumeValue.isUnknown()) {
+ return assumeValue;
+ }
+ return field.getOptimizationInfo().getAbstractValue();
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/If.java b/src/main/java/com/android/tools/r8/ir/code/If.java
index b0ecd2d..4a3db76 100644
--- a/src/main/java/com/android/tools/r8/ir/code/If.java
+++ b/src/main/java/com/android/tools/r8/ir/code/If.java
@@ -188,7 +188,12 @@
assert !isZeroTest();
assert left.outType() == right.outType();
assert verifyTypeCompatible(left.getOutType(), type);
- return targetFromCondition(Long.signum(left.getRawValue() - right.getRawValue()));
+ return targetFromCondition(left.getRawValue(), right.getRawValue());
+ }
+
+ public BasicBlock targetFromCondition(long left, long right) {
+ assert !isZeroTest();
+ return targetFromCondition(Long.signum(left - right));
}
public BasicBlock targetFromNonNullObject() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/Inc.java b/src/main/java/com/android/tools/r8/ir/code/Inc.java
index 5d3a877..3b51d7d 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Inc.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Inc.java
@@ -12,11 +12,12 @@
import com.android.tools.r8.cf.code.CfStore;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.ir.analysis.constant.LatticeElement;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.lightir.LirBuilder;
-import java.util.function.Function;
public class Inc extends Unop {
@@ -81,7 +82,8 @@
}
@Override
- public LatticeElement evaluate(IRCode code, Function<Value, LatticeElement> getLatticeElement) {
+ public AbstractValue getAbstractValue(
+ AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
// Inc is inserted after register allocation so this is not used.
throw new Unreachable();
}
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 c679523..dd732b4 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
@@ -17,9 +17,6 @@
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.AnalysisAssumption;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis.Query;
import com.android.tools.r8.ir.analysis.VerifyTypesHelper;
-import com.android.tools.r8.ir.analysis.constant.Bottom;
-import com.android.tools.r8.ir.analysis.constant.ConstRangeLatticeElement;
-import com.android.tools.r8.ir.analysis.constant.LatticeElement;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.EmptyFieldSet;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.UnknownFieldSet;
@@ -37,6 +34,7 @@
import com.android.tools.r8.lightir.LirBuilder;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.LongInterval;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.StringUtils.BraceType;
import com.google.common.collect.ImmutableSet;
@@ -45,7 +43,6 @@
import java.util.Iterator;
import java.util.List;
import java.util.Set;
-import java.util.function.Function;
import java.util.function.Predicate;
public abstract class Instruction
@@ -198,6 +195,12 @@
public AbstractValue getAbstractValue(
AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
assert hasOutValue();
+ if (outValue.hasValueRange()) {
+ LongInterval longInterval = outValue.getValueRange();
+ return appView
+ .abstractValueFactory()
+ .createNumberFromIntervalValue(longInterval.getMin(), longInterval.getMax());
+ }
return UnknownValue.getInstance();
}
@@ -1496,13 +1499,6 @@
public abstract boolean hasInvariantOutType();
- public LatticeElement evaluate(IRCode code, Function<Value, LatticeElement> getLatticeElement) {
- if (outValue.hasValueRange()) {
- return new ConstRangeLatticeElement(outValue);
- }
- return Bottom.getInstance();
- }
-
// TODO(b/72693244): maybe rename to computeOutType once TypeVerificationHelper is gone?
public TypeElement evaluate(AppView<?> appView) {
assert outValue == null;
diff --git a/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java b/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java
index 5457a36..a833668 100644
--- a/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java
+++ b/src/main/java/com/android/tools/r8/ir/code/LogicalBinop.java
@@ -6,14 +6,13 @@
import com.android.tools.r8.cf.code.CfLogicalBinop;
import com.android.tools.r8.dex.code.DexInstruction;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.ir.analysis.constant.Bottom;
-import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
-import com.android.tools.r8.ir.analysis.constant.LatticeElement;
-import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.SingleNumberValue;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.lightir.LirBuilder;
-import java.util.function.Function;
public abstract class LogicalBinop extends Binop {
@@ -109,17 +108,19 @@
}
@Override
- public LatticeElement evaluate(IRCode code, Function<Value, LatticeElement> getLatticeElement) {
- LatticeElement leftLattice = getLatticeElement.apply(leftValue());
- LatticeElement rightLattice = getLatticeElement.apply(rightValue());
- if (leftLattice.isConst() && rightLattice.isConst()) {
- ConstNumber leftConst = leftLattice.asConst().getConstNumber();
- ConstNumber rightConst = rightLattice.asConst().getConstNumber();
- ConstNumber newConst;
+ public AbstractValue getAbstractValue(
+ AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
+ if (outValue.hasLocalInfo()) {
+ return AbstractValue.unknown();
+ }
+ AbstractValue leftAbstractValue = abstractValueSupplier.getAbstractValue(leftValue());
+ AbstractValue rightAbstractValue = abstractValueSupplier.getAbstractValue(rightValue());
+ if (leftAbstractValue.isSingleNumberValue() && rightAbstractValue.isSingleNumberValue()) {
+ SingleNumberValue leftConst = leftAbstractValue.asSingleNumberValue();
+ SingleNumberValue rightConst = rightAbstractValue.asSingleNumberValue();
+ long newConst;
if (type == NumericType.INT) {
- int result = foldIntegers(leftConst.getIntValue(), rightConst.getIntValue());
- Value value = code.createValue(TypeElement.getInt(), getLocalInfo());
- newConst = new ConstNumber(value, result);
+ newConst = foldIntegers(leftConst.getIntValue(), rightConst.getIntValue());
} else {
assert type == NumericType.LONG;
long right;
@@ -129,13 +130,11 @@
} else {
right = rightConst.getLongValue();
}
- long result = foldLongs(leftConst.getLongValue(), right);
- Value value = code.createValue(TypeElement.getLong(), getLocalInfo());
- newConst = new ConstNumber(value, result);
+ newConst = foldLongs(leftConst.getLongValue(), right);
}
- return new ConstLatticeElement(newConst);
+ return appView.abstractValueFactory().createSingleNumberValue(newConst);
}
- return Bottom.getInstance();
+ return AbstractValue.unknown();
}
abstract CfLogicalBinop.Opcode getCfOpcode();
diff --git a/src/main/java/com/android/tools/r8/ir/code/Neg.java b/src/main/java/com/android/tools/r8/ir/code/Neg.java
index 7b7c683..222973a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Neg.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Neg.java
@@ -10,15 +10,13 @@
import com.android.tools.r8.dex.code.DexNegInt;
import com.android.tools.r8.dex.code.DexNegLong;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.ir.analysis.constant.Bottom;
-import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
-import com.android.tools.r8.ir.analysis.constant.LatticeElement;
-import com.android.tools.r8.ir.analysis.type.PrimitiveTypeElement;
-import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.SingleNumberValue;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.lightir.LirBuilder;
-import java.util.function.Function;
public class Neg extends Unop {
@@ -86,26 +84,28 @@
}
@Override
- public LatticeElement evaluate(IRCode code, Function<Value, LatticeElement> getLatticeElement) {
- LatticeElement sourceLattice = getLatticeElement.apply(source());
- if (sourceLattice.isConst()) {
- ConstNumber sourceConst = sourceLattice.asConst().getConstNumber();
- TypeElement typeLattice = PrimitiveTypeElement.fromNumericType(type);
- Value value = code.createValue(typeLattice, getLocalInfo());
- ConstNumber newConst;
+ public AbstractValue getAbstractValue(
+ AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
+ if (outValue.hasLocalInfo()) {
+ return AbstractValue.unknown();
+ }
+ AbstractValue sourceLattice = abstractValueSupplier.getAbstractValue(source());
+ if (sourceLattice.isSingleNumberValue()) {
+ SingleNumberValue sourceConst = sourceLattice.asSingleNumberValue();
+ long newConst;
if (type == NumericType.INT) {
- newConst = new ConstNumber(value, -sourceConst.getIntValue());
+ newConst = -sourceConst.getIntValue();
} else if (type == NumericType.LONG) {
- newConst = new ConstNumber(value, -sourceConst.getLongValue());
+ newConst = -sourceConst.getLongValue();
} else if (type == NumericType.FLOAT) {
- newConst = new ConstNumber(value, Float.floatToIntBits(-sourceConst.getFloatValue()));
+ newConst = Float.floatToIntBits(-sourceConst.getFloatValue());
} else {
assert type == NumericType.DOUBLE;
- newConst = new ConstNumber(value, Double.doubleToLongBits(-sourceConst.getDoubleValue()));
+ newConst = Double.doubleToLongBits(-sourceConst.getDoubleValue());
}
- return new ConstLatticeElement(newConst);
+ return appView.abstractValueFactory().createSingleNumberValue(newConst);
}
- return Bottom.getInstance();
+ return AbstractValue.unknown();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Not.java b/src/main/java/com/android/tools/r8/ir/code/Not.java
index 3c6f4c7..ea07979 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Not.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Not.java
@@ -8,15 +8,13 @@
import com.android.tools.r8.dex.code.DexNotInt;
import com.android.tools.r8.dex.code.DexNotLong;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.ir.analysis.constant.Bottom;
-import com.android.tools.r8.ir.analysis.constant.ConstLatticeElement;
-import com.android.tools.r8.ir.analysis.constant.LatticeElement;
-import com.android.tools.r8.ir.analysis.type.PrimitiveTypeElement;
-import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.SingleNumberValue;
import com.android.tools.r8.ir.conversion.CfBuilder;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.lightir.LirBuilder;
-import java.util.function.Function;
public class Not extends Unop {
@@ -43,22 +41,24 @@
}
@Override
- public LatticeElement evaluate(IRCode code, Function<Value, LatticeElement> getLatticeElement) {
- LatticeElement sourceLattice = getLatticeElement.apply(source());
- if (sourceLattice.isConst()) {
- ConstNumber sourceConst = sourceLattice.asConst().getConstNumber();
- TypeElement type = PrimitiveTypeElement.fromNumericType(this.type);
- Value value = code.createValue(type, getLocalInfo());
- ConstNumber newConst;
+ public AbstractValue getAbstractValue(
+ AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
+ if (outValue.hasLocalInfo()) {
+ return AbstractValue.unknown();
+ }
+ AbstractValue sourceLattice = abstractValueSupplier.getAbstractValue(source());
+ if (sourceLattice.isSingleNumberValue()) {
+ SingleNumberValue sourceConst = sourceLattice.asSingleNumberValue();
+ long newConst;
if (this.type == NumericType.INT) {
- newConst = new ConstNumber(value, ~sourceConst.getIntValue());
+ newConst = ~sourceConst.getIntValue();
} else {
assert this.type == NumericType.LONG;
- newConst = new ConstNumber(value, ~sourceConst.getLongValue());
+ newConst = ~sourceConst.getLongValue();
}
- return new ConstLatticeElement(newConst);
+ return appView.abstractValueFactory().createSingleNumberValue(newConst);
}
- return Bottom.getInstance();
+ return AbstractValue.unknown();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/Rem.java b/src/main/java/com/android/tools/r8/ir/code/Rem.java
index df5ffc1..fae9c59 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Rem.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Rem.java
@@ -15,9 +15,9 @@
import com.android.tools.r8.dex.code.DexRemIntLit8;
import com.android.tools.r8.dex.code.DexRemLong;
import com.android.tools.r8.dex.code.DexRemLong2Addr;
-import com.android.tools.r8.ir.analysis.constant.Bottom;
-import com.android.tools.r8.ir.analysis.constant.LatticeElement;
-import java.util.function.Function;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
public class Rem extends ArithmeticBinop {
@@ -131,17 +131,41 @@
}
@Override
+ public boolean instructionInstanceCanThrow(
+ AppView<?> appView,
+ ProgramMethod context,
+ AbstractValueSupplier abstractValueSupplier,
+ SideEffectAssumption assumption) {
+ if (!instructionTypeCanThrow()) {
+ return false;
+ }
+ AbstractValue rightAbstractValue = abstractValueSupplier.getAbstractValue(rightValue());
+ if (rightAbstractValue.isSingleNumberValue() && !rightAbstractValue.isZero()) {
+ return false;
+ }
+ if (rightAbstractValue.isDefiniteBitsNumberValue()
+ && rightAbstractValue.asDefiniteBitsNumberValue().getDefinitelySetIntBits() != 0) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
public boolean instructionTypeCanThrow() {
return type != NumericType.DOUBLE && type != NumericType.FLOAT;
}
@Override
- public LatticeElement evaluate(IRCode code, Function<Value, LatticeElement> getLatticeElement) {
- LatticeElement rightLattice = getLatticeElement.apply(rightValue());
- if (rightLattice.isConst() && !rightLattice.asConst().getConstNumber().isZero()) {
- return super.evaluate(code, getLatticeElement);
+ public AbstractValue getAbstractValue(
+ AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
+ if (outValue.hasLocalInfo()) {
+ return AbstractValue.unknown();
}
- return Bottom.getInstance();
+ AbstractValue rightLattice = abstractValueSupplier.getAbstractValue(rightValue());
+ if (!rightLattice.isZero()) {
+ return super.getAbstractValue(appView, context, abstractValueSupplier);
+ }
+ return AbstractValue.unknown();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/StringSwitch.java b/src/main/java/com/android/tools/r8/ir/code/StringSwitch.java
index 1b4372e..506cb80 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StringSwitch.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StringSwitch.java
@@ -14,6 +14,8 @@
import com.android.tools.r8.lightir.LirBuilder;
import com.android.tools.r8.utils.ThrowingBiConsumer;
import com.android.tools.r8.utils.ThrowingConsumer;
+import java.util.IdentityHashMap;
+import java.util.Map;
public class StringSwitch extends Switch {
@@ -30,6 +32,14 @@
return keys[0];
}
+ public Map<DexString, BasicBlock> getKeyToTargetMap() {
+ Map<DexString, BasicBlock> result = new IdentityHashMap<>();
+ for (int i = 0; i < keys.length; i++) {
+ result.put(getKey(i), targetBlock(i));
+ }
+ return result;
+ }
+
@Override
public int opcode() {
return Opcodes.STRING_SWITCH;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/passes/BranchSimplifier.java b/src/main/java/com/android/tools/r8/ir/conversion/passes/BranchSimplifier.java
index e42475f..6e9d686 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/passes/BranchSimplifier.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/passes/BranchSimplifier.java
@@ -228,7 +228,7 @@
if (theIf.getType() == IfType.EQ || theIf.getType() == IfType.NE) {
AbstractValue lhsAbstractValue = lhs.getAbstractValue(appView, code.context());
if (lhsAbstractValue.isConstantOrNonConstantNumberValue()
- && !lhsAbstractValue.asConstantOrNonConstantNumberValue().containsInt(0)) {
+ && !lhsAbstractValue.asConstantOrNonConstantNumberValue().maybeContainsInt(0)) {
// Value doesn't contain zero at all.
simplifyIfWithKnownCondition(code, block, theIf, theIf.targetFromCondition(1));
return true;
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 40d0bf0..7190f82 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
@@ -793,8 +793,7 @@
private void clearMostRecentStaticFieldWrite(StaticGet staticGet, DexClassAndField field) {
// If the instruction can throw, we need to clear all most-recent-writes, since subsequent
- // field
- // writes (if any) are not guaranteed to be executed.
+ // field writes (if any) are not guaranteed to be executed.
if (staticGet.instructionInstanceCanThrow(appView, method)) {
activeState.clearMostRecentFieldWrites();
} else {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/controlflow/SwitchCaseAnalyzer.java b/src/main/java/com/android/tools/r8/ir/optimize/controlflow/SwitchCaseAnalyzer.java
index 4e01bc5..538f997 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/controlflow/SwitchCaseAnalyzer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/controlflow/SwitchCaseAnalyzer.java
@@ -45,7 +45,7 @@
if (theSwitch.isIntSwitch()) {
int key = theSwitch.asIntSwitch().getKey(index);
if (switchAbstractValue.isConstantOrNonConstantNumberValue()
- && !switchAbstractValue.asConstantOrNonConstantNumberValue().containsInt(key)) {
+ && !switchAbstractValue.asConstantOrNonConstantNumberValue().maybeContainsInt(key)) {
return true;
}
// TODO(b/150836439): Reimplement using AbstractValue.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/R8MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/R8MemberValuePropagation.java
index 9370d5a..64c5ea4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/R8MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/R8MemberValuePropagation.java
@@ -277,11 +277,18 @@
abstractValue = appView.abstractValueFactory().createSingleNumberValue(0);
} else if (appView.appInfo().isFieldWrittenByFieldPutInstruction(target)) {
abstractValue = definition.getOptimizationInfo().getAbstractValue();
- if (abstractValue.isUnknown() && !definition.isStatic()) {
+ if (!definition.isStatic()) {
AbstractValue abstractReceiverValue =
current.asInstanceGet().object().getAbstractValue(appView, code.context());
if (abstractReceiverValue.hasObjectState()) {
- abstractValue = abstractReceiverValue.getObjectState().getAbstractFieldValue(definition);
+ AbstractValue abstractValueFromObjectState =
+ abstractReceiverValue.getObjectState().getAbstractFieldValue(definition);
+ if (!abstractValueFromObjectState.isUnknown()) {
+ // Prefer the abstract value from the current context, as this should be more precise
+ // than the abstract value we computed for the field. If this is not always true, the
+ // meet of the two values could be computed.
+ abstractValue = abstractValueFromObjectState;
+ }
}
}
} else if (definition.isStatic()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/assume/AssumeInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/assume/AssumeInfo.java
index 53dd0bf..0004e86 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/assume/AssumeInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/membervaluepropagation/assume/AssumeInfo.java
@@ -95,7 +95,7 @@
if (other.isUnknown()) {
return value;
}
- return AbstractValue.unknown();
+ return AbstractValue.bottom();
}
private static boolean internalMeetIsSideEffectFree(