Use MethodParameter as open variable + add getSingleOpenVariable helper

Change-Id: Ib457ba13e7d49ba702cf893d89f91f42462b32e4
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/path/PathConstraintAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/path/PathConstraintAnalysis.java
index dd5b2c9..3d61f0e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/path/PathConstraintAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/path/PathConstraintAnalysis.java
@@ -7,6 +7,7 @@
 import com.android.tools.r8.ir.analysis.framework.intraprocedural.IntraproceduralDataflowAnalysis;
 import com.android.tools.r8.ir.analysis.path.state.PathConstraintAnalysisState;
 import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameterFactory;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 /**
@@ -37,11 +38,15 @@
 public class PathConstraintAnalysis
     extends IntraproceduralDataflowAnalysis<PathConstraintAnalysisState> {
 
-  public PathConstraintAnalysis(AppView<AppInfoWithLiveness> appView, IRCode code) {
+  public PathConstraintAnalysis(
+      AppView<AppInfoWithLiveness> appView,
+      IRCode code,
+      MethodParameterFactory methodParameterFactory) {
     super(
         appView,
         PathConstraintAnalysisState.bottom(),
         code,
-        new PathConstraintAnalysisTransferFunction(appView.abstractValueFactory()));
+        new PathConstraintAnalysisTransferFunction(
+            appView.abstractValueFactory(), code.context(), methodParameterFactory));
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/path/PathConstraintAnalysisTransferFunction.java b/src/main/java/com/android/tools/r8/ir/analysis/path/PathConstraintAnalysisTransferFunction.java
index 6b86310..794a9a6 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/path/PathConstraintAnalysisTransferFunction.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/path/PathConstraintAnalysisTransferFunction.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.ir.analysis.path;
 
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.framework.intraprocedural.AbstractTransferFunction;
 import com.android.tools.r8.ir.analysis.framework.intraprocedural.TransferFunctionResult;
 import com.android.tools.r8.ir.analysis.path.state.PathConstraintAnalysisState;
@@ -11,6 +12,7 @@
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.If;
 import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameterFactory;
 import com.android.tools.r8.optimize.argumentpropagation.computation.ComputationTreeBuilder;
 import com.android.tools.r8.optimize.argumentpropagation.computation.ComputationTreeNode;
 
@@ -19,8 +21,12 @@
 
   private final ComputationTreeBuilder computationTreeBuilder;
 
-  PathConstraintAnalysisTransferFunction(AbstractValueFactory abstractValueFactory) {
-    computationTreeBuilder = new ComputationTreeBuilder(abstractValueFactory);
+  PathConstraintAnalysisTransferFunction(
+      AbstractValueFactory abstractValueFactory,
+      ProgramMethod method,
+      MethodParameterFactory methodParameterFactory) {
+    computationTreeBuilder =
+        new ComputationTreeBuilder(abstractValueFactory, method, methodParameterFactory);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
index b83c92e..6350b1e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.lens.GraphLens;
 import com.android.tools.r8.ir.analysis.value.objectstate.ObjectState;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameter;
 import com.android.tools.r8.optimize.argumentpropagation.computation.ComputationTreeNode;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.function.IntFunction;
@@ -29,6 +30,11 @@
     return this;
   }
 
+  @Override
+  public MethodParameter getSingleOpenVariable() {
+    return null;
+  }
+
   public abstract boolean isNonTrivial();
 
   public boolean isSingleBoolean() {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodParameter.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodParameter.java
index 1c83bfa..138725e 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodParameter.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodParameter.java
@@ -7,10 +7,14 @@
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
+import com.android.tools.r8.optimize.argumentpropagation.computation.ComputationTreeNode;
 import com.android.tools.r8.utils.BooleanUtils;
 import java.util.Objects;
+import java.util.function.IntFunction;
 
-public class MethodParameter implements BaseInFlow {
+public class MethodParameter implements BaseInFlow, ComputationTreeNode {
 
   private final DexMethod method;
   private final int index;
@@ -43,11 +47,22 @@
     return index;
   }
 
+  @Override
+  public MethodParameter getSingleOpenVariable() {
+    return this;
+  }
+
   public DexType getType() {
     return method.getArgumentType(index, isMethodStatic);
   }
 
   @Override
+  public AbstractValue evaluate(
+      IntFunction<AbstractValue> argumentAssignment, AbstractValueFactory abstractValueFactory) {
+    return argumentAssignment.apply(index);
+  }
+
+  @Override
   public int internalCompareToSameKind(InFlow other) {
     MethodParameter methodParameter = other.asMethodParameter();
     int result = method.compareTo(methodParameter.method);
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeArgumentNode.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeArgumentNode.java
deleted file mode 100644
index 2ea279f..0000000
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeArgumentNode.java
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2024, 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.computation;
-
-import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
-import com.android.tools.r8.utils.ArrayUtils;
-import java.util.Objects;
-import java.util.function.IntFunction;
-
-/** Represents the read of an argument. */
-public class ComputationTreeArgumentNode extends ComputationTreeBaseNode {
-
-  private static final int NUM_CANONICALIZED_INSTANCES = 32;
-  private static final ComputationTreeArgumentNode[] CANONICALIZED_INSTANCES =
-      ArrayUtils.initialize(
-          new ComputationTreeArgumentNode[NUM_CANONICALIZED_INSTANCES],
-          ComputationTreeArgumentNode::new);
-
-  private final int argumentIndex;
-
-  private ComputationTreeArgumentNode(int argumentIndex) {
-    this.argumentIndex = argumentIndex;
-  }
-
-  public static ComputationTreeArgumentNode create(int argumentIndex) {
-    return argumentIndex < NUM_CANONICALIZED_INSTANCES
-        ? CANONICALIZED_INSTANCES[argumentIndex]
-        : new ComputationTreeArgumentNode(argumentIndex);
-  }
-
-  @Override
-  public AbstractValue evaluate(
-      IntFunction<AbstractValue> argumentAssignment, AbstractValueFactory abstractValueFactory) {
-    return argumentAssignment.apply(argumentIndex);
-  }
-
-  @Override
-  public boolean equals(Object obj) {
-    if (this == obj) {
-      return true;
-    }
-    if (!(obj instanceof ComputationTreeArgumentNode)) {
-      return false;
-    }
-    ComputationTreeArgumentNode node = (ComputationTreeArgumentNode) obj;
-    assert argumentIndex >= NUM_CANONICALIZED_INSTANCES
-        || node.argumentIndex >= NUM_CANONICALIZED_INSTANCES;
-    return argumentIndex == node.argumentIndex;
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(getClass(), argumentIndex);
-  }
-}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeBuilder.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeBuilder.java
index aca8a03..7e7b541 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeBuilder.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeBuilder.java
@@ -8,6 +8,7 @@
 import static com.android.tools.r8.ir.code.Opcodes.CONST_NUMBER;
 import static com.android.tools.r8.ir.code.Opcodes.IF;
 
+import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
 import com.android.tools.r8.ir.analysis.value.UnknownValue;
@@ -17,13 +18,21 @@
 import com.android.tools.r8.ir.code.If;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameterFactory;
 
 public class ComputationTreeBuilder {
 
   private final AbstractValueFactory abstractValueFactory;
+  private final ProgramMethod method;
+  private final MethodParameterFactory methodParameterFactory;
 
-  public ComputationTreeBuilder(AbstractValueFactory abstractValueFactory) {
+  public ComputationTreeBuilder(
+      AbstractValueFactory abstractValueFactory,
+      ProgramMethod method,
+      MethodParameterFactory methodParameterFactory) {
     this.abstractValueFactory = abstractValueFactory;
+    this.method = method;
+    this.methodParameterFactory = methodParameterFactory;
   }
 
   // TODO(b/302281503): "Long lived" computation trees (i.e., the ones that survive past the IR
@@ -44,7 +53,7 @@
         {
           Argument argument = instruction.asArgument();
           if (argument.getOutType().isInt()) {
-            return ComputationTreeArgumentNode.create(argument.getIndex());
+            return methodParameterFactory.create(method, argument.getIndex());
           }
           break;
         }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeLogicalBinopNode.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeLogicalBinopNode.java
index 8f0c95f..d7cf46b 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeLogicalBinopNode.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeLogicalBinopNode.java
@@ -4,6 +4,7 @@
 package com.android.tools.r8.optimize.argumentpropagation.computation;
 
 import com.android.tools.r8.ir.code.NumericType;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameter;
 
 public abstract class ComputationTreeLogicalBinopNode extends ComputationTreeBaseNode {
 
@@ -20,6 +21,15 @@
     return NumericType.INT;
   }
 
+  @Override
+  public final MethodParameter getSingleOpenVariable() {
+    MethodParameter openVariable = left.getSingleOpenVariable();
+    if (openVariable != null) {
+      return right.getSingleOpenVariable() == null ? openVariable : null;
+    }
+    return right.getSingleOpenVariable();
+  }
+
   boolean internalIsEqualTo(ComputationTreeLogicalBinopNode node) {
     return left.equals(node.left) && right.equals(node.right);
   }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeNode.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeNode.java
index f055cff..1231d76 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeNode.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeNode.java
@@ -5,6 +5,7 @@
 
 import com.android.tools.r8.ir.analysis.value.AbstractValue;
 import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameter;
 import java.util.function.IntFunction;
 
 /**
@@ -16,6 +17,8 @@
   AbstractValue evaluate(
       IntFunction<AbstractValue> argumentAssignment, AbstractValueFactory abstractValueFactory);
 
+  MethodParameter getSingleOpenVariable();
+
   default boolean isUnknown() {
     return false;
   }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeUnopNode.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeUnopNode.java
index 3c3fc1e..8ac1ca9 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeUnopNode.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/ComputationTreeUnopNode.java
@@ -3,6 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.optimize.argumentpropagation.computation;
 
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameter;
+
 public abstract class ComputationTreeUnopNode extends ComputationTreeBaseNode {
 
   final ComputationTreeNode operand;
@@ -12,6 +14,11 @@
     this.operand = operand;
   }
 
+  @Override
+  public MethodParameter getSingleOpenVariable() {
+    return operand.getSingleOpenVariable();
+  }
+
   boolean internalIsEqualTo(ComputationTreeUnopNode node) {
     return operand.equals(node.operand);
   }
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/path/PathConstraintAnalysisUnitTest.java b/src/test/java/com/android/tools/r8/ir/analysis/path/PathConstraintAnalysisUnitTest.java
index 56573a5..597cca6 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/path/PathConstraintAnalysisUnitTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/path/PathConstraintAnalysisUnitTest.java
@@ -17,6 +17,7 @@
 import com.android.tools.r8.ir.analysis.path.state.PathConstraintAnalysisState;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameterFactory;
 import com.android.tools.r8.optimize.argumentpropagation.computation.ComputationTreeNode;
 import com.android.tools.r8.optimize.argumentpropagation.computation.ComputationTreeUnopCompareNode;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -50,7 +51,8 @@
     CodeInspector inspector = new CodeInspector(app);
     IRCode code =
         inspector.clazz(Main.class).uniqueMethodWithOriginalName("greet").buildIR(appView);
-    PathConstraintAnalysis analysis = new PathConstraintAnalysis(appView, code);
+    PathConstraintAnalysis analysis =
+        new PathConstraintAnalysis(appView, code, new MethodParameterFactory());
     DataflowAnalysisResult result = analysis.run(code.entryBlock());
     assertTrue(result.isSuccessfulAnalysisResult());
     SuccessfulDataflowAnalysisResult<BasicBlock, PathConstraintAnalysisState> successfulResult =