Introduce base class for computation tree building

Change-Id: Ic41526c33af976c5298bfe627c0b9ce333c308c5
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 3d61f0e..12c6309 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
@@ -47,6 +47,6 @@
         PathConstraintAnalysisState.bottom(),
         code,
         new PathConstraintAnalysisTransferFunction(
-            appView.abstractValueFactory(), code.context(), methodParameterFactory));
+            appView, code, 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 c61df2a..97bb2d6 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
@@ -3,31 +3,34 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.analysis.path;
 
+import com.android.tools.r8.graph.AppView;
 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.ConcretePathConstraintAnalysisState;
 import com.android.tools.r8.ir.analysis.path.state.PathConstraintAnalysisState;
-import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
 import com.android.tools.r8.ir.code.BasicBlock;
+import com.android.tools.r8.ir.code.IRCode;
 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;
+import com.android.tools.r8.optimize.argumentpropagation.computation.DefaultComputationTreeBuilder;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 
 public class PathConstraintAnalysisTransferFunction
     implements AbstractTransferFunction<BasicBlock, Instruction, PathConstraintAnalysisState> {
 
-  private final ComputationTreeBuilder computationTreeBuilder;
+  private final DefaultComputationTreeBuilder computationTreeBuilder;
 
   PathConstraintAnalysisTransferFunction(
-      AbstractValueFactory abstractValueFactory,
+      AppView<AppInfoWithLiveness> appView,
+      IRCode code,
       ProgramMethod method,
       MethodParameterFactory methodParameterFactory) {
     computationTreeBuilder =
-        new ComputationTreeBuilder(abstractValueFactory, method, methodParameterFactory);
+        new DefaultComputationTreeBuilder(appView, code, method, methodParameterFactory);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstructionOrPhi.java b/src/main/java/com/android/tools/r8/ir/code/InstructionOrPhi.java
index 0ae5aaf..34d9483 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstructionOrPhi.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstructionOrPhi.java
@@ -4,27 +4,4 @@
 
 package com.android.tools.r8.ir.code;
 
-public interface InstructionOrPhi {
-
-  default boolean isInstruction() {
-    return false;
-  }
-
-  default Instruction asInstruction() {
-    return null;
-  }
-
-  default boolean isPhi() {
-    return false;
-  }
-
-  default boolean isStackMapPhi() {
-    return false;
-  }
-
-  default Phi asPhi() {
-    return null;
-  }
-
-  BasicBlock getBlock();
-}
+public interface InstructionOrPhi extends InstructionOrValue {}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstructionOrValue.java b/src/main/java/com/android/tools/r8/ir/code/InstructionOrValue.java
new file mode 100644
index 0000000..b45fd92
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/code/InstructionOrValue.java
@@ -0,0 +1,33 @@
+// 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.ir.code;
+
+public interface InstructionOrValue {
+
+  default boolean isInstruction() {
+    return false;
+  }
+
+  default Instruction asInstruction() {
+    return null;
+  }
+
+  default boolean isPhi() {
+    return false;
+  }
+
+  default boolean isStackMapPhi() {
+    return false;
+  }
+
+  default Phi asPhi() {
+    return null;
+  }
+
+  default Value asValue() {
+    return null;
+  }
+
+  BasicBlock getBlock();
+}
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 5fc512f..d08946f 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
@@ -51,7 +51,7 @@
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 
-public class Value implements Comparable<Value> {
+public class Value implements Comparable<Value>, InstructionOrValue {
 
   public void constrainType(
       ValueTypeConstraint constraint, ProgramMethod method, Reporter reporter) {
@@ -789,6 +789,11 @@
   }
 
   @Override
+  public Value asValue() {
+    return this;
+  }
+
+  @Override
   public int compareTo(Value value) {
     return Integer.compare(this.number, value.number);
   }
@@ -943,14 +948,6 @@
     return predicate.test(definition);
   }
 
-  public boolean isPhi() {
-    return false;
-  }
-
-  public Phi asPhi() {
-    return null;
-  }
-
   /**
    * Returns whether this value is known to never be <code>null</code>.
    */
@@ -1120,6 +1117,7 @@
     return definition.hasBlock();
   }
 
+  @Override
   public BasicBlock getBlock() {
     return definition.getBlock();
   }
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 74804a2..a2a899b 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
@@ -3,102 +3,76 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.optimize.argumentpropagation.computation;
 
-import static com.android.tools.r8.ir.code.Opcodes.AND;
-import static com.android.tools.r8.ir.code.Opcodes.ARGUMENT;
-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.AppView;
 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;
-import com.android.tools.r8.ir.code.And;
-import com.android.tools.r8.ir.code.Argument;
-import com.android.tools.r8.ir.code.ConstNumber;
-import com.android.tools.r8.ir.code.If;
+import com.android.tools.r8.ir.code.IRCode;
 import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionOrValue;
+import com.android.tools.r8.ir.code.Phi;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameterFactory;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.IdentityHashMap;
 import java.util.Map;
 
-public class ComputationTreeBuilder {
+public abstract class ComputationTreeBuilder {
 
-  private final AbstractValueFactory abstractValueFactory;
-  private final ProgramMethod method;
-  private final MethodParameterFactory methodParameterFactory;
+  final AppView<AppInfoWithLiveness> appView;
+  final IRCode code;
+  final ProgramMethod method;
+  final MethodParameterFactory methodParameterFactory;
 
-  private final Map<Instruction, ComputationTreeNode> cache = new IdentityHashMap<>();
+  private final Map<InstructionOrValue, ComputationTreeNode> cache = new IdentityHashMap<>();
 
   public ComputationTreeBuilder(
-      AbstractValueFactory abstractValueFactory,
+      AppView<AppInfoWithLiveness> appView,
+      IRCode code,
       ProgramMethod method,
       MethodParameterFactory methodParameterFactory) {
-    this.abstractValueFactory = abstractValueFactory;
+    this.appView = appView;
+    this.code = code;
     this.method = method;
     this.methodParameterFactory = methodParameterFactory;
   }
 
+  AbstractValueFactory factory() {
+    return appView.abstractValueFactory();
+  }
+
   // TODO(b/302281503): "Long lived" computation trees (i.e., the ones that survive past the IR
   //  conversion of the current method) should be canonicalized.
-  public ComputationTreeNode getOrBuildComputationTree(Instruction instruction) {
-    ComputationTreeNode existing = cache.get(instruction);
+  public final ComputationTreeNode getOrBuildComputationTree(
+      InstructionOrValue instructionOrValue) {
+    ComputationTreeNode existing = cache.get(instructionOrValue);
     if (existing != null) {
       return existing;
     }
-    ComputationTreeNode result = buildComputationTree(instruction);
-    cache.put(instruction, result);
+    ComputationTreeNode result = buildComputationTree(instructionOrValue);
+    cache.put(instructionOrValue, result);
     return result;
   }
 
-  private ComputationTreeNode buildComputationTree(Instruction instruction) {
-    switch (instruction.opcode()) {
-      case AND:
-        {
-          And and = instruction.asAnd();
-          ComputationTreeNode left = buildComputationTreeFromValue(and.leftValue());
-          ComputationTreeNode right = buildComputationTreeFromValue(and.rightValue());
-          return ComputationTreeLogicalBinopAndNode.create(left, right);
-        }
-      case ARGUMENT:
-        {
-          Argument argument = instruction.asArgument();
-          if (argument.getOutType().isInt()) {
-            return methodParameterFactory.create(method, argument.getIndex());
-          }
-          break;
-        }
-      case CONST_NUMBER:
-        {
-          ConstNumber constNumber = instruction.asConstNumber();
-          if (constNumber.getOutType().isInt()) {
-            return constNumber.getAbstractValue(abstractValueFactory);
-          }
-          break;
-        }
-      case IF:
-        {
-          If theIf = instruction.asIf();
-          if (theIf.isZeroTest()) {
-            ComputationTreeNode operand = buildComputationTreeFromValue(theIf.lhs());
-            return ComputationTreeUnopCompareNode.create(operand, theIf.getType());
-          }
-          break;
-        }
-      default:
-        break;
+  private ComputationTreeNode buildComputationTree(InstructionOrValue instructionOrValue) {
+    if (instructionOrValue.isInstruction()) {
+      return buildComputationTree(instructionOrValue.asInstruction());
+    } else {
+      Value value = instructionOrValue.asValue();
+      if (value.isPhi()) {
+        return buildComputationTree(value.asPhi());
+      } else {
+        return buildComputationTree(value.getDefinition());
+      }
     }
-    return AbstractValue.unknown();
   }
 
-  private ComputationTreeNode buildComputationTreeFromValue(Value value) {
-    if (value.isPhi()) {
-      return unknown();
-    }
-    return getOrBuildComputationTree(value.getDefinition());
-  }
+  abstract ComputationTreeNode buildComputationTree(Instruction instruction);
 
-  private static UnknownValue unknown() {
+  abstract ComputationTreeNode buildComputationTree(Phi phi);
+
+  static UnknownValue unknown() {
     return AbstractValue.unknown();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/DefaultComputationTreeBuilder.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/DefaultComputationTreeBuilder.java
new file mode 100644
index 0000000..36d7ca9
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/computation/DefaultComputationTreeBuilder.java
@@ -0,0 +1,78 @@
+// 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 static com.android.tools.r8.ir.code.Opcodes.AND;
+import static com.android.tools.r8.ir.code.Opcodes.ARGUMENT;
+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.AppView;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.code.And;
+import com.android.tools.r8.ir.code.Argument;
+import com.android.tools.r8.ir.code.ConstNumber;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.If;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.Phi;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameterFactory;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+
+public class DefaultComputationTreeBuilder extends ComputationTreeBuilder {
+
+  public DefaultComputationTreeBuilder(
+      AppView<AppInfoWithLiveness> appView,
+      IRCode code,
+      ProgramMethod method,
+      MethodParameterFactory methodParameterFactory) {
+    super(appView, code, method, methodParameterFactory);
+  }
+
+  @Override
+  ComputationTreeNode buildComputationTree(Instruction instruction) {
+    switch (instruction.opcode()) {
+      case AND:
+        {
+          And and = instruction.asAnd();
+          ComputationTreeNode left = getOrBuildComputationTree(and.leftValue());
+          ComputationTreeNode right = getOrBuildComputationTree(and.rightValue());
+          return ComputationTreeLogicalBinopAndNode.create(left, right);
+        }
+      case ARGUMENT:
+        {
+          Argument argument = instruction.asArgument();
+          if (argument.getOutType().isInt()) {
+            return methodParameterFactory.create(method, argument.getIndex());
+          }
+          break;
+        }
+      case CONST_NUMBER:
+        {
+          ConstNumber constNumber = instruction.asConstNumber();
+          if (constNumber.getOutType().isInt()) {
+            return constNumber.getAbstractValue(factory());
+          }
+          break;
+        }
+      case IF:
+        {
+          If theIf = instruction.asIf();
+          if (theIf.isZeroTest()) {
+            ComputationTreeNode operand = getOrBuildComputationTree(theIf.lhs());
+            return ComputationTreeUnopCompareNode.create(operand, theIf.getType());
+          }
+          break;
+        }
+      default:
+        break;
+    }
+    return unknown();
+  }
+
+  @Override
+  ComputationTreeNode buildComputationTree(Phi phi) {
+    return unknown();
+  }
+}