Use an iterative implementation for readRegisterRecursive.
Bug: 77626496
Change-Id: I8856f6e92901ace9f8187f2380c5694daec605b1
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 13d66c2..5efbfb5 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -82,6 +82,7 @@
import com.android.tools.r8.ir.code.Xor;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Pair;
import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
@@ -1604,27 +1605,50 @@
private Value readRegisterRecursive(
int register, BasicBlock block, EdgeType readingEdge, ValueType type, DebugLocalInfo local) {
- Value value;
- if (!block.isSealed()) {
- assert !blocks.isEmpty() : "No write to " + register;
- Phi phi = new Phi(valueNumberGenerator.next(), block, type, local);
- block.addIncompletePhi(register, phi, readingEdge);
- value = phi;
- } else if (block.getPredecessors().size() == 1) {
- assert block.verifyFilledPredecessors();
- BasicBlock pred = block.getPredecessors().get(0);
- EdgeType edgeType = pred.getEdgeType(block);
- value = readRegister(register, type, pred, edgeType, local);
- } else {
- Phi phi = new Phi(valueNumberGenerator.next(), block, type, local);
- // We need to write the phi before adding operands to break cycles. If the phi is trivial
- // and is removed by addOperands, the definition is overwritten and looked up again below.
- block.updateCurrentDefinition(register, phi, readingEdge);
- phi.addOperands(this, register);
- // Lookup the value for the register again at this point. Recursive trivial
- // phi removal could have simplified what we wanted to return here.
- value = block.readCurrentDefinition(register, readingEdge);
+ Value value = null;
+ // Iterate back along the predecessor chain as long as there is a single sealed predecessor.
+ List<Pair<BasicBlock, EdgeType>> stack = null;
+ if (block.isSealed() && block.getPredecessors().size() == 1) {
+ stack = new ArrayList<>(blocks.size());
+ do {
+ assert block.verifyFilledPredecessors();
+ BasicBlock pred = block.getPredecessors().get(0);
+ EdgeType edgeType = pred.getEdgeType(block);
+ checkRegister(register);
+ value = pred.readCurrentDefinition(register, edgeType);
+ if (value != null) {
+ break;
+ }
+ stack.add(new Pair<>(block, readingEdge));
+ block = pred;
+ readingEdge = edgeType;
+ } while (block.isSealed() && block.getPredecessors().size() == 1);
}
+ // If the register still has unknown value create a phi value for it.
+ if (value == null) {
+ if (!block.isSealed()) {
+ assert !blocks.isEmpty() : "No write to " + register;
+ Phi phi = new Phi(valueNumberGenerator.next(), block, type, local);
+ block.addIncompletePhi(register, phi, readingEdge);
+ value = phi;
+ } else {
+ Phi phi = new Phi(valueNumberGenerator.next(), block, type, local);
+ // We need to write the phi before adding operands to break cycles. If the phi is trivial
+ // and is removed by addOperands, the definition is overwritten and looked up again below.
+ block.updateCurrentDefinition(register, phi, readingEdge);
+ phi.addOperands(this, register);
+ // Lookup the value for the register again at this point. Recursive trivial
+ // phi removal could have simplified what we wanted to return here.
+ value = block.readCurrentDefinition(register, readingEdge);
+ }
+ }
+ // If the stack of successors is non-empty then update their definitions with the value.
+ if (stack != null) {
+ for (Pair<BasicBlock, EdgeType> item : stack) {
+ item.getFirst().updateCurrentDefinition(register, value, item.getSecond());
+ }
+ }
+ // Update the last block at which the definition was found/created.
block.updateCurrentDefinition(register, value, readingEdge);
return value;
}