High-level skeleton for new argument propagation

Bug: 190154391
Change-Id: I78b528ff2f546142d2ce788b749ed03821eb4b7e
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index b509c1f..225343b 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -28,6 +28,7 @@
 import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoFactory;
 import com.android.tools.r8.ir.optimize.library.LibraryMemberOptimizer;
 import com.android.tools.r8.ir.optimize.library.LibraryMethodSideEffectModelCollection;
+import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.KeepInfoCollection;
 import com.android.tools.r8.shaking.LibraryModeledPredicate;
@@ -84,6 +85,7 @@
   private final LibraryMethodSideEffectModelCollection libraryMethodSideEffectModelCollection;
 
   // Optimizations.
+  private final ArgumentPropagator argumentPropagator;
   private final CallSiteOptimizationInfoPropagator callSiteOptimizationInfoPropagator;
   private final LibraryMemberOptimizer libraryMemberOptimizer;
   private final ProtoShrinker protoShrinker;
@@ -121,9 +123,16 @@
     this.rewritePrefix = mapper;
 
     if (enableWholeProgramOptimizations() && options().callSiteOptimizationOptions().isEnabled()) {
-      this.callSiteOptimizationInfoPropagator =
-          new CallSiteOptimizationInfoPropagator(withLiveness());
+      if (options().callSiteOptimizationOptions().isExperimentalArgumentPropagationEnabled()) {
+        this.argumentPropagator = new ArgumentPropagator(withLiveness());
+        this.callSiteOptimizationInfoPropagator = null;
+      } else {
+        this.argumentPropagator = null;
+        this.callSiteOptimizationInfoPropagator =
+            new CallSiteOptimizationInfoPropagator(withLiveness());
+      }
     } else {
+      this.argumentPropagator = null;
       this.callSiteOptimizationInfoPropagator = null;
     }
 
@@ -323,6 +332,13 @@
     return callSiteOptimizationInfoPropagator;
   }
 
+  public <E extends Throwable> void withArgumentPropagator(
+      ThrowingConsumer<ArgumentPropagator, E> consumer) throws E {
+    if (argumentPropagator != null) {
+      consumer.accept(argumentPropagator);
+    }
+  }
+
   public <E extends Throwable> void withCallSiteOptimizationInfoPropagator(
       ThrowingConsumer<CallSiteOptimizationInfoPropagator, E> consumer) throws E {
     if (callSiteOptimizationInfoPropagator != null) {
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 b6e8153..4177124 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
@@ -98,6 +98,7 @@
 import com.android.tools.r8.ir.regalloc.RegisterAllocator;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.naming.IdentifierNameStringMarker;
+import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
 import com.android.tools.r8.position.MethodPosition;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.LibraryMethodOverrideAnalysis;
@@ -678,6 +679,8 @@
 
     printPhase("Primary optimization pass");
 
+    // Setup the argument propagator for the primary optimization pass.
+    appView.withArgumentPropagator(ArgumentPropagator::initializeCodeScanner);
     appView.withCallSiteOptimizationInfoPropagator(
         optimization -> {
           optimization.abandonCallSitePropagationForLambdaImplementationMethods(
@@ -723,11 +726,20 @@
     // Assure that no more optimization feedback left after primary processing.
     assert feedback.noUpdatesLeft();
     appView.setAllCodeProcessed();
+
     // All the code has been processed so the rewriting required by the lenses is done everywhere,
     // we clear lens code rewriting so that the lens rewriter can be re-executed in phase 2 if new
     // lenses with code rewriting are added.
     appView.clearCodeRewritings();
 
+    // Analyze the data collected by the argument propagator, use the analysis result to update
+    // the parameter optimization infos, and rewrite the application.
+    appView.withArgumentPropagator(
+        argumentPropagator -> {
+          argumentPropagator.populateParameterOptimizationInfo();
+          argumentPropagator.optimizeMethodParameters(postMethodProcessorBuilder);
+        });
+
     if (libraryMethodOverrideAnalysis != null) {
       libraryMethodOverrideAnalysis.finish();
     }
@@ -1612,6 +1624,8 @@
       MethodProcessor methodProcessor,
       MutableMethodConversionOptions conversionOptions,
       Timing timing) {
+    appView.withArgumentPropagator(
+        argumentPropagator -> argumentPropagator.scan(method, code, methodProcessor));
 
     if (enumUnboxer != null && methodProcessor.isPrimaryMethodProcessor()) {
       enumUnboxer.analyzeEnums(code, conversionOptions);
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
new file mode 100644
index 0000000..d7f5e52
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
@@ -0,0 +1,79 @@
+// Copyright (c) 2021, 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.optimize.argumentpropagation;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.conversion.PostMethodProcessor;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+
+/** Optimization that propagates information about arguments from call sites to method entries. */
+public class ArgumentPropagator {
+
+  private final AppView<AppInfoWithLiveness> appView;
+
+  /**
+   * Collects information about arguments from call sites, meanwhile pruning redundant information.
+   *
+   * <p>The data held by this instance is incomplete and should not be used for optimization until
+   * processed by {@link ArgumentPropagatorOptimizationInfoPopulator}.
+   */
+  private ArgumentPropagatorCodeScanner codeScanner;
+
+  public ArgumentPropagator(AppView<AppInfoWithLiveness> appView) {
+    assert appView.enableWholeProgramOptimizations();
+    assert appView.options().isOptimizing();
+    assert appView.options().callSiteOptimizationOptions().isEnabled();
+    assert appView
+        .options()
+        .callSiteOptimizationOptions()
+        .isExperimentalArgumentPropagationEnabled();
+    this.appView = appView;
+  }
+
+  /**
+   * Called by {@link IRConverter} *before* the primary optimization pass to setup the scanner for
+   * collecting argument information from the code objects.
+   */
+  public void initializeCodeScanner() {
+    codeScanner = new ArgumentPropagatorCodeScanner(appView);
+  }
+
+  /** Called by {@link IRConverter} prior to finalizing methods. */
+  public void scan(ProgramMethod method, IRCode code, MethodProcessor methodProcessor) {
+    if (codeScanner != null) {
+      // TODO(b/190154391): Do we process synthetic methods using a OneTimeMethodProcessor
+      //  during the primary optimization pass?
+      assert methodProcessor.isPrimaryMethodProcessor();
+      codeScanner.scan(method, code);
+    } else {
+      assert !methodProcessor.isPrimaryMethodProcessor();
+    }
+  }
+
+  /**
+   * Called by {@link IRConverter} *after* the primary optimization pass to populate the parameter
+   * optimization info.
+   */
+  public void populateParameterOptimizationInfo() {
+    assert appView.isAllCodeProcessed();
+    new ArgumentPropagatorOptimizationInfoPopulator()
+        .populateOptimizationInfo(codeScanner.getResult());
+    codeScanner = null;
+  }
+
+  /**
+   * Called by {@link IRConverter} to optimize method definitions. This also adds all methods that
+   * require reprocessing to {@param postMethodProcessorBuilder}.
+   */
+  public void optimizeMethodParameters(PostMethodProcessor.Builder postMethodProcessorBuilder) {
+    // TODO(b/190154391): Remove parameters with constant values.
+    // TODO(b/190154391): Remove unused parameters by simulating they are constant.
+    // TODO(b/190154391): Strengthen the static type of parameters.
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
new file mode 100644
index 0000000..7cb1c98
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
@@ -0,0 +1,64 @@
+// Copyright (c) 2021, 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.optimize.argumentpropagation;
+
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Analyzes each {@link IRCode} during the primary optimization to collect information about the
+ * arguments passed to method parameters.
+ *
+ * <p>State pruning is applied on-the-fly to avoid storing redundant information.
+ */
+class ArgumentPropagatorCodeScanner {
+
+  private final AppView<AppInfoWithLiveness> appView;
+
+  /**
+   * Maps each non-interface method to the upper most method in the super class chain with the same
+   * method signature. This only contains an entry for non-private virtual methods that override
+   * another method in the program.
+   */
+  private final Map<DexMethod, DexMethod> classMethodRoots;
+
+  /**
+   * The methods that are not subject to argument propagation. This includes (i) methods that are
+   * not subject to optimization due to -keep rules, (ii) classpath/library method overrides, and
+   * (iii) methods that are unlikely to benefit from argument propagation according to heuristics.
+   *
+   * <p>Argument propagation must also be disabled for lambda implementation methods unless we model
+   * the calls from lambda main methods synthesized by the JVM.
+   */
+  private final Set<DexMethod> unoptimizableMethods;
+
+  ArgumentPropagatorCodeScanner(AppView<AppInfoWithLiveness> appView) {
+    this.appView = appView;
+    this.classMethodRoots = computeClassMethodRoots();
+    this.unoptimizableMethods = computeUnoptimizableMethods();
+  }
+
+  private Map<DexMethod, DexMethod> computeClassMethodRoots() {
+    throw new Unimplemented();
+  }
+
+  private Set<DexMethod> computeUnoptimizableMethods() {
+    throw new Unimplemented();
+  }
+
+  ArgumentPropagatorCodeScannerResult getResult() {
+    throw new Unimplemented();
+  }
+
+  void scan(ProgramMethod method, IRCode code) {
+    throw new Unimplemented();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScannerResult.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScannerResult.java
new file mode 100644
index 0000000..4143bfb
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScannerResult.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2021, 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.optimize.argumentpropagation;
+
+public class ArgumentPropagatorCodeScannerResult {}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
new file mode 100644
index 0000000..d116411
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
@@ -0,0 +1,28 @@
+// Copyright (c) 2021, 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.optimize.argumentpropagation;
+
+import com.android.tools.r8.errors.Unimplemented;
+
+/**
+ * Propagates the argument flow information collected by the {@link ArgumentPropagatorCodeScanner}.
+ * This is needed to propagate argument information from call sites to all possible dispatch
+ * targets.
+ */
+public class ArgumentPropagatorOptimizationInfoPopulator {
+
+  /**
+   * Computes an over-approximation of each parameter's value and type and stores the result in
+   * {@link com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo}.
+   */
+  void populateOptimizationInfo(ArgumentPropagatorCodeScannerResult codeScannerResult) {
+    // TODO(b/190154391): Propagate argument information to handle virtual dispatch.
+    // TODO(b/190154391): To deal with arguments that are themselves passed as arguments to invoke
+    //  instructions, build a flow graph where nodes are parameters and there is an edge from a
+    //  parameter p1 to p2 if the value of p2 is at least the value of p1. Then propagate the
+    //  collected argument information throughout the flow graph.
+    throw new Unimplemented();
+  }
+}
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 0a9c18a..5b57a6e 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1247,6 +1247,10 @@
       return enableConstantPropagation || enableTypePropagation;
     }
 
+    public boolean isExperimentalArgumentPropagationEnabled() {
+      return false;
+    }
+
     public boolean isConstantPropagationEnabled() {
       return enableConstantPropagation;
     }