[llvm] 0b28d75 - [ConstraintElimination] Add support for EQ predicates.

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 1 12:53:52 PST 2021


Author: Florian Hahn
Date: 2021-02-01T20:48:31Z
New Revision: 0b28d756af183b9f294ddca5432a0ad5054ac9c2

URL: https://github.com/llvm/llvm-project/commit/0b28d756af183b9f294ddca5432a0ad5054ac9c2
DIFF: https://github.com/llvm/llvm-project/commit/0b28d756af183b9f294ddca5432a0ad5054ac9c2.diff

LOG: [ConstraintElimination] Add support for EQ predicates.

A == B map to A >= B && A <= B
(https://alive2.llvm.org/ce/z/_dwxKn).

This extends the constraint construction to return a list of
constraints, which can be used to properly de-compose nested AND & OR.

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
    llvm/test/Transforms/ConstraintElimination/eq.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index dc105e4eaaa7..84c3ec98b029 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -92,10 +92,19 @@ static SmallVector<std::pair<int64_t, Value *>, 4> decompose(Value *V) {
   return {{0, nullptr}, {1, V}};
 }
 
+struct ConstraintTy {
+  SmallVector<int64_t, 8> Coefficients;
+
+  ConstraintTy(SmallVector<int64_t, 8> Coefficients)
+      : Coefficients(Coefficients) {}
+
+  unsigned size() const { return Coefficients.size(); }
+};
+
 /// Turn a condition \p CmpI into a constraint vector, using indices from \p
 /// Value2Index. If \p ShouldAdd is true, new indices are added for values not
 /// yet in \p Value2Index.
-static SmallVector<int64_t, 8>
+static SmallVector<ConstraintTy, 4>
 getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
               DenseMap<Value *, unsigned> &Value2Index, bool ShouldAdd) {
   int64_t Offset1 = 0;
@@ -117,6 +126,13 @@ getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
     return getConstraint(CmpInst::getSwappedPredicate(Pred), Op1, Op0,
                          Value2Index, ShouldAdd);
 
+  if (Pred == CmpInst::ICMP_EQ) {
+    auto A = getConstraint(CmpInst::ICMP_UGE, Op0, Op1, Value2Index, ShouldAdd);
+    auto B = getConstraint(CmpInst::ICMP_ULE, Op0, Op1, Value2Index, ShouldAdd);
+    append_range(A, B);
+    return A;
+  }
+
   // Only ULE and ULT predicates are supported at the moment.
   if (Pred != CmpInst::ICMP_ULE && Pred != CmpInst::ICMP_ULT)
     return {};
@@ -156,10 +172,10 @@ getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
     R[Value2Index[KV.second]] -= KV.first;
 
   R[0] = Offset1 + Offset2 + (Pred == CmpInst::ICMP_ULT ? -1 : 0);
-  return R;
+  return {R};
 }
 
-static SmallVector<int64_t, 8>
+static SmallVector<ConstraintTy, 4>
 getConstraint(CmpInst *Cmp, DenseMap<Value *, unsigned> &Value2Index,
               bool ShouldAdd) {
   return getConstraint(Cmp->getPredicate(), Cmp->getOperand(0),
@@ -301,9 +317,9 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
         if (!Cmp)
           continue;
         auto R = getConstraint(Cmp, Value2Index, false);
-        if (R.empty() || R.size() == 1)
+        if (R.size() != 1 || R[0].size() == 1)
           continue;
-        if (CS.isConditionImplied(R)) {
+        if (CS.isConditionImplied(R[0].Coefficients)) {
           if (!DebugCounter::shouldExecute(EliminatedCounter))
             continue;
 
@@ -318,7 +334,8 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
           NumCondsRemoved++;
           Changed = true;
         }
-        if (CS.isConditionImplied(ConstraintSystem::negate(R))) {
+        if (CS.isConditionImplied(
+                ConstraintSystem::negate(R[0].Coefficients))) {
           if (!DebugCounter::shouldExecute(EliminatedCounter))
             continue;
 
@@ -360,11 +377,16 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
       continue;
 
     LLVM_DEBUG(dbgs() << "Adding " << *CB.Condition << " " << CB.Not << "\n");
-
-    // If R has been added to the system, queue it for removal once it goes
-    // out-of-scope.
-    if (CS.addVariableRowFill(R))
-      DFSInStack.emplace_back(CB.NumIn, CB.NumOut, CB.Condition, CB.Not);
+    bool Added = false;
+    for (auto &C : R) {
+      auto Coeffs = C.Coefficients;
+
+      Added |= CS.addVariableRowFill(Coeffs);
+      // If R has been added to the system, queue it for removal once it goes
+      // out-of-scope.
+      if (Added)
+        DFSInStack.emplace_back(CB.NumIn, CB.NumOut, CB.Condition, CB.Not);
+    }
   }
 
   assert(CS.size() == DFSInStack.size() &&

diff  --git a/llvm/test/Transforms/ConstraintElimination/eq.ll b/llvm/test/Transforms/ConstraintElimination/eq.ll
index 4015d75cb2e5..9f47f9cee1d2 100644
--- a/llvm/test/Transforms/ConstraintElimination/eq.ll
+++ b/llvm/test/Transforms/ConstraintElimination/eq.ll
@@ -9,15 +9,15 @@ define i1 @test_eq_1(i8 %a, i8 %b) {
 ; CHECK:       then:
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp uge i8 [[A]], [[B]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ule i8 [[A]], [[B]]
-; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[RES_1:%.*]] = xor i1 true, true
 ; CHECK-NEXT:    [[T_3:%.*]] = icmp eq i8 [[A]], [[B]]
 ; CHECK-NEXT:    [[RES_2:%.*]] = xor i1 [[RES_1]], [[T_3]]
 ; CHECK-NEXT:    [[T_4:%.*]] = icmp eq i8 [[B]], [[A]]
 ; CHECK-NEXT:    [[RES_3:%.*]] = xor i1 [[RES_2]], [[T_4]]
 ; CHECK-NEXT:    [[F_1:%.*]] = icmp ugt i8 [[B]], [[A]]
-; CHECK-NEXT:    [[RES_4:%.*]] = xor i1 [[RES_3]], [[F_1]]
+; CHECK-NEXT:    [[RES_4:%.*]] = xor i1 [[RES_3]], false
 ; CHECK-NEXT:    [[F_2:%.*]] = icmp ult i8 [[B]], [[A]]
-; CHECK-NEXT:    [[RES_5:%.*]] = xor i1 [[RES_4]], [[F_2]]
+; CHECK-NEXT:    [[RES_5:%.*]] = xor i1 [[RES_4]], false
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i8 [[B]], 99
 ; CHECK-NEXT:    [[RES_6:%.*]] = xor i1 [[RES_5]], [[C_1]]
 ; CHECK-NEXT:    ret i1 [[RES_6]]
@@ -95,13 +95,13 @@ define i1 @test_eq_2(i8 %a, i8 %b) {
 ; CHECK:       then.then:
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ult i8 [[A]], 100
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult i8 [[B]], 100
-; CHECK-NEXT:    [[XOR_1:%.*]] = xor i1 [[T_1]], true
+; CHECK-NEXT:    [[XOR_1:%.*]] = xor i1 true, true
 ; CHECK-NEXT:    [[F_1:%.*]] = icmp uge i8 [[A]], 100
-; CHECK-NEXT:    [[XOR_2:%.*]] = xor i1 [[XOR_1]], [[F_1]]
+; CHECK-NEXT:    [[XOR_2:%.*]] = xor i1 [[XOR_1]], false
 ; CHECK-NEXT:    [[F_2:%.*]] = icmp uge i8 [[B]], 100
 ; CHECK-NEXT:    [[XOR_3:%.*]] = xor i1 [[XOR_2]], false
 ; CHECK-NEXT:    [[F_3_1:%.*]] = icmp ugt i8 [[A]], 99
-; CHECK-NEXT:    [[XOR_4:%.*]] = xor i1 [[XOR_3]], [[F_3_1]]
+; CHECK-NEXT:    [[XOR_4:%.*]] = xor i1 [[XOR_3]], false
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i8 [[A]], 99
 ; CHECK-NEXT:    [[XOR_5:%.*]] = xor i1 [[XOR_4]], [[C_1]]
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ugt i8 [[A]], 98
@@ -110,17 +110,17 @@ define i1 @test_eq_2(i8 %a, i8 %b) {
 ; CHECK:       then.else:
 ; CHECK-NEXT:    [[F_4:%.*]] = icmp ult i8 [[A]], 100
 ; CHECK-NEXT:    [[F_5:%.*]] = icmp ult i8 [[B]], 100
-; CHECK-NEXT:    [[XOR_7:%.*]] = xor i1 [[F_4]], false
+; CHECK-NEXT:    [[XOR_7:%.*]] = xor i1 false, false
 ; CHECK-NEXT:    [[T_3:%.*]] = icmp uge i8 [[A]], 100
-; CHECK-NEXT:    [[XOR_8:%.*]] = xor i1 [[XOR_7]], [[T_3]]
+; CHECK-NEXT:    [[XOR_8:%.*]] = xor i1 [[XOR_7]], true
 ; CHECK-NEXT:    [[T_4:%.*]] = icmp uge i8 [[B]], 100
 ; CHECK-NEXT:    [[XOR_9:%.*]] = xor i1 [[XOR_8]], true
 ; CHECK-NEXT:    [[T_5:%.*]] = icmp ugt i8 [[A]], 99
-; CHECK-NEXT:    [[XOR_10:%.*]] = xor i1 [[XOR_9]], [[T_5]]
+; CHECK-NEXT:    [[XOR_10:%.*]] = xor i1 [[XOR_9]], true
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp ult i8 [[A]], 99
-; CHECK-NEXT:    [[XOR_11:%.*]] = xor i1 [[XOR_10]], [[C_3]]
+; CHECK-NEXT:    [[XOR_11:%.*]] = xor i1 [[XOR_10]], false
 ; CHECK-NEXT:    [[C_4:%.*]] = icmp ugt i8 [[A]], 98
-; CHECK-NEXT:    [[XOR_12:%.*]] = xor i1 [[XOR_11]], [[C_4]]
+; CHECK-NEXT:    [[XOR_12:%.*]] = xor i1 [[XOR_11]], true
 ; CHECK-NEXT:    ret i1 [[XOR_12]]
 ; CHECK:       else:
 ; CHECK-NEXT:    [[CMP_2:%.*]] = icmp ult i8 [[A]], 100
@@ -298,13 +298,13 @@ define i1 @test_eq_ult_and(i8 %a, i8 %b) {
 ; CHECK:       then:
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ult i8 [[A]], 100
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult i8 [[B]], 100
-; CHECK-NEXT:    [[XOR_1:%.*]] = xor i1 [[T_1]], true
+; CHECK-NEXT:    [[XOR_1:%.*]] = xor i1 true, true
 ; CHECK-NEXT:    [[F_1:%.*]] = icmp uge i8 [[A]], 100
-; CHECK-NEXT:    [[XOR_2:%.*]] = xor i1 [[XOR_1]], [[F_1]]
+; CHECK-NEXT:    [[XOR_2:%.*]] = xor i1 [[XOR_1]], false
 ; CHECK-NEXT:    [[F_2:%.*]] = icmp uge i8 [[B]], 100
 ; CHECK-NEXT:    [[XOR_3:%.*]] = xor i1 [[XOR_2]], false
 ; CHECK-NEXT:    [[F_3_1:%.*]] = icmp ugt i8 [[A]], 99
-; CHECK-NEXT:    [[XOR_4:%.*]] = xor i1 [[XOR_3]], [[F_3_1]]
+; CHECK-NEXT:    [[XOR_4:%.*]] = xor i1 [[XOR_3]], false
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i8 [[A]], 99
 ; CHECK-NEXT:    [[XOR_5:%.*]] = xor i1 [[XOR_4]], [[C_1]]
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ugt i8 [[A]], 98


        


More information about the llvm-commits mailing list