Merge "Add peephole infrastructure to IR"
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index ea6cac0..5436f0b 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -41,6 +41,7 @@
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.optimize.CodeRewriter;
 import com.android.tools.r8.ir.optimize.DeadCodeRemover;
+import com.android.tools.r8.ir.optimize.peepholes.BasicBlockMuncher;
 import com.android.tools.r8.utils.InternalOptions;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
@@ -135,6 +136,8 @@
     new DeadCodeRemover(code, rewriter, graphLense, options).run();
     LoadStoreHelper loadStoreHelper = new LoadStoreHelper(code, types);
     loadStoreHelper.insertLoadsAndStores();
+    BasicBlockMuncher muncher = new BasicBlockMuncher();
+    muncher.optimize(code);
     removeUnneededLoadsAndStores();
     registerAllocator = new CfRegisterAllocator(code, options);
     registerAllocator.allocateRegisters();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/peepholes/BasicBlockMuncher.java b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/BasicBlockMuncher.java
new file mode 100644
index 0000000..9528401
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/BasicBlockMuncher.java
@@ -0,0 +1,35 @@
+// Copyright (c) 2018, 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.optimize.peepholes;
+
+import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import java.util.Arrays;
+import java.util.List;
+
+public class BasicBlockMuncher {
+
+  private final List<BasicBlockPeephole> peepholes = Arrays.asList();
+
+  public void optimize(IRCode code) {
+    for (BasicBlock block : code.blocks) {
+      InstructionListIterator it = block.listIterator(block.getInstructions().size());
+      boolean matched = true;
+      while (matched || it.hasPrevious()) {
+        if (!it.hasPrevious()) {
+          matched = false;
+          it = block.listIterator(block.getInstructions().size());
+        }
+        for (BasicBlockPeephole peepHole : peepholes) {
+          matched |= peepHole.match(it);
+        }
+        if (it.hasPrevious()) {
+          it.previous();
+        }
+      }
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/peepholes/BasicBlockPeephole.java b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/BasicBlockPeephole.java
new file mode 100644
index 0000000..a957334
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/BasicBlockPeephole.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2018, 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.optimize.peepholes;
+
+import com.android.tools.r8.ir.code.InstructionListIterator;
+
+public interface BasicBlockPeephole {
+  boolean match(InstructionListIterator it);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/peepholes/PeepholeHelper.java b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/PeepholeHelper.java
new file mode 100644
index 0000000..55078e3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/PeepholeHelper.java
@@ -0,0 +1,60 @@
+// Copyright (c) 2018, 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.optimize.peepholes;
+
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import java.util.function.Predicate;
+
+public class PeepholeHelper {
+
+  public static class PeepholeLayout {
+    private Instruction[] instructions;
+    private Predicate<Instruction>[] predicates;
+
+    public PeepholeLayout(Instruction[] instructions, Predicate<Instruction>... predicates) {
+      this.instructions = instructions;
+      this.predicates = predicates;
+    }
+
+    public Instruction[] test(InstructionListIterator it) {
+      int index = 0;
+      boolean success = true;
+      for (Predicate<Instruction> p : predicates) {
+        if (!it.hasNext()) {
+          success = false;
+          break;
+        }
+        int insertIndex = index++;
+        instructions[insertIndex] = it.next();
+        if (!p.test(instructions[insertIndex])) {
+          success = false;
+          break;
+        }
+      }
+      for (int i = 0; i < index; i++) {
+        it.previous();
+      }
+      return success ? instructions : null;
+    }
+  }
+
+  public static PeepholeLayout getLayout(Predicate<Instruction>... predicates) {
+    Instruction[] arr = new Instruction[predicates.length];
+    return new PeepholeLayout(arr, predicates);
+  }
+
+  public static void swapNextTwoInstructions(InstructionListIterator it) {
+    assert it.hasNext();
+    Instruction moveForward = it.next();
+    Instruction moveBack = it.next();
+    it.set(moveForward);
+    // Two calls to previous is needed because the iterator moves between elements.
+    it.previous();
+    it.previous();
+    it.set(moveBack);
+    it.next();
+  }
+}