Introduce various constraints for simple inlining

This introduces a constraint that is always true, and constraints that are true if a specific argument is guaranteed to be either true, false, null, or non-null.

Bug: 132600418
Change-Id: I0db575dfded14ba71ff3c40c16e697bd2f25fca8
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 d51e21c..6bedacf 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -13,6 +13,7 @@
 import com.android.tools.r8.graph.classmerging.StaticallyMergedClasses;
 import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
 import com.android.tools.r8.horizontalclassmerging.HorizontallyMergedClasses;
+import com.android.tools.r8.ir.analysis.inlining.SimpleInliningConstraintFactory;
 import com.android.tools.r8.ir.analysis.proto.EnumLiteProtoShrinker;
 import com.android.tools.r8.ir.analysis.proto.GeneratedExtensionRegistryShrinker;
 import com.android.tools.r8.ir.analysis.proto.GeneratedMessageLiteBuilderShrinker;
@@ -67,6 +68,8 @@
   private final InstanceFieldInitializationInfoFactory instanceFieldInitializationInfoFactory =
       new InstanceFieldInitializationInfoFactory();
   private final MethodProcessingId.Factory methodProcessingIdFactory;
+  private final SimpleInliningConstraintFactory simpleInliningConstraintFactory =
+      new SimpleInliningConstraintFactory();
 
   // Desugaring.
   public final PrefixRewritingMapper rewritePrefix;
@@ -187,6 +190,10 @@
     return methodProcessingIdFactory;
   }
 
+  public SimpleInliningConstraintFactory simpleInliningConstraintFactory() {
+    return simpleInliningConstraintFactory;
+  }
+
   public T appInfo() {
     assert !appInfo.hasClassHierarchy() || enableWholeProgramOptimizations();
     return appInfo;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java
new file mode 100644
index 0000000..d92af89
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/AlwaysSimpleInliningConstraint.java
@@ -0,0 +1,30 @@
+// Copyright (c) 2020, 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.analysis.inlining;
+
+import com.android.tools.r8.ir.code.InvokeMethod;
+
+/** Constraint that is always satisfied. */
+public class AlwaysSimpleInliningConstraint extends SimpleInliningConstraint {
+
+  public static final AlwaysSimpleInliningConstraint INSTANCE =
+      new AlwaysSimpleInliningConstraint();
+
+  private AlwaysSimpleInliningConstraint() {}
+
+  public static AlwaysSimpleInliningConstraint getInstance() {
+    return INSTANCE;
+  }
+
+  @Override
+  public boolean isAlways() {
+    return true;
+  }
+
+  @Override
+  public boolean isSatisfied(InvokeMethod invoke) {
+    return false;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanFalseSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanFalseSimpleInliningConstraint.java
new file mode 100644
index 0000000..a568f38
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanFalseSimpleInliningConstraint.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2020, 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.analysis.inlining;
+
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.Value;
+
+/** Constraint that is satisfied if a specific argument is always false. */
+public class BooleanFalseSimpleInliningConstraint extends SimpleInliningArgumentConstraint {
+
+  private BooleanFalseSimpleInliningConstraint(int argumentIndex) {
+    super(argumentIndex);
+  }
+
+  static BooleanFalseSimpleInliningConstraint create(
+      int argumentIndex, SimpleInliningConstraintFactory witness) {
+    assert witness != null;
+    return new BooleanFalseSimpleInliningConstraint(argumentIndex);
+  }
+
+  @Override
+  public boolean isBooleanFalse() {
+    return true;
+  }
+
+  @Override
+  public boolean isSatisfied(InvokeMethod invoke) {
+    Value argument = getArgument(invoke);
+    assert argument.getType().isInt();
+    return argument.isConstBoolean(false);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanTrueSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanTrueSimpleInliningConstraint.java
new file mode 100644
index 0000000..37b61d7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/BooleanTrueSimpleInliningConstraint.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2020, 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.analysis.inlining;
+
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.Value;
+
+/** Constraint that is satisfied if a specific argument is always true. */
+public class BooleanTrueSimpleInliningConstraint extends SimpleInliningArgumentConstraint {
+
+  private BooleanTrueSimpleInliningConstraint(int argumentIndex) {
+    super(argumentIndex);
+  }
+
+  static BooleanTrueSimpleInliningConstraint create(
+      int argumentIndex, SimpleInliningConstraintFactory witness) {
+    assert witness != null;
+    return new BooleanTrueSimpleInliningConstraint(argumentIndex);
+  }
+
+  @Override
+  public boolean isBooleanTrue() {
+    return true;
+  }
+
+  @Override
+  public boolean isSatisfied(InvokeMethod invoke) {
+    Value argument = getArgument(invoke);
+    assert argument.getType().isInt();
+    return argument.isConstBoolean(true);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java
index 295f0c5..d3c0fca 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NeverSimpleInliningConstraint.java
@@ -6,6 +6,7 @@
 
 import com.android.tools.r8.ir.code.InvokeMethod;
 
+/** Constraint that is never satisfied. */
 public class NeverSimpleInliningConstraint extends SimpleInliningConstraint {
 
   public static final NeverSimpleInliningConstraint INSTANCE = new NeverSimpleInliningConstraint();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NotNullSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NotNullSimpleInliningConstraint.java
new file mode 100644
index 0000000..6ccf6ca
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NotNullSimpleInliningConstraint.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2020, 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.analysis.inlining;
+
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.Value;
+
+/** Constraint that is satisfied if a specific argument is always non-null. */
+public class NotNullSimpleInliningConstraint extends SimpleInliningArgumentConstraint {
+
+  private NotNullSimpleInliningConstraint(int argumentIndex) {
+    super(argumentIndex);
+  }
+
+  static NotNullSimpleInliningConstraint create(
+      int argumentIndex, SimpleInliningConstraintFactory witness) {
+    assert witness != null;
+    return new NotNullSimpleInliningConstraint(argumentIndex);
+  }
+
+  @Override
+  public boolean isNotNull() {
+    return true;
+  }
+
+  @Override
+  public boolean isSatisfied(InvokeMethod invoke) {
+    Value argument = getArgument(invoke);
+    assert argument.getType().isReferenceType() : invoke;
+    return argument.isNeverNull();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java
new file mode 100644
index 0000000..39cae4b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/NullSimpleInliningConstraint.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2020, 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.analysis.inlining;
+
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.Value;
+
+/** Constraint that is satisfied if a specific argument is always null. */
+public class NullSimpleInliningConstraint extends SimpleInliningArgumentConstraint {
+
+  private NullSimpleInliningConstraint(int argumentIndex) {
+    super(argumentIndex);
+  }
+
+  static NullSimpleInliningConstraint create(
+      int argumentIndex, SimpleInliningConstraintFactory witness) {
+    assert witness != null;
+    return new NullSimpleInliningConstraint(argumentIndex);
+  }
+
+  @Override
+  public boolean isNull() {
+    return true;
+  }
+
+  @Override
+  public boolean isSatisfied(InvokeMethod invoke) {
+    Value argument = getArgument(invoke);
+    assert argument.getType().isReferenceType();
+    return argument.getType().isDefinitelyNull();
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningArgumentConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningArgumentConstraint.java
new file mode 100644
index 0000000..d05b97e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningArgumentConstraint.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2020, 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.analysis.inlining;
+
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.Value;
+
+public abstract class SimpleInliningArgumentConstraint extends SimpleInliningConstraint {
+
+  private final int argumentIndex;
+
+  SimpleInliningArgumentConstraint(int argumentIndex) {
+    this.argumentIndex = argumentIndex;
+  }
+
+  Value getArgument(InvokeMethod invoke) {
+    return invoke.getArgument(argumentIndex);
+  }
+
+  int getArgumentIndex() {
+    return argumentIndex;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java
index 73bca62..1420223 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraint.java
@@ -8,9 +8,29 @@
 
 public abstract class SimpleInliningConstraint {
 
+  public boolean isAlways() {
+    return false;
+  }
+
+  public boolean isBooleanFalse() {
+    return false;
+  }
+
+  public boolean isBooleanTrue() {
+    return false;
+  }
+
   public boolean isNever() {
     return false;
   }
 
+  public boolean isNotNull() {
+    return false;
+  }
+
+  public boolean isNull() {
+    return false;
+  }
+
   public abstract boolean isSatisfied(InvokeMethod invoke);
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintFactory.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintFactory.java
new file mode 100644
index 0000000..1e3651a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintFactory.java
@@ -0,0 +1,40 @@
+// Copyright (c) 2020, 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.analysis.inlining;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class SimpleInliningConstraintFactory {
+
+  private final Map<Integer, BooleanFalseSimpleInliningConstraint> booleanFalseConstraints =
+      new ConcurrentHashMap<>();
+  private final Map<Integer, BooleanTrueSimpleInliningConstraint> booleanTrueConstraints =
+      new ConcurrentHashMap<>();
+  private final Map<Integer, NotNullSimpleInliningConstraint> notNullConstraints =
+      new ConcurrentHashMap<>();
+  private final Map<Integer, NullSimpleInliningConstraint> nullConstraints =
+      new ConcurrentHashMap<>();
+
+  public BooleanFalseSimpleInliningConstraint createBooleanFalseConstraint(int argumentIndex) {
+    return booleanFalseConstraints.computeIfAbsent(
+        argumentIndex, key -> BooleanFalseSimpleInliningConstraint.create(key, this));
+  }
+
+  public BooleanTrueSimpleInliningConstraint createBooleanTrueConstraint(int argumentIndex) {
+    return booleanTrueConstraints.computeIfAbsent(
+        argumentIndex, key -> BooleanTrueSimpleInliningConstraint.create(key, this));
+  }
+
+  public NotNullSimpleInliningConstraint createNotNullConstraint(int argumentIndex) {
+    return notNullConstraints.computeIfAbsent(
+        argumentIndex, key -> NotNullSimpleInliningConstraint.create(key, this));
+  }
+
+  public NullSimpleInliningConstraint createNullConstraint(int argumentIndex) {
+    return nullConstraints.computeIfAbsent(
+        argumentIndex, key -> NullSimpleInliningConstraint.create(key, this));
+  }
+}
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 b842c63..0f0d6e9 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
@@ -30,6 +30,7 @@
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.position.MethodPosition;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.LongInterval;
 import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.SetUtils;
@@ -778,6 +779,11 @@
     return isConstant() && getConstInstruction().isConstNumber();
   }
 
+  public boolean isConstBoolean(boolean value) {
+    return isConstNumber()
+        && definition.asConstNumber().getRawValue() == BooleanUtils.longValue(value);
+  }
+
   public boolean isConstZero() {
     return isConstNumber() && definition.asConstNumber().isZero();
   }