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) {