Introduce constraints to compose first-order simple inlining constraints

Change-Id: I85ba12382c8d0b54121c0b9ebcc15cd134d8afbf
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
index d05b97e..749d6f4 100644
--- 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
@@ -22,4 +22,9 @@
   int getArgumentIndex() {
     return argumentIndex;
   }
+
+  @Override
+  public boolean isArgumentConstraint() {
+    return true;
+  }
 }
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 1420223..db78fd2 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
@@ -5,6 +5,8 @@
 package com.android.tools.r8.ir.analysis.inlining;
 
 import com.android.tools.r8.ir.code.InvokeMethod;
+import com.google.common.collect.ImmutableList;
+import java.util.function.Supplier;
 
 public abstract class SimpleInliningConstraint {
 
@@ -12,6 +14,10 @@
     return false;
   }
 
+  public boolean isArgumentConstraint() {
+    return false;
+  }
+
   public boolean isBooleanFalse() {
     return false;
   }
@@ -20,6 +26,22 @@
     return false;
   }
 
+  public boolean isConjunction() {
+    return false;
+  }
+
+  public SimpleInliningConstraintConjunction asConjunction() {
+    return null;
+  }
+
+  public boolean isDisjunction() {
+    return false;
+  }
+
+  public SimpleInliningConstraintDisjunction asDisjunction() {
+    return null;
+  }
+
   public boolean isNever() {
     return false;
   }
@@ -33,4 +55,53 @@
   }
 
   public abstract boolean isSatisfied(InvokeMethod invoke);
+
+  public final SimpleInliningConstraint meet(SimpleInliningConstraint other) {
+    if (isAlways()) {
+      return other;
+    }
+    if (other.isAlways()) {
+      return this;
+    }
+    if (isNever() || other.isNever()) {
+      return NeverSimpleInliningConstraint.getInstance();
+    }
+    if (isConjunction()) {
+      return asConjunction().add(other);
+    }
+    if (other.isConjunction()) {
+      return other.asConjunction().add(this);
+    }
+    assert isArgumentConstraint() || isDisjunction();
+    assert other.isArgumentConstraint() || other.isDisjunction();
+    return new SimpleInliningConstraintConjunction(ImmutableList.of(this, other));
+  }
+
+  public final SimpleInliningConstraint lazyMeet(Supplier<SimpleInliningConstraint> supplier) {
+    if (isNever()) {
+      return NeverSimpleInliningConstraint.getInstance();
+    }
+    return meet(supplier.get());
+  }
+
+  public final SimpleInliningConstraint join(SimpleInliningConstraint other) {
+    if (isAlways() || other.isAlways()) {
+      return AlwaysSimpleInliningConstraint.getInstance();
+    }
+    if (isNever()) {
+      return other;
+    }
+    if (other.isNever()) {
+      return this;
+    }
+    if (isDisjunction()) {
+      return asDisjunction().add(other);
+    }
+    if (other.isDisjunction()) {
+      return other.asDisjunction().add(this);
+    }
+    assert isArgumentConstraint() || isConjunction();
+    assert other.isArgumentConstraint() || other.isConjunction();
+    return new SimpleInliningConstraintDisjunction(ImmutableList.of(this, other));
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java
new file mode 100644
index 0000000..ccc7400
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintConjunction.java
@@ -0,0 +1,65 @@
+// 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.google.common.collect.ImmutableList;
+import java.util.List;
+
+public class SimpleInliningConstraintConjunction extends SimpleInliningConstraint {
+
+  private final List<SimpleInliningConstraint> constraints;
+
+  public SimpleInliningConstraintConjunction(List<SimpleInliningConstraint> constraints) {
+    assert constraints.size() > 1;
+    assert constraints.stream().noneMatch(SimpleInliningConstraint::isAlways);
+    assert constraints.stream().noneMatch(SimpleInliningConstraint::isConjunction);
+    assert constraints.stream().noneMatch(SimpleInliningConstraint::isNever);
+    this.constraints = constraints;
+  }
+
+  SimpleInliningConstraint add(SimpleInliningConstraint constraint) {
+    assert !constraint.isAlways();
+    assert !constraint.isNever();
+    if (constraint.isConjunction()) {
+      return addAll(constraint.asConjunction());
+    }
+    assert constraint.isArgumentConstraint() || constraint.isDisjunction();
+    return new SimpleInliningConstraintConjunction(
+        ImmutableList.<SimpleInliningConstraint>builder()
+            .addAll(constraints)
+            .add(constraint)
+            .build());
+  }
+
+  public SimpleInliningConstraintConjunction addAll(
+      SimpleInliningConstraintConjunction conjunction) {
+    return new SimpleInliningConstraintConjunction(
+        ImmutableList.<SimpleInliningConstraint>builder()
+            .addAll(constraints)
+            .addAll(conjunction.constraints)
+            .build());
+  }
+
+  @Override
+  public boolean isConjunction() {
+    return true;
+  }
+
+  @Override
+  public SimpleInliningConstraintConjunction asConjunction() {
+    return this;
+  }
+
+  @Override
+  public boolean isSatisfied(InvokeMethod invoke) {
+    for (SimpleInliningConstraint constraint : constraints) {
+      if (!constraint.isSatisfied(invoke)) {
+        return false;
+      }
+    }
+    return true;
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java
new file mode 100644
index 0000000..f84e5cd
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/inlining/SimpleInliningConstraintDisjunction.java
@@ -0,0 +1,65 @@
+// 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.google.common.collect.ImmutableList;
+import java.util.List;
+
+public class SimpleInliningConstraintDisjunction extends SimpleInliningConstraint {
+
+  private final List<SimpleInliningConstraint> constraints;
+
+  public SimpleInliningConstraintDisjunction(List<SimpleInliningConstraint> constraints) {
+    assert constraints.size() > 1;
+    assert constraints.stream().noneMatch(SimpleInliningConstraint::isAlways);
+    assert constraints.stream().noneMatch(SimpleInliningConstraint::isDisjunction);
+    assert constraints.stream().noneMatch(SimpleInliningConstraint::isNever);
+    this.constraints = constraints;
+  }
+
+  SimpleInliningConstraint add(SimpleInliningConstraint constraint) {
+    assert !constraint.isAlways();
+    assert !constraint.isNever();
+    if (constraint.isDisjunction()) {
+      return addAll(constraint.asDisjunction());
+    }
+    assert constraint.isArgumentConstraint() || constraint.isConjunction();
+    return new SimpleInliningConstraintDisjunction(
+        ImmutableList.<SimpleInliningConstraint>builder()
+            .addAll(constraints)
+            .add(constraint)
+            .build());
+  }
+
+  public SimpleInliningConstraintDisjunction addAll(
+      SimpleInliningConstraintDisjunction disjunction) {
+    return new SimpleInliningConstraintDisjunction(
+        ImmutableList.<SimpleInliningConstraint>builder()
+            .addAll(constraints)
+            .addAll(disjunction.constraints)
+            .build());
+  }
+
+  @Override
+  public boolean isDisjunction() {
+    return true;
+  }
+
+  @Override
+  public SimpleInliningConstraintDisjunction asDisjunction() {
+    return this;
+  }
+
+  @Override
+  public boolean isSatisfied(InvokeMethod invoke) {
+    for (SimpleInliningConstraint constraint : constraints) {
+      if (constraint.isSatisfied(invoke)) {
+        return true;
+      }
+    }
+    return false;
+  }
+}