Split KnownArrayLengthRewriter

Bug: b/284304606
Change-Id: I8adf12e3f1cd287ab8ea7ca12265f07134c9c835
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 700422b..2a2813f 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -32,6 +32,7 @@
 import com.android.tools.r8.ir.conversion.passes.BranchSimplifier;
 import com.android.tools.r8.ir.conversion.passes.CommonSubexpressionElimination;
 import com.android.tools.r8.ir.conversion.passes.DexConstantOptimizer;
+import com.android.tools.r8.ir.conversion.passes.KnownArrayLengthRewriter;
 import com.android.tools.r8.ir.conversion.passes.NaturalIntLoopRemover;
 import com.android.tools.r8.ir.conversion.passes.ParentConstructorHoistingCodeRewriter;
 import com.android.tools.r8.ir.conversion.passes.SplitBranch;
@@ -739,9 +740,7 @@
       enumValueOptimizer.run(code, timing);
     }
 
-    timing.begin("Rewrite array length");
-    codeRewriter.rewriteKnownArrayLengthCalls(code);
-    timing.end();
+    new KnownArrayLengthRewriter(appView).run(code, timing);
     new NaturalIntLoopRemover(appView).run(code, timing);
     if (assertionErrorTwoArgsConstructorRewriter != null) {
       timing.begin("Rewrite AssertionError");
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/passes/KnownArrayLengthRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/passes/KnownArrayLengthRewriter.java
new file mode 100644
index 0000000..086a7e0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/conversion/passes/KnownArrayLengthRewriter.java
@@ -0,0 +1,81 @@
+// Copyright (c) 2023, 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.conversion.passes;
+
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.code.ArrayLength;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.Phi;
+import com.android.tools.r8.ir.code.Value;
+import java.util.Set;
+
+public class KnownArrayLengthRewriter extends CodeRewriterPass<AppInfo> {
+
+  public KnownArrayLengthRewriter(AppView<?> appView) {
+    super(appView);
+  }
+
+  @Override
+  protected String getTimingId() {
+    return "KnownArrayLengthRewriter";
+  }
+
+  @Override
+  protected boolean shouldRewriteCode(IRCode code) {
+    return code.metadata().mayHaveArrayLength();
+  }
+
+  @Override
+  protected void rewriteCode(IRCode code) {
+    InstructionListIterator iterator = code.instructionListIterator();
+    while (iterator.hasNext()) {
+      Instruction current = iterator.next();
+      if (!current.isArrayLength()) {
+        continue;
+      }
+
+      ArrayLength arrayLength = current.asArrayLength();
+      if (arrayLength.hasOutValue() && arrayLength.outValue().hasLocalInfo()) {
+        continue;
+      }
+
+      Value array = arrayLength.array().getAliasedValue();
+      if (array.isPhi() || !arrayLength.array().isNeverNull() || array.hasLocalInfo()) {
+        continue;
+      }
+
+      AbstractValue abstractValue = array.getAbstractValue(appView, code.context());
+      if (!abstractValue.hasKnownArrayLength() && !array.isNeverNull()) {
+        continue;
+      }
+      Instruction arrayDefinition = array.getDefinition();
+      assert arrayDefinition != null;
+
+      Set<Phi> phiUsers = arrayLength.outValue().uniquePhiUsers();
+      if (arrayDefinition.isNewArrayEmpty()) {
+        Value size = arrayDefinition.asNewArrayEmpty().size();
+        arrayLength.outValue().replaceUsers(size);
+        iterator.removeOrReplaceByDebugLocalRead();
+      } else if (arrayDefinition.isNewArrayFilledData()) {
+        long size = arrayDefinition.asNewArrayFilledData().size;
+        if (size > Integer.MAX_VALUE) {
+          continue;
+        }
+        iterator.replaceCurrentInstructionWithConstInt(code, (int) size);
+      } else if (abstractValue.hasKnownArrayLength()) {
+        iterator.replaceCurrentInstructionWithConstInt(code, abstractValue.getKnownArrayLength());
+      } else {
+        continue;
+      }
+
+      phiUsers.forEach(Phi::removeTrivialPhi);
+    }
+    assert code.isConsistentSSA(appView);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 0476582..4984711 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -21,8 +21,6 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
-import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.code.ArrayLength;
 import com.android.tools.r8.ir.code.Assume;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.ConstNumber;
@@ -40,7 +38,6 @@
 import com.android.tools.r8.ir.code.InvokeMethod;
 import com.android.tools.r8.ir.code.InvokeVirtual;
 import com.android.tools.r8.ir.code.Move;
-import com.android.tools.r8.ir.code.Phi;
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.Position.SyntheticPosition;
 import com.android.tools.r8.ir.code.StaticGet;
@@ -259,54 +256,6 @@
     }
   }
 
-  public void rewriteKnownArrayLengthCalls(IRCode code) {
-    InstructionListIterator iterator = code.instructionListIterator();
-    while (iterator.hasNext()) {
-      Instruction current = iterator.next();
-      if (!current.isArrayLength()) {
-        continue;
-      }
-
-      ArrayLength arrayLength = current.asArrayLength();
-      if (arrayLength.hasOutValue() && arrayLength.outValue().hasLocalInfo()) {
-        continue;
-      }
-
-      Value array = arrayLength.array().getAliasedValue();
-      if (array.isPhi() || !arrayLength.array().isNeverNull() || array.hasLocalInfo()) {
-        continue;
-      }
-
-      AbstractValue abstractValue = array.getAbstractValue(appView, code.context());
-      if (!abstractValue.hasKnownArrayLength() && !array.isNeverNull()) {
-        continue;
-      }
-      Instruction arrayDefinition = array.getDefinition();
-      assert arrayDefinition != null;
-
-      Set<Phi> phiUsers = arrayLength.outValue().uniquePhiUsers();
-      if (arrayDefinition.isNewArrayEmpty()) {
-        Value size = arrayDefinition.asNewArrayEmpty().size();
-        arrayLength.outValue().replaceUsers(size);
-        iterator.removeOrReplaceByDebugLocalRead();
-      } else if (arrayDefinition.isNewArrayFilledData()) {
-        long size = arrayDefinition.asNewArrayFilledData().size;
-        if (size > Integer.MAX_VALUE) {
-          continue;
-        }
-        iterator.replaceCurrentInstructionWithConstInt(code, (int) size);
-      } else if (abstractValue.hasKnownArrayLength()) {
-        iterator.replaceCurrentInstructionWithConstInt(code, abstractValue.getKnownArrayLength());
-      } else {
-        continue;
-      }
-
-      phiUsers.forEach(Phi::removeTrivialPhi);
-    }
-    code.removeRedundantBlocks();
-    assert code.isConsistentSSA(appView);
-  }
-
   // TODO(mikaelpeltier) Manage that from and to instruction do not belong to the same block.
   private static boolean hasLocalOrLineChangeBetween(
       Instruction from, Instruction to, DexString localVar) {