Eliminate debug-moves if their preceding phi-move is sufficient.
This reapplies 4c93257 after the recent debug def-use-chain changes.
Bug: 64831882
Change-Id: I4205d5738ea3b49bc311db6e428de3aed886a16d
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
index 8a2de9b..5089ca5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionIterator.java
@@ -154,7 +154,7 @@
for (Value value : current.inValues()) {
value.removeUser(current);
}
- if (current.outValue() != null) {
+ if (current.outValue() != null && current.outValue().isUsed()) {
assert newInstruction.outValue() != null;
current.outValue().replaceUsers(newInstruction.outValue());
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
index ef49910..d8ea70b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
@@ -60,8 +60,8 @@
}
/**
- * Safe removal function that will insert a Nop to take over the debug values if any are assocated
- * with the current instruction.
+ * Safe removal function that will insert a Nop to take over the debug values if any are
+ * associated with the current instruction.
*/
void removeOrReplaceByNop();
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index 0af8f63..ffe3181 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -86,7 +86,7 @@
private boolean isArgument = false;
private boolean knownToBeBoolean = false;
private LongInterval valueRange;
- private final DebugData debugData;
+ private DebugData debugData;
public Value(int number, MoveType type, DebugLocalInfo local) {
this.number = number;
@@ -114,6 +114,11 @@
return debugData == null ? null : debugData.local;
}
+ public void setLocalInfo(DebugLocalInfo local) {
+ assert debugData == null;
+ debugData = new DebugData(local);
+ }
+
public List<Instruction> getDebugLocalStarts() {
if (debugData == null) {
return Collections.emptyList();
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 5b5d382..0ddd43a 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
@@ -442,6 +442,10 @@
printC1VisualizerHeader(method);
printMethod(code, "Initial IR (SSA)");
+ if (options.debug) {
+ codeRewriter.simplifyDebugLocals(code);
+ }
+
if (!method.isProcessed()) {
if (protoLiteRewriter != null && protoLiteRewriter.appliesTo(method)) {
protoLiteRewriter.rewriteProtoLiteSpecialMethod(code, method);
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 52c9eb4..20f272a 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
@@ -38,6 +38,7 @@
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.ConstString;
import com.android.tools.r8.ir.code.ConstType;
+import com.android.tools.r8.ir.code.DebugLocalWrite;
import com.android.tools.r8.ir.code.DominatorTree;
import com.android.tools.r8.ir.code.Goto;
import com.android.tools.r8.ir.code.IRCode;
@@ -1432,6 +1433,40 @@
}
}
+ public void simplifyDebugLocals(IRCode code) {
+ for (BasicBlock block : code.blocks) {
+ for (Phi phi : block.getPhis()) {
+ if (phi.getLocalInfo() == null && phi.numberOfUsers() == 1 && phi.numberOfAllUsers() == 1) {
+ Instruction instruction = phi.uniqueUsers().iterator().next();
+ if (instruction.isDebugLocalWrite()) {
+ removeDebugWriteOfPhi(phi, instruction.asDebugLocalWrite());
+ }
+ }
+ }
+ }
+ }
+
+ private void removeDebugWriteOfPhi(Phi phi, DebugLocalWrite write) {
+ assert write.src() == phi;
+ for (InstructionListIterator iterator = phi.getBlock().listIterator(); iterator.hasNext(); ) {
+ Instruction next = iterator.next();
+ if (!next.isDebugLocalWrite()) {
+ // If the debug write is not in the block header bail out.
+ return;
+ }
+ if (next == write) {
+ // Associate the phi with the local.
+ phi.setLocalInfo(write.getLocalInfo());
+ // Replace uses of the write with the phi.
+ write.outValue().replaceUsers(phi);
+ // Safely remove the write.
+ // TODO(zerny): Once phis become instructions, move debug values there instead of a nop.
+ iterator.removeOrReplaceByNop();
+ return;
+ }
+ }
+ }
+
private static class ExpressionEquivalence extends Equivalence<Instruction> {
@Override