Only analyze BasicBlock instructions once in FieldValueAnalysis
Change-Id: Ife528e77988cc2f5d90c7ce2b94f6d3127ea1c8c
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
index e9060a4..0f02442 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
@@ -239,20 +239,24 @@
if (!blockOrPredecessorMaybeReadAnyField) {
// Finally, we update the read set with the fields that are read by the instructions in the
- // current block.
- for (Instruction instruction : block.getInstructions()) {
- AbstractFieldSet instructionReadSet = instruction.readSet(appView, context);
- if (instructionReadSet.isBottom()) {
- continue;
+ // current block. This can be skipped if the block has already been processed.
+ if (seenBefore) {
+ assert verifyFieldSetContainsAllFieldReadsInBlock(knownReadSet, block, context);
+ } else {
+ for (Instruction instruction : block.getInstructions()) {
+ AbstractFieldSet instructionReadSet = instruction.readSet(appView, context);
+ if (instructionReadSet.isBottom()) {
+ continue;
+ }
+ if (instructionReadSet.isTop()) {
+ blockOrPredecessorMaybeReadAnyField = true;
+ break;
+ }
+ if (!knownReadSet.isConcreteFieldSet()) {
+ knownReadSet = new ConcreteMutableFieldSet();
+ }
+ knownReadSet.asConcreteFieldSet().addAll(instructionReadSet.asConcreteFieldSet());
}
- if (instructionReadSet.isTop()) {
- blockOrPredecessorMaybeReadAnyField = true;
- break;
- }
- if (!knownReadSet.isConcreteFieldSet()) {
- knownReadSet = new ConcreteMutableFieldSet();
- }
- knownReadSet.asConcreteFieldSet().addAll(instructionReadSet.asConcreteFieldSet());
}
}
@@ -279,6 +283,21 @@
return result;
}
+ private boolean verifyFieldSetContainsAllFieldReadsInBlock(
+ KnownFieldSet readSet, BasicBlock block, DexType context) {
+ for (Instruction instruction : block.getInstructions()) {
+ AbstractFieldSet instructionReadSet = instruction.readSet(appView, context);
+ assert !instructionReadSet.isTop();
+ if (instructionReadSet.isBottom()) {
+ continue;
+ }
+ for (DexEncodedField field : instructionReadSet.asConcreteFieldSet().getFields()) {
+ assert readSet.contains(field);
+ }
+ }
+ return true;
+ }
+
private void updateFieldOptimizationInfo(DexEncodedField field, Value value) {
// Abstract value.
Value root = value.getAliasedValue();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/KnownFieldSet.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/KnownFieldSet.java
index b96918e..263101b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/KnownFieldSet.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/KnownFieldSet.java
@@ -4,8 +4,12 @@
package com.android.tools.r8.ir.analysis.fieldvalueanalysis;
+import com.android.tools.r8.graph.DexEncodedField;
+
public interface KnownFieldSet {
+ boolean contains(DexEncodedField field);
+
default boolean isConcreteFieldSet() {
return false;
}