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/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);
+      }
+    }
+  }
 }