Verify absence of dead code after optimization info collection
Change-Id: I83d044211756ea6265ddbb442c630775665833c3
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index 4c3822a..f4bb790 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -527,6 +527,15 @@
return !phis.isEmpty();
}
+ public boolean hasDeadPhi(AppView<?> appView, IRCode code) {
+ for (Phi phi : phis) {
+ if (phi.isDead(appView, code)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public List<Phi> getPhis() {
return phis;
}
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 5c88e60..a16d39d 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
@@ -46,6 +46,7 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.Xor;
import com.android.tools.r8.ir.optimize.CodeRewriter;
+import com.android.tools.r8.ir.optimize.DeadCodeRemover;
import com.android.tools.r8.ir.optimize.PeepholeOptimizer;
import com.android.tools.r8.ir.optimize.PhiOptimizations;
import com.android.tools.r8.ir.optimize.peepholes.BasicBlockMuncher;
@@ -127,10 +128,11 @@
this.code = code;
}
- public CfCode build() {
+ public CfCode build(DeadCodeRemover deadCodeRemover) {
computeInitializers();
TypeVerificationHelper typeVerificationHelper = new TypeVerificationHelper(appView, code);
typeVerificationHelper.computeVerificationTypes();
+ assert deadCodeRemover.verifyNoDeadCode(code);
rewriteNots();
LoadStoreHelper loadStoreHelper = new LoadStoreHelper(appView, code, typeVerificationHelper);
loadStoreHelper.insertLoadsAndStores();
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 3b97428..f7b9ce0 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
@@ -1602,7 +1602,7 @@
private void finalizeToCf(DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
assert !method.getCode().isDexCode();
CfBuilder builder = new CfBuilder(appView, method, code);
- CfCode result = builder.build();
+ CfCode result = builder.build(deadCodeRemover);
method.setCode(result, appView);
markProcessed(method, code, feedback);
}
@@ -1654,6 +1654,7 @@
IRCode code, DexEncodedMethod method, Timing timing) {
// Always perform dead code elimination before register allocation. The register allocator
// does not allow dead code (to make sure that we do not waste registers for unneeded values).
+ assert deadCodeRemover.verifyNoDeadCode(code);
materializeInstructionBeforeLongOperationsWorkaround(code);
workaroundForwardingInitializerBug(code);
timing.begin("Allocate registers");
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 8a462f7..55db2fd 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
@@ -1177,12 +1177,13 @@
}
// Replace result uses for methods where something is known about what is returned.
- public void rewriteMoveResult(IRCode code) {
+ public boolean rewriteMoveResult(IRCode code) {
if (options.isGeneratingClassFiles() || !code.metadata().mayHaveInvokeMethod()) {
- return;
+ return false;
}
AssumeDynamicTypeRemover assumeDynamicTypeRemover = new AssumeDynamicTypeRemover(appView, code);
+ boolean changed = false;
boolean mayHaveRemovedTrivialPhi = false;
Set<Value> affectedValues = Sets.newIdentityHashSet();
Set<BasicBlock> blocksToBeRemoved = Sets.newIdentityHashSet();
@@ -1218,6 +1219,7 @@
mayHaveRemovedTrivialPhi |= outValue.numberOfPhiUsers() > 0;
outValue.replaceUsers(argument);
invoke.setOutValue(null);
+ changed = true;
}
}
}
@@ -1235,6 +1237,7 @@
new TypeAnalysis(appView).narrowing(affectedValues);
}
assert code.isConsistentSSA();
+ return changed;
}
enum RemoveCheckCastInstructionIfTrivialResult {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
index f2056d3..ef9c66c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
@@ -57,6 +57,24 @@
timing.end();
}
+ public boolean verifyNoDeadCode(IRCode code) {
+ assert !codeRewriter.rewriteMoveResult(code);
+ assert !removeUnneededCatchHandlers(code);
+ for (BasicBlock block : code.blocks) {
+ assert !block.hasDeadPhi(appView, code);
+ for (Instruction instruction : block.getInstructions()) {
+ // No unused move-result instructions.
+ assert !instruction.isInvoke()
+ || !instruction.hasOutValue()
+ || instruction.outValue().hasAnyUsers();
+ // No dead instructions.
+ assert !instruction.canBeDeadCode(appView, code)
+ || (instruction.hasOutValue() && !instruction.outValue().isDead(appView, code));
+ }
+ }
+ return true;
+ }
+
// Add the block from where the value originates to the worklist.
private static void updateWorklist(Queue<BasicBlock> worklist, Value value) {
BasicBlock block = null;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
index f68af70..e0ca9093 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -305,7 +305,7 @@
IRCode code = method.buildIR(appView, origin);
codeOptimizations.forEach(codeOptimization -> codeOptimization.accept(code, methodProcessor));
CodeRewriter.removeAssumeInstructions(appView, code);
- converter.finalizeIR(method, code, feedback, Timing.empty());
+ converter.removeDeadCodeAndFinalizeIR(method, code, feedback, Timing.empty());
}
private void insertAssumeInstructions(IRCode code, MethodProcessor methodProcessor) {