[llvm] [polly] [ConstraintElimination] Use SCEV ranges information for Loop counter (PR #91457)

via llvm-commits llvm-commits at lists.llvm.org
Mon May 13 06:26:37 PDT 2024


https://github.com/v01dXYZ updated https://github.com/llvm/llvm-project/pull/91457

>From c41b5b55860b5afaef6d7dca643d77a817bdb1c9 Mon Sep 17 00:00:00 2001
From: v01dxyz <v01dxyz at v01d.xyz>
Date: Tue, 7 May 2024 13:13:52 +0000
Subject: [PATCH 1/3] [ConstraintSystem] FM Elimination loop code
 simplification and comments

Simplify the code of the loop performing the element-wise multiplication
as there were strange patterns. I added some comments to help understand
the intent of the code for some external viewers.
---
 llvm/lib/Analysis/ConstraintSystem.cpp | 40 +++++++++++++-------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/llvm/lib/Analysis/ConstraintSystem.cpp b/llvm/lib/Analysis/ConstraintSystem.cpp
index 1a9c7c21e9ced..2b6c3818e026d 100644
--- a/llvm/lib/Analysis/ConstraintSystem.cpp
+++ b/llvm/lib/Analysis/ConstraintSystem.cpp
@@ -52,18 +52,16 @@ bool ConstraintSystem::eliminateUsingFM() {
   for (unsigned R1 = 0; R1 < NumRemainingConstraints; R1++) {
     // FIXME do not use copy
     for (unsigned R2 = R1 + 1; R2 < NumRemainingConstraints; R2++) {
-      if (R1 == R2)
-        continue;
-
       int64_t UpperLast = getLastCoefficient(RemainingRows[R2], LastIdx);
       int64_t LowerLast = getLastCoefficient(RemainingRows[R1], LastIdx);
       assert(
           UpperLast != 0 && LowerLast != 0 &&
           "RemainingRows should only contain rows where the variable is != 0");
 
+      // ensure signs are different then swap if necessary to only
+      // deal with UpperLast > 0
       if ((LowerLast < 0 && UpperLast < 0) || (LowerLast > 0 && UpperLast > 0))
         continue;
-
       unsigned LowerR = R1;
       unsigned UpperR = R2;
       if (UpperLast < 0) {
@@ -71,43 +69,45 @@ bool ConstraintSystem::eliminateUsingFM() {
         std::swap(LowerLast, UpperLast);
       }
 
+      // The following loop does the element-wise operation on sparse
+      // vectors:
+      //
+      // NR = - UpperRow * LowerLast + LowerRow * UpperLast
       SmallVector<Entry, 8> NR;
       unsigned IdxUpper = 0;
       unsigned IdxLower = 0;
       auto &LowerRow = RemainingRows[LowerR];
       auto &UpperRow = RemainingRows[UpperR];
-      while (true) {
-        if (IdxUpper >= UpperRow.size() || IdxLower >= LowerRow.size())
-          break;
+
+      while (IdxUpper < UpperRow.size() && IdxLower < LowerRow.size()) {
         int64_t M1, M2, N;
         int64_t UpperV = 0;
         int64_t LowerV = 0;
-        uint16_t CurrentId = std::numeric_limits<uint16_t>::max();
-        if (IdxUpper < UpperRow.size()) {
-          CurrentId = std::min(UpperRow[IdxUpper].Id, CurrentId);
-        }
-        if (IdxLower < LowerRow.size()) {
-          CurrentId = std::min(LowerRow[IdxLower].Id, CurrentId);
-        }
+        uint16_t CurrentId =
+            std::min(UpperRow[IdxUpper].Id, LowerRow[IdxLower].Id);
 
-        if (IdxUpper < UpperRow.size() && UpperRow[IdxUpper].Id == CurrentId) {
+        if (UpperRow[IdxUpper].Id == CurrentId) {
           UpperV = UpperRow[IdxUpper].Coefficient;
-          IdxUpper++;
+          IdxUpper += 1;
+        }
+        if (LowerRow[IdxLower].Id == CurrentId) {
+          LowerV = LowerRow[IdxLower].Coefficient;
+          IdxLower += 1;
         }
 
         if (MulOverflow(UpperV, -1 * LowerLast, M1))
           return false;
-        if (IdxLower < LowerRow.size() && LowerRow[IdxLower].Id == CurrentId) {
-          LowerV = LowerRow[IdxLower].Coefficient;
-          IdxLower++;
-        }
 
         if (MulOverflow(LowerV, UpperLast, M2))
           return false;
+
         if (AddOverflow(M1, M2, N))
           return false;
+
+        // useless to add a 0 to a sparse vector
         if (N == 0)
           continue;
+
         NR.emplace_back(N, CurrentId);
       }
       if (NR.empty())

>From 9027268dd0e22c93e362dbdfb671b18c458622ca Mon Sep 17 00:00:00 2001
From: v01dxyz <v01dxyz at v01d.xyz>
Date: Tue, 7 May 2024 14:27:58 +0000
Subject: [PATCH 2/3] [ConstraintSystem] Relax system if elimination not
 possible

When constructing a new constraint from a pair of lower/upper
constraints on the variable to eliminate, it simply ignores the new
constraint by not adding it if an overflow occurs when computing one
of its coefficients or if there are already too many constraints.

Previously, it simply stopped at this stage and considered the system
as having solution. Thus adding new constraints could turn a
unsatisfiable system into a possibly satisfiable one which is a little
bit strange.

Unsatisfiability of the new system still implies unsatisfiability of
the former one (the projected solution set of the original system is
included in the solution set of the new system).
---
 llvm/include/llvm/Analysis/ConstraintSystem.h | 11 +++++++-
 llvm/lib/Analysis/ConstraintSystem.cpp        | 28 +++++++++++--------
 .../constraint-overflow.ll                    |  3 +-
 3 files changed, 27 insertions(+), 15 deletions(-)

diff --git a/llvm/include/llvm/Analysis/ConstraintSystem.h b/llvm/include/llvm/Analysis/ConstraintSystem.h
index 7b02b618f7cb4..32f61caee0d37 100644
--- a/llvm/include/llvm/Analysis/ConstraintSystem.h
+++ b/llvm/include/llvm/Analysis/ConstraintSystem.h
@@ -43,6 +43,9 @@ class ConstraintSystem {
     return 0;
   }
 
+  // WARNING: it represents rather the maximum number of coefficients in the
+  // constraints which is actually the number of variables PLUS one (for the
+  // constant part).
   size_t NumVariables = 0;
 
   /// Current linear constraints in the system.
@@ -54,7 +57,13 @@ class ConstraintSystem {
   /// constraint system.
   DenseMap<Value *, unsigned> Value2Index;
 
-  // Eliminate constraints from the system using Fourier–Motzkin elimination.
+  // Eliminate the last variable from the system using Fourier–Motzkin
+  // elimination, while possibly relaxing it if it is beyond
+  // acceptable means (too many created constraints, overflow when
+  // computing the coefficients)
+  //
+  // return true if the updated system is equivalent, otherwise return
+  // false if it is relaxed.
   bool eliminateUsingFM();
 
   /// Returns true if there may be a solution for the constraints in the system.
diff --git a/llvm/lib/Analysis/ConstraintSystem.cpp b/llvm/lib/Analysis/ConstraintSystem.cpp
index 2b6c3818e026d..9f7c32207fd95 100644
--- a/llvm/lib/Analysis/ConstraintSystem.cpp
+++ b/llvm/lib/Analysis/ConstraintSystem.cpp
@@ -47,6 +47,9 @@ bool ConstraintSystem::eliminateUsingFM() {
     }
   }
 
+  // Track if an overflow occurred when computing coefficents
+  bool Overflow = false;
+
   // Process rows where the variable is != 0.
   unsigned NumRemainingConstraints = RemainingRows.size();
   for (unsigned R1 = 0; R1 < NumRemainingConstraints; R1++) {
@@ -95,14 +98,11 @@ bool ConstraintSystem::eliminateUsingFM() {
           IdxLower += 1;
         }
 
-        if (MulOverflow(UpperV, -1 * LowerLast, M1))
-          return false;
-
-        if (MulOverflow(LowerV, UpperLast, M2))
-          return false;
-
-        if (AddOverflow(M1, M2, N))
-          return false;
+        if (MulOverflow(UpperV, -1 * LowerLast, M1) ||
+            MulOverflow(LowerV, UpperLast, M2) || AddOverflow(M1, M2, N)) {
+          Overflow = true;
+          continue;
+        }
 
         // useless to add a 0 to a sparse vector
         if (N == 0)
@@ -120,13 +120,17 @@ bool ConstraintSystem::eliminateUsingFM() {
   }
   NumVariables -= 1;
 
-  return true;
+  return !Overflow;
 }
 
 bool ConstraintSystem::mayHaveSolutionImpl() {
-  while (!Constraints.empty() && NumVariables > 1) {
-    if (!eliminateUsingFM())
-      return true;
+  while (!Constraints.empty() && Constraints.size() <= 500 &&
+         NumVariables > 1) {
+    if (!eliminateUsingFM()) {
+      LLVM_DEBUG(
+          dbgs()
+          << "Some new constraints has been ignored during elimination.\n");
+    };
   }
 
   if (Constraints.empty() || NumVariables > 1)
diff --git a/llvm/test/Transforms/ConstraintElimination/constraint-overflow.ll b/llvm/test/Transforms/ConstraintElimination/constraint-overflow.ll
index 88f87f4afab28..efb89fd0512d9 100644
--- a/llvm/test/Transforms/ConstraintElimination/constraint-overflow.ll
+++ b/llvm/test/Transforms/ConstraintElimination/constraint-overflow.ll
@@ -13,8 +13,7 @@ define i32 @f(i64 %a3, i64 %numElements) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt i64 [[A1]], [[A3]]
 ; CHECK-NEXT:    br i1 [[CMP]], label [[IF_END_I:%.*]], label [[ABORT:%.*]]
 ; CHECK:       if.end.i:
-; CHECK-NEXT:    [[CMP2_NOT_I:%.*]] = icmp ult i64 [[A1]], [[A3]]
-; CHECK-NEXT:    br i1 [[CMP2_NOT_I]], label [[ABORT]], label [[EXIT:%.*]]
+; CHECK-NEXT:    br i1 false, label [[ABORT]], label [[EXIT:%.*]]
 ; CHECK:       abort:
 ; CHECK-NEXT:    ret i32 -1
 ; CHECK:       exit:

>From 7062594c43ba6150204428a237c89d5280a8e34b Mon Sep 17 00:00:00 2001
From: v01dxyz <v01dxyz at v01d.xyz>
Date: Fri, 3 May 2024 15:44:42 +0000
Subject: [PATCH 3/3] [ConstraintElim] Use SCEV inferred ranges of loop counter

When looking at the loop counter, if the min/max values of the SCEV
ranges are relevant (not extremal), add this information as
ConditionFacts for the Loop header.

It allows icmp simplifications independently of the branch taken, such
as using `i <= N` after a block `for(i=0; i<N; i+=1) { ... }`.

Fixes https://github.com/llvm/llvm-project/issues/90417

IMPORTANT: Concerning modifications to Polly

One test for polly was modified as an icmp simplification could be
done earlier in the pipeline than previously. The input of
`polly::CodePreparationPass` is almost the same one, except the name
of one block that is different because of this simplification done
earlier.
---
 .../Scalar/ConstraintElimination.cpp          | 44 ++++++++--
 .../loops-bottom-tested-base.ll               | 15 ++--
 .../loops-header-tested-base.ll               | 37 +++------
 .../Transforms/ConstraintElimination/loops.ll | 11 +--
 .../monotonic-int-phis-decrement.ll           |  3 +-
 .../monotonic-int-phis-wrapping.ll            |  9 +-
 .../scev-phis-range-facts.ll                  | 83 +++++++++++++++++++
 ...facts-to-unsigned-is-known-non-negative.ll |  9 +-
 ...d-facts-to-signed-is-known-non-negative.ll |  7 +-
 polly/test/Support/pipelineposition.ll        |  2 +-
 10 files changed, 155 insertions(+), 65 deletions(-)
 create mode 100644 llvm/test/Transforms/ConstraintElimination/scev-phis-range-facts.ll

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 7e48c28176bd1..e4f2feb1b28bf 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -916,6 +916,45 @@ void State::addInfoForInductions(BasicBlock &BB) {
       !SE.isSCEVable(PN->getType()))
     return;
 
+  auto *AR = dyn_cast_or_null<SCEVAddRecExpr>(SE.getSCEV(PN));
+  BasicBlock *LoopPred = L->getLoopPredecessor();
+  if (!AR || AR->getLoop() != L || !LoopPred)
+    return;
+
+  // If SCEV provides relevant range information, we push those facts
+  // to the worklist relatively to the header node itself (and not its
+  // successor).
+  auto UnsignedRange = SE.getUnsignedRange(AR);
+  auto SignedRange = SE.getSignedRange(AR);
+  DomTreeNode *DTNHeader = DT.getNode(&BB);
+
+  // The range can wrap thus we take Min/Max instead of Lower/Upper
+  auto UnsignedMin = UnsignedRange.getUnsignedMin();
+  auto UnsignedMax = UnsignedRange.getUnsignedMax();
+  if (!UnsignedMax.isMaxValue()) {
+    WorkList.push_back(FactOrCheck::getConditionFact(
+        DTNHeader, CmpInst::ICMP_ULE, PN,
+        Constant::getIntegerValue(PN->getType(), UnsignedMax)));
+  }
+  if (!UnsignedMin.isMinValue()) {
+    WorkList.push_back(FactOrCheck::getConditionFact(
+        DTNHeader, CmpInst::ICMP_UGE, PN,
+        Constant::getIntegerValue(PN->getType(), UnsignedMin)));
+  }
+
+  auto SignedMin = SignedRange.getSignedMin();
+  auto SignedMax = SignedRange.getSignedMax();
+  if (!SignedMax.isMaxSignedValue()) {
+    WorkList.push_back(FactOrCheck::getConditionFact(
+        DTNHeader, CmpInst::ICMP_SLE, PN,
+        Constant::getIntegerValue(PN->getType(), SignedMax)));
+  }
+  if (!SignedMin.isMinSignedValue()) {
+    WorkList.push_back(FactOrCheck::getConditionFact(
+        DTNHeader, CmpInst::ICMP_SGE, PN,
+        Constant::getIntegerValue(PN->getType(), SignedMin)));
+  }
+
   BasicBlock *InLoopSucc = nullptr;
   if (Pred == CmpInst::ICMP_NE)
     InLoopSucc = cast<BranchInst>(BB.getTerminator())->getSuccessor(0);
@@ -927,11 +966,6 @@ void State::addInfoForInductions(BasicBlock &BB) {
   if (!L->contains(InLoopSucc) || !L->isLoopExiting(&BB) || InLoopSucc == &BB)
     return;
 
-  auto *AR = dyn_cast_or_null<SCEVAddRecExpr>(SE.getSCEV(PN));
-  BasicBlock *LoopPred = L->getLoopPredecessor();
-  if (!AR || AR->getLoop() != L || !LoopPred)
-    return;
-
   const SCEV *StartSCEV = AR->getStart();
   Value *StartValue = nullptr;
   if (auto *C = dyn_cast<SCEVConstant>(StartSCEV)) {
diff --git a/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-base.ll b/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-base.ll
index 3dbea9496da8d..72a998e71ff87 100644
--- a/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-base.ll
+++ b/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-base.ll
@@ -11,10 +11,8 @@ define void @loop_iv_cond_variable_bound(i32 %n) {
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ule i32 [[IV]], [[N:%.*]]
 ; CHECK-NEXT:    call void @use(i1 [[T_1]])
-; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i32 [[IV]], 0
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
-; CHECK-NEXT:    [[T_3:%.*]] = icmp sge i32 [[IV]], -1
-; CHECK-NEXT:    call void @use(i1 [[T_3]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i32 [[IV]], [[N]]
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ugt i32 [[IV]], 1
@@ -56,12 +54,9 @@ define void @loop_iv_cond_constant_bound() {
 ; CHECK-NEXT:    br label [[LOOP:%.*]]
 ; CHECK:       loop:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
-; CHECK-NEXT:    [[T_1:%.*]] = icmp ule i32 [[IV]], 2
-; CHECK-NEXT:    call void @use(i1 [[T_1]])
-; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i32 [[IV]], 0
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
-; CHECK-NEXT:    [[T_3:%.*]] = icmp sge i32 [[IV]], -1
-; CHECK-NEXT:    call void @use(i1 [[T_3]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i32 [[IV]], 2
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ugt i32 [[IV]], 1
diff --git a/llvm/test/Transforms/ConstraintElimination/loops-header-tested-base.ll b/llvm/test/Transforms/ConstraintElimination/loops-header-tested-base.ll
index 7b928a030614b..61b3411a8cded 100644
--- a/llvm/test/Transforms/ConstraintElimination/loops-header-tested-base.ll
+++ b/llvm/test/Transforms/ConstraintElimination/loops-header-tested-base.ll
@@ -14,15 +14,11 @@ define void @loop_phi_pos_start_value(i32 %y, i1 %c, i32 %n) {
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    call void @use(i1 false)
-; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i32 [[X]], 10
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
-; CHECK-NEXT:    [[C_2:%.*]] = icmp sle i32 [[X]], 9
-; CHECK-NEXT:    call void @use(i1 [[C_2]])
-; CHECK-NEXT:    [[C_3:%.*]] = icmp sgt i32 [[X]], 9
-; CHECK-NEXT:    call void @use(i1 [[C_3]])
 ; CHECK-NEXT:    call void @use(i1 true)
-; CHECK-NEXT:    [[C_5:%.*]] = icmp sge i32 [[X]], 9
-; CHECK-NEXT:    call void @use(i1 [[C_5]])
+; CHECK-NEXT:    call void @use(i1 false)
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[X_NEXT]] = add nsw i32 [[X]], 1
 ; CHECK-NEXT:    br label [[LOOP_HEADER]]
 ; CHECK:       exit:
@@ -75,8 +71,7 @@ define void @loop_phi_neg_start_value(i32 %y, i1 %c, i32 %n) {
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    call void @use(i1 false)
-; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i32 [[X]], -10
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp sle i32 [[X]], 9
 ; CHECK-NEXT:    call void @use(i1 [[C_2]])
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp sgt i32 [[X]], 9
@@ -248,12 +243,11 @@ define void @loop_latch_not_executed_constant_bound(i32 %y, i1 %c) {
 ; CHECK-NEXT:    br i1 [[C:%.*]], label [[LOOP_HEADER:%.*]], label [[EXIT:%.*]]
 ; CHECK:       loop.header:
 ; CHECK-NEXT:    [[X:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[X_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
-; CHECK-NEXT:    [[C_1:%.*]] = icmp ugt i32 [[X]], 10
-; CHECK-NEXT:    br i1 [[C_1]], label [[LOOP_LATCH]], label [[EXIT]]
+; CHECK-NEXT:    br i1 false, label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
-; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    call void @use(i1 true)
-; CHECK-NEXT:    call void @use(i1 false)
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[X_NEXT]] = add i32 [[X]], 1
 ; CHECK-NEXT:    br label [[LOOP_HEADER]]
@@ -299,10 +293,8 @@ define void @loop_iv_cond_variable_bound(i32 %n) {
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
 ; CHECK-NEXT:    [[T_1:%.*]] = icmp ule i32 [[IV]], [[N:%.*]]
 ; CHECK-NEXT:    call void @use(i1 [[T_1]])
-; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i32 [[IV]], 0
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
-; CHECK-NEXT:    [[T_3:%.*]] = icmp sge i32 [[IV]], -1
-; CHECK-NEXT:    call void @use(i1 [[T_3]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i32 [[IV]], [[N]]
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ugt i32 [[IV]], 1
@@ -362,12 +354,9 @@ define void @loop_iv_cond_constant_bound() {
 ; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
 ; CHECK:       loop.header:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
-; CHECK-NEXT:    [[T_1:%.*]] = icmp ule i32 [[IV]], 2
-; CHECK-NEXT:    call void @use(i1 [[T_1]])
-; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i32 [[IV]], 0
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
-; CHECK-NEXT:    [[T_3:%.*]] = icmp sge i32 [[IV]], -1
-; CHECK-NEXT:    call void @use(i1 [[T_3]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ult i32 [[IV]], 2
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ugt i32 [[IV]], 1
diff --git a/llvm/test/Transforms/ConstraintElimination/loops.ll b/llvm/test/Transforms/ConstraintElimination/loops.ll
index 25d4ac436ce8c..8753fff4aac7e 100644
--- a/llvm/test/Transforms/ConstraintElimination/loops.ll
+++ b/llvm/test/Transforms/ConstraintElimination/loops.ll
@@ -107,15 +107,12 @@ define i32 @loop_header_dom_successors_flipped(i32 %y, i1 %c) {
 ; CHECK-NEXT:    br i1 [[C:%.*]], label [[LOOP_HEADER:%.*]], label [[EXIT:%.*]]
 ; CHECK:       loop.header:
 ; CHECK-NEXT:    [[X:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[X_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
-; CHECK-NEXT:    [[C_1:%.*]] = icmp ule i32 [[X]], 10
-; CHECK-NEXT:    br i1 [[C_1]], label [[EXIT]], label [[LOOP_LATCH]]
+; CHECK-NEXT:    br i1 true, label [[EXIT]], label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
-; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    call void @use(i1 true)
-; CHECK-NEXT:    [[C_2:%.*]] = icmp ugt i32 [[X]], 11
-; CHECK-NEXT:    call void @use(i1 [[C_2]])
-; CHECK-NEXT:    [[C_3:%.*]] = icmp ule i32 [[X]], 11
-; CHECK-NEXT:    call void @use(i1 [[C_3]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[X_NEXT]] = add i32 [[X]], 1
 ; CHECK-NEXT:    br label [[LOOP_HEADER]]
 ; CHECK:       exit:
diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-decrement.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-decrement.ll
index 155423d33a69a..a81f2059026c0 100644
--- a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-decrement.ll
+++ b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-decrement.ll
@@ -197,8 +197,7 @@ define void @add_rec_decreasing_2_cond_true_constant(i8 noundef %len) {
 ; CHECK-NEXT:    [[CMP2_NOT:%.*]] = icmp eq i8 [[K_0]], 0
 ; CHECK-NEXT:    br i1 [[CMP2_NOT]], label [[EXIT:%.*]], label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
-; CHECK-NEXT:    [[CMP_NOT_I:%.*]] = icmp ult i8 [[K_0]], 5
-; CHECK-NEXT:    call void @use(i1 [[CMP_NOT_I]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[K_DEC]] = add i8 [[K_0]], -2
 ; CHECK-NEXT:    br label [[LOOP_HEADER]]
 ; CHECK:       exit:
diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-wrapping.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-wrapping.ll
index 17aa4d54abfba..2a58220b78f00 100644
--- a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-wrapping.ll
+++ b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-wrapping.ll
@@ -49,8 +49,7 @@ define void @test_iv_nuw_nsw_1_uge_start(i8 %len.n, i8 %a) {
 ; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
 ; CHECK:       loop.header:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ -1, [[LOOP_PH:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
-; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[IV]], 1
-; CHECK-NEXT:    br i1 [[C]], label [[EXIT:%.*]], label [[FOR_BODY:%.*]]
+; CHECK-NEXT:    br i1 false, label [[EXIT:%.*]], label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
 ; CHECK-NEXT:    [[C_2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_2]], label [[LOOP_LATCH]], label [[EXIT]]
@@ -90,8 +89,7 @@ define void @test_iv_nuw_nsw_2_uge_start(i8 %len.n, i8 %a) {
 ; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
 ; CHECK:       loop.header:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ [[START]], [[LOOP_PH:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
-; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[IV]], 1
-; CHECK-NEXT:    br i1 [[C]], label [[EXIT:%.*]], label [[FOR_BODY:%.*]]
+; CHECK-NEXT:    br i1 false, label [[EXIT:%.*]], label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
 ; CHECK-NEXT:    [[C_2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_2]], label [[LOOP_LATCH]], label [[EXIT]]
@@ -131,8 +129,7 @@ define void @test_iv_nsw_nuw_1_ult_end(i8 %len.n, i8 %a) {
 ; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
 ; CHECK:       loop.header:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ -2, [[LOOP_PH:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
-; CHECK-NEXT:    [[C:%.*]] = icmp eq i8 [[IV]], 1
-; CHECK-NEXT:    br i1 [[C]], label [[EXIT:%.*]], label [[FOR_BODY:%.*]]
+; CHECK-NEXT:    br i1 false, label [[EXIT:%.*]], label [[FOR_BODY:%.*]]
 ; CHECK:       for.body:
 ; CHECK-NEXT:    [[C_2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_2]], label [[LOOP_LATCH]], label [[EXIT]]
diff --git a/llvm/test/Transforms/ConstraintElimination/scev-phis-range-facts.ll b/llvm/test/Transforms/ConstraintElimination/scev-phis-range-facts.ll
new file mode 100644
index 0000000000000..0c77574add33d
--- /dev/null
+++ b/llvm/test/Transforms/ConstraintElimination/scev-phis-range-facts.ll
@@ -0,0 +1,83 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
+
+define i1 @test_ult_loop_with_ult_icmp_N_at_end(ptr %s) {
+; CHECK-LABEL: define i1 @test_ult_loop_with_ult_icmp_N_at_end(
+; CHECK-SAME: ptr [[S:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[WHILE_COND:%.*]]
+; CHECK:       while.cond:
+; CHECK-NEXT:    [[I_0:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[ADD:%.*]], [[WHILE_BODY:%.*]] ]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i64 [[I_0]], 1234
+; CHECK-NEXT:    br i1 [[CMP]], label [[WHILE_BODY]], label [[WHILE_END:%.*]]
+; CHECK:       while.body:
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[S]], i64 [[I_0]]
+; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[ARRAYIDX]], align 1
+; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[TMP0]], -48
+; CHECK-NEXT:    [[OR_COND:%.*]] = icmp ult i8 [[TMP1]], 10
+; CHECK-NEXT:    [[ADD]] = add nuw nsw i64 [[I_0]], 1
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[WHILE_COND]], label [[WHILE_END]]
+; CHECK:       while.end:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  br label %while.cond
+
+while.cond:
+  %i.0 = phi i64 [ 0, %entry ], [ %add, %while.body ]
+  %cmp = icmp ult i64 %i.0, 1234
+  br i1 %cmp, label %while.body, label %while.end
+
+while.body:
+  %arrayidx = getelementptr inbounds i8, ptr %s, i64 %i.0
+  %0 = load i8, ptr %arrayidx, align 1
+  %1 = add i8 %0, -48
+  %or.cond = icmp ult i8 %1, 10
+  %add = add nuw nsw i64 %i.0, 1
+  br i1 %or.cond, label %while.cond, label %while.end
+
+while.end:
+  %cmp6 = icmp ult i64 %i.0, 1235
+  ret i1 %cmp6
+}
+
+define i1 @test_eq_loop_with_ult_icmp_N_at_end(ptr %s) {
+; CHECK-LABEL: define i1 @test_eq_loop_with_ult_icmp_N_at_end(
+; CHECK-SAME: ptr [[S:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    br label [[WHILE_COND:%.*]]
+; CHECK:       while.cond:
+; CHECK-NEXT:    [[I_0:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[ADD:%.*]], [[WHILE_BODY:%.*]] ]
+; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i64 [[I_0]], 1234
+; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label [[WHILE_END:%.*]], label [[WHILE_BODY]]
+; CHECK:       while.body:
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[S]], i64 [[I_0]]
+; CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[ARRAYIDX]], align 1
+; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[TMP0]], -48
+; CHECK-NEXT:    [[OR_COND:%.*]] = icmp ult i8 [[TMP1]], 10
+; CHECK-NEXT:    [[ADD]] = add nuw nsw i64 [[I_0]], 1
+; CHECK-NEXT:    br i1 [[OR_COND]], label [[WHILE_COND]], label [[WHILE_END]]
+; CHECK:       while.end:
+; CHECK-NEXT:    ret i1 true
+;
+entry:
+  br label %while.cond
+
+while.cond:
+  %i.0 = phi i64 [ 0, %entry ], [ %add, %while.body ]
+  %exitcond.not = icmp eq i64 %i.0, 1234
+  br i1 %exitcond.not, label %while.end, label %while.body
+
+while.body:
+  %arrayidx = getelementptr inbounds i8, ptr %s, i64 %i.0
+  %0 = load i8, ptr %arrayidx, align 1
+  %1 = add i8 %0, -48
+  %or.cond = icmp ult i8 %1, 10
+  %add = add nuw nsw i64 %i.0, 1
+;  %add = add i64 %i.0, 1
+  br i1 %or.cond, label %while.cond, label %while.end
+
+while.end:
+  %cmp6 = icmp ult i64 %i.0, 1235
+  ret i1 %cmp6
+}
diff --git a/llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned-is-known-non-negative.ll b/llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned-is-known-non-negative.ll
index efb218ff099fb..fec03ea148ba9 100644
--- a/llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned-is-known-non-negative.ll
+++ b/llvm/test/Transforms/ConstraintElimination/transfer-signed-facts-to-unsigned-is-known-non-negative.ll
@@ -65,8 +65,7 @@ define void @iv_known_non_negative_constant_trip_count_no_nsw_flag(i8 %N) {
 ; CHECK-NEXT:    call void @use(i1 [[F_1]])
 ; CHECK-NEXT:    [[F_2:%.*]] = icmp sle i8 [[N]], [[IV]]
 ; CHECK-NEXT:    call void @use(i1 [[F_2]])
-; CHECK-NEXT:    [[C_0:%.*]] = icmp ugt i8 [[IV]], 2
-; CHECK-NEXT:    call void @use(i1 [[C_0]])
+; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw i8 [[IV]], 1
 ; CHECK-NEXT:    br label [[LOOP_HEADER]]
 ; CHECK:       exit.1:
@@ -153,11 +152,9 @@ define void @iv_may_signed_wrap_variable_trip_count(i8 %N) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp slt i8 [[IV]], [[N:%.*]]
 ; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP_LATCH]], label [[EXIT_1:%.*]]
 ; CHECK:       loop.latch:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp ugt i8 [[N]], [[IV]]
-; CHECK-NEXT:    call void @use(i1 [[T_1]])
 ; CHECK-NEXT:    call void @use(i1 true)
-; CHECK-NEXT:    [[F_1:%.*]] = icmp ule i8 [[N]], [[IV]]
-; CHECK-NEXT:    call void @use(i1 [[F_1]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    [[C_0:%.*]] = icmp ugt i8 [[IV]], 2
 ; CHECK-NEXT:    call void @use(i1 [[C_0]])
diff --git a/llvm/test/Transforms/ConstraintElimination/transfer-unsigned-facts-to-signed-is-known-non-negative.ll b/llvm/test/Transforms/ConstraintElimination/transfer-unsigned-facts-to-signed-is-known-non-negative.ll
index b127361ff0244..7e34f2f6fac86 100644
--- a/llvm/test/Transforms/ConstraintElimination/transfer-unsigned-facts-to-signed-is-known-non-negative.ll
+++ b/llvm/test/Transforms/ConstraintElimination/transfer-unsigned-facts-to-signed-is-known-non-negative.ll
@@ -9,13 +9,12 @@ define void @iv_known_non_negative_iv_constant_trip_count_uge() {
 ; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
 ; CHECK:       loop.header:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i8 [[IV]], 2
-; CHECK-NEXT:    br i1 [[CMP]], label [[LOOP_LATCH]], label [[EXIT_1:%.*]]
+; CHECK-NEXT:    br i1 false, label [[LOOP_LATCH]], label [[EXIT_1:%.*]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    call void @use(i1 true)
-; CHECK-NEXT:    call void @use(i1 false)
-; CHECK-NEXT:    call void @use(i1 false)
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i8 [[IV]], 1
 ; CHECK-NEXT:    br label [[LOOP_HEADER]]
 ; CHECK:       exit.1:
diff --git a/polly/test/Support/pipelineposition.ll b/polly/test/Support/pipelineposition.ll
index a4506ba1d64ed..8dbb0593f65d5 100644
--- a/polly/test/Support/pipelineposition.ll
+++ b/polly/test/Support/pipelineposition.ll
@@ -81,4 +81,4 @@ return:
 
 ; INLINED3-LABEL: Function: caller
 ; INLINED3:       Schedule :=
-; INLINED3-NEXT:    [n] -> { Stmt_body_i_us[i0, i1] -> [i0, i1] };
+; INLINED3-NEXT:    [n] -> { Stmt_body_i[i0, i1] -> [i0, i1] };



More information about the llvm-commits mailing list