Improve performance of MoveLoadUpPeephole by not resetting position

Bug: 138922694
Change-Id: I830bd4a25c4bf862162a1ca00645aec56b7e3bb9
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 db2d7bb..8907df8 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
@@ -142,7 +142,7 @@
       boolean reachedFixpoint = false;
       phiOptimizations.optimize(code);
       while (!reachedFixpoint) {
-        BasicBlockMuncher.optimize(code);
+        BasicBlockMuncher.optimize(code, appView.options());
         reachedFixpoint = !phiOptimizations.optimize(code);
       }
     }
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
index b2db648..8eaf454 100644
--- 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
@@ -4,10 +4,14 @@
 
 package com.android.tools.r8.ir.optimize.peepholes;
 
+import static com.android.tools.r8.utils.InternalOptions.TestingOptions.NO_LIMIT;
+
+import com.android.tools.r8.errors.CompilationError;
 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 com.android.tools.r8.ir.code.LinearFlowInstructionListIterator;
+import com.android.tools.r8.utils.InternalOptions;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
 import java.util.ListIterator;
@@ -29,13 +33,15 @@
         new StoreLoadToDupStorePeephole());
   }
 
-  public static void optimize(IRCode code) {
-    runPeepholes(code, nonDestructivePeepholes());
-    runPeepholes(code, destructivePeepholes());
+  public static void optimize(IRCode code, InternalOptions options) {
+    runPeepholes(code, nonDestructivePeepholes(), options);
+    runPeepholes(code, destructivePeepholes(), options);
   }
 
-  private static void runPeepholes(IRCode code, List<BasicBlockPeephole> peepholes) {
+  private static void runPeepholes(
+      IRCode code, List<BasicBlockPeephole> peepholes, InternalOptions options) {
     ListIterator<BasicBlock> blocksIterator = code.listIterator(code.blocks.size());
+    int iterations = 0;
     while (blocksIterator.hasPrevious()) {
       BasicBlock currentBlock = blocksIterator.previous();
       InstructionListIterator it =
@@ -60,6 +66,12 @@
           }
         }
         if (it.hasPrevious()) {
+          if (options.testing.basicBlockMuncherIterationLimit != NO_LIMIT) {
+            if (iterations > options.testing.basicBlockMuncherIterationLimit) {
+              throw new CompilationError("Too many iterations in BasicBlockMuncher");
+            }
+            iterations++;
+          }
           it.previous();
         }
       }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/peepholes/MoveLoadUpPeephole.java b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/MoveLoadUpPeephole.java
index 1a98fef..c50791e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/peepholes/MoveLoadUpPeephole.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/peepholes/MoveLoadUpPeephole.java
@@ -85,8 +85,10 @@
 
     // Find the place to insert a new load.
     Instruction current = it.previous();
+    int moves = 1;
     while (current != insertPosition) {
       current = it.previous();
+      moves++;
     }
 
     // Insert directly above the other load.
@@ -94,8 +96,11 @@
     newLoad.setPosition(insertPosition.getPosition());
     it.add(newLoad);
 
-    // Do not reset the instruction pointer because the iterator should reset.
-    return true;
+    // This will run in a loop where we are only going backwards and there is no need to iterate
+    // the same instructions again since the StoreLoad peephole will not change the level of the
+    // stack.
+    PeepholeHelper.resetPrevious(it, moves + 1);
+    return false;
   }
 
   private static boolean isPotentionalIncInstruction(InstructionListIterator it) {
@@ -127,7 +132,7 @@
 
   @Override
   public boolean resetAfterMatch() {
-    return true;
+    return false;
   }
 
 }
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index b9dd6c6..60d6b06 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -973,6 +973,8 @@
 
   public static class TestingOptions {
 
+    public static int NO_LIMIT = -1;
+
     // Force writing the specified bytes as the DEX version content.
     public byte[] forceDexVersionBytes = null;
 
@@ -1018,6 +1020,7 @@
     public StringConsumer desugaredLibraryKeepRuleConsumer = null;
     // TODO(b/129458850) When fixed, remove this and change all usages to "true".
     public boolean enableStatefulLambdaCreateInstanceMethod = false;
+    public int basicBlockMuncherIterationLimit = NO_LIMIT;
 
     // Flag to turn on/off JDK11+ nest-access control even when not required (Cf backend)
     public boolean enableForceNestBasedAccessDesugaringForTest = false;
diff --git a/src/test/java/com/android/tools/r8/cf/BasicBlockMuncherQuadraticTest.java b/src/test/java/com/android/tools/r8/cf/BasicBlockMuncherQuadraticTest.java
index f47127f..7ab71ea 100644
--- a/src/test/java/com/android/tools/r8/cf/BasicBlockMuncherQuadraticTest.java
+++ b/src/test/java/com/android/tools/r8/cf/BasicBlockMuncherQuadraticTest.java
@@ -17,11 +17,8 @@
         .addKeepMainRule(MethodHolder.class)
         .addInnerClasses(BasicBlockMuncherQuadraticTest.class)
         .noMinification()
+        .addOptionsModification(options -> options.testing.basicBlockMuncherIterationLimit = 50000)
         .compile();
-    long end = System.currentTimeMillis();
-    if (end - start > 1000) {
-      System.out.println("WARNING: compilation of this method took " + (end - start) + " ms.");
-    }
   }
 
   public static class MethodHolder {