Merge "Add extensive logging for debugging"
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 20c04ab..3d1f080 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
@@ -509,6 +509,8 @@
// 2) Perform outlining for the collected candidates.
// Ideally, we should outline eagerly when threshold for a template has been reached.
+ printPhase("Primary optimization pass");
+
// Process the application identifying outlining candidates.
OptimizationFeedbackDelayed feedback = new OptimizationFeedbackDelayed();
{
@@ -533,30 +535,39 @@
// TODO(b/112831361): Implement support for staticizeClasses in CF backend.
if (!options.isGeneratingClassFiles()) {
+ printPhase("Class staticizer post processing");
staticizeClasses(feedback, executorService);
}
// Second inlining pass for dealing with double inline callers.
if (inliner != null) {
+ printPhase("Double caller inlining");
// Use direct feedback still, since methods after inlining may
// change their status or other properties.
inliner.processDoubleInlineCallers(this, feedback);
}
+ printPhase("Lambda class synthesis");
synthesizeLambdaClasses(builder, executorService);
- desugarInterfaceMethods(builder, IncludeAllResources, executorService);
- synthesizeTwrCloseResourceUtilityClass(builder);
+ printPhase("Interface method desugaring");
+ desugarInterfaceMethods(builder, IncludeAllResources, executorService);
+
+ printPhase("Twr close resource utility class synthesis");
+ synthesizeTwrCloseResourceUtilityClass(builder);
handleSynthesizedClassMapping(builder);
+
+ printPhase("Lambda merging finalization");
finalizeLambdaMerging(application, feedback, builder, executorService);
if (outliner != null) {
+ printPhase("Outlining");
timing.begin("IR conversion phase 2");
if (outliner.selectMethodsForOutlining()) {
forEachSelectedOutliningMethod(
executorService,
(code, method) -> {
- printMethod(code, "IR before outlining (SSA)");
+ printMethod(code, "IR before outlining (SSA)", null);
outliner.identifyOutlineSites(code, method);
});
DexProgramClass outlineClass = outliner.buildOutlinerClass(computeOutlineClassType());
@@ -565,7 +576,7 @@
executorService,
(code, method) -> {
outliner.applyOutliningCandidate(code, method);
- printMethod(code, "IR after outlining (SSA)");
+ printMethod(code, "IR after outlining (SSA)", null);
finalizeIR(method, code, ignoreOptimizationFeedback);
});
assert outliner.checkAllOutlineSitesFoundAgain();
@@ -831,7 +842,7 @@
}
// Compilation header if printing CFGs for this method.
printC1VisualizerHeader(method);
- printMethod(code, "Initial IR (SSA)");
+ String previous = printMethod(code, "Initial IR (SSA)", null);
if (method.getCode() != null && method.getCode().isJarCode()) {
computeKotlinNonNullParamHints(feedback, method, code);
@@ -879,6 +890,8 @@
assert code.isConsistentSSA();
}
+ previous = printMethod(code, "IR after class staticizer (SSA)", previous);
+
if (identifierNameStringMarker != null) {
identifierNameStringMarker.decoupleIdentifierNameStringsInMethod(method, code);
assert code.isConsistentSSA();
@@ -903,6 +916,8 @@
inliner.performInlining(method, code, isProcessedConcurrently, callSiteInformation);
}
+ previous = printMethod(code, "IR after inlining (SSA)", previous);
+
if (appInfo.hasLiveness()) {
// Reflection optimization 1. getClass() -> const-class
ReflectionOptimizer.rewriteGetClass(appInfo.withLiveness(), code);
@@ -982,8 +997,12 @@
assert code.isConsistentSSA();
}
+ previous = printMethod(code, "IR after lambda desugaring (SSA)", previous);
+
assert code.verifyTypes(appInfo, appView, graphLense());
+ previous = printMethod(code, "IR before class inlining (SSA)", previous);
+
if (classInliner != null) {
// Class inliner should work before lambda merger, so if it inlines the
// lambda, it does not get collected by merger.
@@ -1000,25 +1019,35 @@
assert code.isConsistentSSA();
}
+ previous = printMethod(code, "IR after class inlining (SSA)", previous);
+
if (interfaceMethodRewriter != null) {
interfaceMethodRewriter.rewriteMethodReferences(method, code);
assert code.isConsistentSSA();
}
+ previous = printMethod(code, "IR after interface method rewriting (SSA)", previous);
+
if (twrCloseResourceRewriter != null) {
twrCloseResourceRewriter.rewriteMethodCode(code);
}
+ previous = printMethod(code, "IR after twr close resource rewriter (SSA)", previous);
+
if (lambdaMerger != null) {
lambdaMerger.processMethodCode(method, code);
assert code.isConsistentSSA();
}
+ previous = printMethod(code, "IR after lambda merger (SSA)", previous);
+
if (options.outline.enabled) {
outlineHandler.accept(code, method);
assert code.isConsistentSSA();
}
+ previous = printMethod(code, "IR after outline handler (SSA)", previous);
+
// TODO(mkroghj) Test if shorten live ranges is worth it.
if (!options.isGeneratingClassFiles()) {
ConstantCanonicalizer.canonicalize(code);
@@ -1027,10 +1056,14 @@
}
idempotentFunctionCallCanonicalizer.canonicalize(code);
+ previous =
+ printMethod(code, "IR after idempotent function call canonicalization (SSA)", previous);
+
codeRewriter.identifyReturnsArgument(method, code, feedback);
if (options.enableInlining && inliner != null) {
codeRewriter.identifyInvokeSemanticsForInlining(method, code, feedback);
}
+
// If hints from Kotlin metadata or use of Kotlin Intrinsics were not available, track usage of
// parameters and compute their nullability.
if (method.getOptimizationInfo().getNonNullParamHints() == null) {
@@ -1043,8 +1076,13 @@
assert code.isConsistentSSA();
}
+ previous = printMethod(code, "IR after argument type logging (SSA)", previous);
+
// Analysis must be done after method is rewritten by logArgumentTypes()
codeRewriter.identifyClassInlinerEligibility(method, code, feedback);
+
+ previous = printMethod(code, "IR after class inliner eligibility (SSA)", previous);
+
if (method.isInstanceInitializer() || method.isClassInitializer()) {
codeRewriter.identifyTrivialInitializer(method, code, feedback);
}
@@ -1057,7 +1095,7 @@
codeRewriter.workaroundNumberConversionRegisterAllocationBug(code);
}
- printMethod(code, "Optimized IR (SSA)");
+ printMethod(code, "Optimized IR (SSA)", previous);
finalizeIR(method, code, feedback);
}
@@ -1174,7 +1212,7 @@
Log.debug(getClass(), "Resulting dex code for %s:\n%s",
method.toSourceString(), logCode(options, method));
}
- printMethod(code, "Final IR (non-SSA)");
+ printMethod(code, "Final IR (non-SSA)", null);
markProcessed(method, code, feedback);
}
@@ -1213,7 +1251,7 @@
if (options.canHaveExceptionTargetingLoopHeaderBug()) {
codeRewriter.workaroundExceptionTargetingLoopHeaderBug(code);
}
- printMethod(code, "After register allocation (non-SSA)");
+ printMethod(code, "After register allocation (non-SSA)", null);
for (int i = 0; i < PEEPHOLE_OPTIMIZATION_PASSES; i++) {
CodeRewriter.collapseTrivialGotos(method, code);
PeepholeOptimizer.optimize(code, registerAllocator);
@@ -1399,7 +1437,13 @@
}
}
- private void printMethod(IRCode code, String title) {
+ private void printPhase(String phase) {
+ if (!options.extensiveLoggingFilter.isEmpty()) {
+ System.out.println("Entering phase: " + phase);
+ }
+ }
+
+ private String printMethod(IRCode code, String title, String previous) {
if (printer != null) {
printer.resetUnusedValue();
printer.begin("cfg");
@@ -1407,5 +1451,20 @@
code.print(printer);
printer.end("cfg");
}
+ if (options.extensiveLoggingFilter.contains(code.method.method.toSourceString())) {
+ String current = code.toString();
+ System.out.println();
+ System.out.println("-----------------------------------------------------------------------");
+ System.out.println(title);
+ System.out.println("-----------------------------------------------------------------------");
+ if (previous != null && previous.equals(current)) {
+ System.out.println("Unchanged");
+ } else {
+ System.out.println(current);
+ }
+ System.out.println("-----------------------------------------------------------------------");
+ return current;
+ }
+ return previous;
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index d8f4dba..fe187d7 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -25,6 +25,7 @@
import com.android.tools.r8.utils.IROrdering.IdentityIROrdering;
import com.android.tools.r8.utils.IROrdering.NondeterministicIROrdering;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
@@ -207,6 +208,7 @@
}
}
+ public Set<String> extensiveLoggingFilter = getExtensiveLoggingFilter();
public List<String> methodsFilter = ImmutableList.of();
public int minApiLevel = AndroidApiLevel.getDefault().getLevel();
// Skipping min_api check and compiling an intermediate result intended for later merging.
@@ -265,6 +267,18 @@
public LineNumberOptimization lineNumberOptimization = LineNumberOptimization.ON;
+ private static Set<String> getExtensiveLoggingFilter() {
+ String property = System.getProperty("com.android.tools.r8.extensiveLoggingFilter");
+ if (property != null) {
+ ImmutableSet.Builder<String> builder = ImmutableSet.builder();
+ for (String method : property.split(";")) {
+ builder.add(method);
+ }
+ return builder.build();
+ }
+ return ImmutableSet.of();
+ }
+
public static class InvalidParameterAnnotationInfo {
final DexMethod method;