[llvm] 1f1f037 - [ConstraintElimination] Improve index handing during constraint building.

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 8 05:07:08 PST 2021


Author: Florian Hahn
Date: 2021-02-08T13:05:13Z
New Revision: 1f1f037ed3101d3074f65faceca81218c88a505c

URL: https://github.com/llvm/llvm-project/commit/1f1f037ed3101d3074f65faceca81218c88a505c
DIFF: https://github.com/llvm/llvm-project/commit/1f1f037ed3101d3074f65faceca81218c88a505c.diff

LOG: [ConstraintElimination] Improve index handing during constraint building.

This patch improves the index management during constraint building.
Previously, the code rejected constraints which used values that were not
part of Value2Index, but after combining the coefficients of the new
indices were 0 (if ShouldAdd was 0).

In those cases, no new indices need to be added. Instead of adding to
Value2Index directly, add new indices to the NewIndices map. The caller
can then check if it needs to add any new indices.

This enables checking constraints like `a + x <= a + n` to `x <= n`,
even if there is no constraint for `a` directly.

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
    llvm/test/Transforms/ConstraintElimination/decompose-with-temporary-indices.ll
    llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index eb82d67dcd79..46a56f4c31fb 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -106,34 +106,39 @@ struct ConstraintTy {
   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.
+/// Turn a condition \p CmpI into a vector of constraints, using indices from \p
+/// Value2Index. Additional indices for newly discovered values are added to \p
+/// NewIndices.
 static SmallVector<ConstraintTy, 4>
 getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
-              DenseMap<Value *, unsigned> &Value2Index, bool ShouldAdd) {
+              const DenseMap<Value *, unsigned> &Value2Index,
+              DenseMap<Value *, unsigned> &NewIndices) {
   int64_t Offset1 = 0;
   int64_t Offset2 = 0;
 
-  auto TryToGetIndex = [ShouldAdd,
-                        &Value2Index](Value *V) -> Optional<unsigned> {
-    if (ShouldAdd) {
-      Value2Index.insert({V, Value2Index.size() + 1});
-      return Value2Index[V];
-    }
-    auto I = Value2Index.find(V);
-    if (I == Value2Index.end())
-      return None;
-    return I->second;
+  // First try to look up \p V in Value2Index and NewIndices. Otherwise add a
+  // new entry to NewIndices.
+  auto GetOrAddIndex = [&Value2Index, &NewIndices](Value *V) -> unsigned {
+    auto V2I = Value2Index.find(V);
+    if (V2I != Value2Index.end())
+      return V2I->second;
+    auto NewI = NewIndices.find(V);
+    if (NewI != NewIndices.end())
+      return NewI->second;
+    auto Insert =
+        NewIndices.insert({V, Value2Index.size() + NewIndices.size() + 1});
+    return Insert.first->second;
   };
 
   if (Pred == CmpInst::ICMP_UGT || Pred == CmpInst::ICMP_UGE)
     return getConstraint(CmpInst::getSwappedPredicate(Pred), Op1, Op0,
-                         Value2Index, ShouldAdd);
+                         Value2Index, NewIndices);
 
   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);
+    auto A =
+        getConstraint(CmpInst::ICMP_UGE, Op0, Op1, Value2Index, NewIndices);
+    auto B =
+        getConstraint(CmpInst::ICMP_ULE, Op0, Op1, Value2Index, NewIndices);
     append_range(A, B);
     return A;
   }
@@ -160,31 +165,29 @@ getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
   auto VariablesA = make_range(std::next(ADec.begin()), ADec.end());
   auto VariablesB = make_range(std::next(BDec.begin()), BDec.end());
 
-  // Check if each referenced value in the constraint is already in the system
-  // or can be added (if ShouldAdd is true).
+  // Make sure all variables have entries in Value2Index or NewIndices.
   for (const auto &KV :
        concat<std::pair<int64_t, Value *>>(VariablesA, VariablesB))
-    if (!TryToGetIndex(KV.second))
-      return {};
+    GetOrAddIndex(KV.second);
 
   // Build result constraint, by first adding all coefficients from A and then
   // subtracting all coefficients from B.
-  SmallVector<int64_t, 8> R(Value2Index.size() + 1, 0);
+  SmallVector<int64_t, 8> R(Value2Index.size() + NewIndices.size() + 1, 0);
   for (const auto &KV : VariablesA)
-    R[Value2Index[KV.second]] += KV.first;
+    R[GetOrAddIndex(KV.second)] += KV.first;
 
   for (const auto &KV : VariablesB)
-    R[Value2Index[KV.second]] -= KV.first;
+    R[GetOrAddIndex(KV.second)] -= KV.first;
 
   R[0] = Offset1 + Offset2 + (Pred == CmpInst::ICMP_ULT ? -1 : 0);
   return {R};
 }
 
 static SmallVector<ConstraintTy, 4>
-getConstraint(CmpInst *Cmp, DenseMap<Value *, unsigned> &Value2Index,
-              bool ShouldAdd) {
+getConstraint(CmpInst *Cmp, const DenseMap<Value *, unsigned> &Value2Index,
+              DenseMap<Value *, unsigned> &NewIndices) {
   return getConstraint(Cmp->getPredicate(), Cmp->getOperand(0),
-                       Cmp->getOperand(1), Value2Index, ShouldAdd);
+                       Cmp->getOperand(1), Value2Index, NewIndices);
 }
 
 namespace {
@@ -343,9 +346,26 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
         auto *Cmp = dyn_cast<CmpInst>(&I);
         if (!Cmp)
           continue;
-        auto R = getConstraint(Cmp, Value2Index, false);
-        if (R.size() != 1 || R[0].size() == 1)
+
+        DenseMap<Value *, unsigned> NewIndices;
+        auto R = getConstraint(Cmp, Value2Index, NewIndices);
+        if (R.size() != 1)
+          continue;
+
+        // Check if all coefficients of new indices are 0 after building the
+        // constraint. Skip if any of the new indices has a non-null
+        // coefficient.
+        bool HasNewIndex = false;
+        for (unsigned I = 0; I < NewIndices.size(); ++I) {
+          int64_t Last = R[0].Coefficients.pop_back_val();
+          if (Last != 0) {
+            HasNewIndex = true;
+            break;
+          }
+        }
+        if (HasNewIndex || R[0].size() == 1)
           continue;
+
         if (CS.isConditionImplied(R[0].Coefficients)) {
           if (!DebugCounter::shouldExecute(EliminatedCounter))
             continue;
@@ -399,10 +419,14 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT) {
 
     // Otherwise, add the condition to the system and stack, if we can transform
     // it into a constraint.
-    auto R = getConstraint(CB.Condition, Value2Index, true);
+    DenseMap<Value *, unsigned> NewIndices;
+    auto R = getConstraint(CB.Condition, Value2Index, NewIndices);
     if (R.empty())
       continue;
 
+    for (auto &KV : NewIndices)
+      Value2Index.insert(KV);
+
     LLVM_DEBUG(dbgs() << "Adding " << *CB.Condition << " " << CB.Not << "\n");
     bool Added = false;
     for (auto &C : R) {

diff  --git a/llvm/test/Transforms/ConstraintElimination/decompose-with-temporary-indices.ll b/llvm/test/Transforms/ConstraintElimination/decompose-with-temporary-indices.ll
index 87e6f6ecaf8d..79a5afae3716 100644
--- a/llvm/test/Transforms/ConstraintElimination/decompose-with-temporary-indices.ll
+++ b/llvm/test/Transforms/ConstraintElimination/decompose-with-temporary-indices.ll
@@ -14,9 +14,9 @@ define void @test_uge_temporary_indices_decompose(i8 %start, i8 %n, i8 %idx) {
 ; CHECK-NEXT:    br i1 [[CMP_PRE]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
 ; CHECK:       if.then:
 ; CHECK-NEXT:    [[T_0:%.*]] = icmp ult i8 [[START_ADD_IDX]], [[START_ADD_N]]
-; CHECK-NEXT:    call void @use(i1 [[T_0]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[F_0:%.*]] = icmp uge i8 [[START_ADD_IDX]], [[START_ADD_N]]
-; CHECK-NEXT:    call void @use(i1 [[F_0]])
+; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i8 [[START_ADD_1]], [[START_ADD_N]]
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ult i8 [[START_ADD_IDX]], [[START_ADD_1]]
@@ -24,9 +24,9 @@ define void @test_uge_temporary_indices_decompose(i8 %start, i8 %n, i8 %idx) {
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.end:
 ; CHECK-NEXT:    [[F_1:%.*]] = icmp ult i8 [[START_ADD_IDX]], [[START_ADD_N]]
-; CHECK-NEXT:    call void @use(i1 [[F_1]])
+; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp uge i8 [[START_ADD_IDX]], [[START_ADD_N]]
-; CHECK-NEXT:    call void @use(i1 [[T_1]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp ult i8 [[START_ADD_1]], [[START_ADD_N]]
 ; CHECK-NEXT:    call void @use(i1 [[C_3]])
 ; CHECK-NEXT:    [[C_4:%.*]] = icmp ult i8 [[START_ADD_IDX]], [[START_ADD_1]]

diff  --git a/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll b/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll
index 7972cf8635b6..d628f8fac496 100644
--- a/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll
+++ b/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll
@@ -663,8 +663,8 @@ define void @test_ptr_need_one_upper_check(i32* readonly %src, i32* %dst, i32 %n
 ; CHECK-NEXT:    [[DST_UPPER:%.*]] = getelementptr inbounds i32, i32* [[DST:%.*]], i64 [[TMP0]]
 ; CHECK-NEXT:    [[DST_IDX:%.*]] = getelementptr inbounds i32, i32* [[DST]], i64 [[IDXPROM]]
 ; CHECK-NEXT:    [[CMP_DST_IDX_UPPER:%.*]] = icmp ult i32* [[DST_IDX]], [[DST_UPPER]]
-; CHECK-NEXT:    call void @use(i1 [[CMP_DST_IDX_UPPER]])
-; CHECK-NEXT:    br i1 [[CMP_DST_IDX_UPPER]], label [[LOOP_LATCH_2]], label [[EXIT]]
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    br i1 true, label [[LOOP_LATCH_2]], label [[EXIT]]
 ; CHECK:       loop.latch.2:
 ; CHECK-NEXT:    br label [[LOOP_HEADER]]
 ; CHECK:       exit:


        


More information about the llvm-commits mailing list