Deduplicate phi just after Ir building
- Sccp can generate duplicate Phi, deduplicate them only on block
where it could be needed.
Change-Id: I5ec08d2c8696eea18b0a9d156ee685eee792501f
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 be3fc05..d5bf54b 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
@@ -13,12 +13,12 @@
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.Switch;
import com.android.tools.r8.ir.code.Value;
-import com.google.common.base.Equivalence;
-import com.google.common.base.Equivalence.Wrapper;
+import java.util.ArrayList;
import java.util.BitSet;
import java.util.Deque;
import java.util.HashMap;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
/**
@@ -75,30 +75,9 @@
assert code.isConsistentSSA();
}
- private static class PhiEquivalence extends Equivalence<Phi> {
-
- @Override
- protected boolean doEquivalent(Phi a, Phi b) {
- assert a.getBlock() == b.getBlock();
- for (int i = 0; i < a.getOperands().size(); i++) {
- if (a.getOperand(i) != b.getOperand(i)) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- protected int doHash(Phi phi) {
- int hash = 0;
- for (Value value : phi.getOperands()) {
- hash = hash * 13 + value.hashCode();
- }
- return hash;
- }
- }
-
private void rewriteCode() {
+ List<BasicBlock> blockToAnalyze = new ArrayList<>();
+
mapping.entrySet().stream()
.filter((entry) -> entry.getValue().isConst())
.forEach((entry) -> {
@@ -109,6 +88,7 @@
// D8 relies on dead code removal to get rid of the dead phi itself.
if (value.numberOfAllUsers() != 0) {
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);
@@ -130,18 +110,8 @@
}
});
- for (BasicBlock block : code.blocks) {
- PhiEquivalence equivalence = new PhiEquivalence();
- HashMap<Wrapper<Phi>, Phi> phis = new HashMap<>();
- for (Phi phi : block.getPhis()) {
- Wrapper<Phi> key = equivalence.wrap(phi);
- Phi replacement = phis.get(key);
- if (replacement != null) {
- phi.replaceUsers(replacement);
- } else {
- phis.put(key, phi);
- }
- }
+ for (BasicBlock block : blockToAnalyze) {
+ block.deduplicatePhis();
}
code.removeAllTrivialPhis();
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index 3e685a2..fc74be1 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -14,6 +14,8 @@
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.StringUtils.BraceType;
+import com.google.common.base.Equivalence;
+import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.ImmutableList;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import java.util.ArrayDeque;
@@ -21,6 +23,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
@@ -1398,4 +1401,46 @@
return false;
}
+
+ private static class PhiEquivalence extends Equivalence<Phi> {
+ @Override
+ protected boolean doEquivalent(Phi a, Phi b) {
+ assert a.getBlock() == b.getBlock();
+ for (int i = 0; i < a.getOperands().size(); i++) {
+ if (a.getOperand(i) != b.getOperand(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ protected int doHash(Phi phi) {
+ int hash = 0;
+ for (Value value : phi.getOperands()) {
+ hash = hash * 13 + value.hashCode();
+ }
+ return hash;
+ }
+ }
+
+ public void deduplicatePhis() {
+ PhiEquivalence equivalence = new PhiEquivalence();
+ HashMap<Wrapper<Phi>, Phi> wrapper2phi = new HashMap<>();
+ Iterator<Phi> phiIt = phis.iterator();
+ while (phiIt.hasNext()) {
+ Phi phi = phiIt.next();
+ Wrapper<Phi> key = equivalence.wrap(phi);
+ Phi replacement = wrapper2phi.get(key);
+ if (replacement != null) {
+ phi.replaceUsers(replacement);
+ for (Value operand : phi.getOperands()) {
+ operand.removePhiUser(phi);
+ }
+ phiIt.remove();
+ } else {
+ wrapper2phi.put(key, phi);
+ }
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index e4168ea..b392308 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -414,6 +414,12 @@
clearCanonicalizationMaps();
source = null;
+ for (BasicBlock block : blocks) {
+ block.deduplicatePhis();
+ }
+
+ ir.removeAllTrivialPhis();
+
assert ir.isConsistentSSA();
return ir;
}