[llvm] [ConstraintElim] Add lower bounds for all inductions in a loop header. (PR #216764)

Florian Hahn via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 17 09:24:11 PDT 2026


https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/216764

addInfoForInductions only derives facts for inductions that appear in an EQ/NE compare controlling the loop header or latch. The lower bound PN >= Start does not depend on the shape of the loop-controlling condition at all: an induction that never decreases equals its start value in the first iteration and only grows from there, so the bound holds on entry to the header in every iteration.

Move logic to addLowerBoundsForHeaderInductions, which add lower bounds info for each phi with backedge values that increment it by a constant amount and is known to be non-decreasing.

Constructing SCEVs is expensive, so this handles most cases by checking the flags on the increment (phi would be poison based on wrap flags), only falling back to SCEV when necessary like before.

This triggers quite widely on real world code:
https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/940

This slightly increases compile-time, because we add quite a bit more facts, but together with https://github.com/llvm/llvm-project/pull/215735 the increase is quite modest:

 * stage1-O3: +0.04%
 * stage1-ReleaseThinLTO: +0.04%
 * stage1-ReleaseLTO-g: +0.04%
 * stage1-aarch64-O3: 0.04%
 * stage2-O3: +0.04%
 * clang: +0.03%

https://llvm-compile-time-tracker.com/compare.php?from=09aebb3b68def6d89fadc3aa5efceab97a60d8fb&to=1ed0f1d1f481234d66e6dd2055502862f5510d15&stat=instructions:u

>From 78a9ce12f2cb6c5f69fd40d508866a9d52085800 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 5 Aug 2026 21:21:59 +0100
Subject: [PATCH] [ConstraintElim] Add lower bounds for all inductions in a
 loop header.

addInfoForInductions only derives facts for inductions that appear in an
EQ/NE compare controlling the loop header or latch. The lower bound
PN >= Start does not depend on the shape of the loop-controlling
condition at all: an induction that never decreases equals its start
value in the first iteration and only grows from there, so the bound
holds on entry to the header in every iteration.

Move logic to addLowerBoundsForHeaderInductions, which add lower bounds
info for each phi with backedge values that increment it by a constant
amount and is known to be non-decreasing.

Constructing SCEVs is expensive, so this handles most cases by checking
the flags on the increment (phi would be poison based on wrap flags),
only falling back to SCEV when necessary like before.

This triggers quite widely on real world code:
https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/940

This slightly increases compile-time, because we add quite a bit more
facts, but together with https://github.com/llvm/llvm-project/pull/215735
the increase is quite modest:

 * stage1-O3: +0.04%
 * stage1-ReleaseThinLTO: +0.04%
 * stage1-ReleaseLTO-g: +0.04%
 * stage1-aarch64-O3: 0.04%
 * stage2-O3: +0.04%
 * clang: +0.03%

https://llvm-compile-time-tracker.com/compare.php?from=09aebb3b68def6d89fadc3aa5efceab97a60d8fb&to=1ed0f1d1f481234d66e6dd2055502862f5510d15&stat=instructions:u
---
 .../Scalar/ConstraintElimination.cpp          | 122 +++++++++++++-----
 .../and-implied-by-operands.ll                |   3 +-
 .../header-induction-start-bounds.ll          |  81 +++++++-----
 ...on-condition-in-loop-exit-latch-counted.ll |   3 +-
 ...nduction-condition-in-loop-exit-postinc.ll |   6 +-
 .../induction-nowrap-from-scev-not-ir.ll      |   3 +-
 .../loops-bottom-tested-base.ll               |  12 +-
 .../loops-header-tested-base.ll               |  27 ++--
 .../loops-header-tested-pointer-cmps.ll       |   4 +-
 .../loops-header-tested-pointer-iv.ll         |   3 +-
 .../monotonic-int-phis-wrapping.ll            |   6 +-
 .../monotonic-pointer-phis-chain-of-exits.ll  |  12 +-
 .../monotonic-pointer-phis-early-exits.ll     |  21 +--
 .../monotonic-pointer-phis.ll                 |   3 +-
 14 files changed, 176 insertions(+), 130 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 638c7e276d311..eab570790adaa 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -184,10 +184,19 @@ struct State {
   /// Process block \p BB and add known facts to work-list.
   void addInfoFor(BasicBlock &BB);
 
+  /// If \p BB is a loop header, bound each induction phi in it by its start
+  /// value, if it is non-decreasing.
+  void addLowerBoundsForHeaderInductions(BasicBlock &BB);
+
   /// Try to add facts for loop inductions (AddRecs) in EQ/NE compares
   /// controlling the loop header.
   void addInfoForInductions(BasicBlock &BB);
 
+  /// Returns the senses, {unsigned, signed}, in which stepping the induction
+  /// phi \p PN, starting at \p Start, to \p Step cannot decrease it.
+  std::pair<bool, bool> getNonDecreasingInfo(PHINode &PN, Value *Start,
+                                             Value *Step);
+
   /// Returns true if we can add a known condition from BB to its successor
   /// block Succ.
   bool canAddSuccessor(BasicBlock &BB, BasicBlock *Succ) const {
@@ -965,6 +974,84 @@ static void dumpConstraint(ArrayRef<int64_t> C,
 }
 #endif
 
+/// Splits the induction phi \p PN into the start value, coming from the loop
+/// predecessor \p LoopPred, and the step value, coming from inside the loop.
+/// Returns {nullptr, nullptr} if \p PN has other incoming values.
+static std::pair<Value *, Value *> getStartAndStep(const PHINode &PN,
+                                                   const BasicBlock *LoopPred) {
+  assert(PN.getBasicBlockIndex(LoopPred) >= 0 &&
+         "LoopPred must be a predecessor of the phi's block");
+  if (PN.getNumIncomingValues() != 2)
+    return {nullptr, nullptr};
+  unsigned StartIdx = PN.getIncomingBlock(0) == LoopPred ? 0 : 1;
+  return {PN.getIncomingValue(StartIdx), PN.getIncomingValue(1 - StartIdx)};
+}
+
+std::pair<bool, bool> State::getNonDecreasingInfo(PHINode &PN, Value *Start,
+                                                  Value *Step) {
+  bool Unsigned = false, Signed = false;
+  const APInt *StepOffset = nullptr;
+  if (match(Step, m_c_Add(m_Specific(&PN), m_APInt(StepOffset)))) {
+    if (StepOffset->isNegative())
+      return {false, false};
+    const auto *Add = cast<OverflowingBinaryOperator>(Step);
+    Unsigned = Add->hasNoUnsignedWrap();
+    Signed = Add->hasNoSignedWrap();
+  } else if (const auto *GEP = dyn_cast<GEPOperator>(Step)) {
+    const DataLayout &DL = PN.getDataLayout();
+    APInt GEPOffset(DL.getIndexTypeSizeInBits(GEP->getType()), 0);
+    Unsigned = GEP->getPointerOperand() == &PN &&
+               (GEP->hasNoUnsignedWrap() ||
+                ((GEP->hasNoUnsignedSignedWrap() &&
+                  GEP->accumulateConstantOffset(DL, GEPOffset) &&
+                  !GEPOffset.isNegative())));
+  }
+
+  // Forming the SCEV of a phi is expensive, so only consult it for a PN + C
+  // step whose no-wrap flags prove nothing.
+  if (Unsigned || Signed || !StepOffset)
+    return {Unsigned, Signed};
+
+  const auto *AR = dyn_cast<SCEVAddRecExpr>(SE.getSCEV(&PN));
+  if (!AR)
+    return {false, false};
+  return {SE.getMonotonicPredicateType(AR, CmpInst::ICMP_UGT) ==
+              ScalarEvolution::MonotonicallyIncreasing,
+          SE.getMonotonicPredicateType(AR, CmpInst::ICMP_SGT) ==
+              ScalarEvolution::MonotonicallyIncreasing};
+}
+
+void State::addLowerBoundsForHeaderInductions(BasicBlock &BB) {
+  Loop *L = LI.getLoopFor(&BB);
+  if (!L || L->getHeader() != &BB)
+    return;
+  BasicBlock *LoopPred = L->getLoopPredecessor();
+  if (!LoopPred)
+    return;
+
+  DomTreeNode *DTN = DT.getNode(&BB);
+  for (PHINode &PN : BB.phis()) {
+    if (!PN.getType()->isIntegerTy() && !PN.getType()->isPointerTy())
+      continue;
+
+    auto [Start, Step] = getStartAndStep(PN, LoopPred);
+    if (!Start)
+      continue;
+
+    auto [Unsigned, Signed] = getNonDecreasingInfo(PN, Start, Step);
+    // Every variable in the unsigned system already has a `V >= 0` row, so a
+    // zero start value would just duplicate it.
+    if (match(Start, m_Zero()))
+      Unsigned = false;
+    if (!Unsigned && !Signed)
+      continue;
+
+    CmpPredicate Pred(Unsigned ? CmpInst::ICMP_UGE : CmpInst::ICMP_SGE,
+                      /*HasSameSign=*/Unsigned && Signed);
+    WorkList.push_back(FactOrCheck::getConditionFact(DTN, Pred, &PN, Start));
+  }
+}
+
 void State::addInfoForInductions(BasicBlock &BB) {
   auto *L = LI.getLoopFor(&BB);
   if (!L)
@@ -1016,18 +1103,12 @@ void State::addInfoForInductions(BasicBlock &BB) {
   if (!LoopPred || !L->isLoopInvariant(B))
     return;
 
-  Value *StartValue = PN->getIncomingValueForBlock(LoopPred);
-  BasicBlock *BackedgeBB = PN->getIncomingBlock(0) == LoopPred
-                               ? PN->getIncomingBlock(1)
-                               : PN->getIncomingBlock(0);
-  Value *Backedge = PN->getIncomingValueForBlock(BackedgeBB);
+  auto [StartValue, Backedge] = getStartAndStep(*PN, LoopPred);
   const APInt *StepOffset = nullptr;
   const SCEV *StartSCEV = nullptr;
-  OverflowingBinaryOperator *Inc = nullptr;
   if (match(Backedge, m_c_Add(m_Specific(PN), m_APInt(StepOffset)))) {
     if (StepOffset->isZero())
       return;
-    Inc = cast<OverflowingBinaryOperator>(Backedge);
   } else {
     const SCEV *Expr = SE.getSCEV(PN);
     if (!match(Expr,
@@ -1069,30 +1150,8 @@ void State::addInfoForInductions(BasicBlock &BB) {
     return;
   }
 
-  // Monotonicity is only used if the step is non-negative. If Inc is set it
-  // reduces to the induction wrap flags. If that fails, try to refine via SCEV.
-  bool MonotonicallyIncreasingUnsigned = Inc && Inc->hasNoUnsignedWrap();
-  bool MonotonicallyIncreasingSigned = Inc && Inc->hasNoSignedWrap();
-  if (!(MonotonicallyIncreasingUnsigned && MonotonicallyIncreasingSigned)) {
-    const SCEVAddRecExpr *IndAR = cast<SCEVAddRecExpr>(SE.getSCEV(PN));
-    if (!MonotonicallyIncreasingUnsigned)
-      MonotonicallyIncreasingUnsigned =
-          SE.getMonotonicPredicateType(IndAR, CmpInst::ICMP_UGT) ==
-          ScalarEvolution::MonotonicallyIncreasing;
-    if (!MonotonicallyIncreasingSigned)
-      MonotonicallyIncreasingSigned =
-          SE.getMonotonicPredicateType(IndAR, CmpInst::ICMP_SGT) ==
-          ScalarEvolution::MonotonicallyIncreasing;
-  }
-
-  // If the induction is known not to wrap, PN >= StartValue can be added
-  // unconditionally.
-  if (MonotonicallyIncreasingUnsigned)
-    WorkList.push_back(
-        FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_UGE, PN, StartValue));
-  if (MonotonicallyIncreasingSigned)
-    WorkList.push_back(
-        FactOrCheck::getConditionFact(DTN, CmpInst::ICMP_SGE, PN, StartValue));
+  auto [MonotonicallyIncreasingUnsigned, MonotonicallyIncreasingSigned] =
+      getNonDecreasingInfo(*PN, StartValue, Backedge);
 
   // Make sure AR either steps by 1 or that the value we compare against is a
   // GEP based on the same start value and all offsets are a multiple of the
@@ -1207,6 +1266,7 @@ static bool getConstraintFromMemoryAccess(GetElementPtrInst &GEP,
 }
 
 void State::addInfoFor(BasicBlock &BB) {
+  addLowerBoundsForHeaderInductions(BB);
   addInfoForInductions(BB);
   auto &DL = BB.getDataLayout();
 
diff --git a/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll b/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll
index deefe05ddb317..78a91b56a59cf 100644
--- a/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll
+++ b/llvm/test/Transforms/ConstraintElimination/and-implied-by-operands.ll
@@ -321,9 +321,8 @@ define void @test_monotonic_ptr_iv_inc_1_eq_to_uge(ptr %start, i16 %len) {
 ; CHECK-NEXT:    [[AND_0:%.*]] = and i1 [[LEN_NEG]], [[C]]
 ; CHECK-NEXT:    br i1 [[AND_0]], label [[FOR_BODY:%.*]], label [[EXIT:%.*]]
 ; CHECK:       for.body:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[T_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
diff --git a/llvm/test/Transforms/ConstraintElimination/header-induction-start-bounds.ll b/llvm/test/Transforms/ConstraintElimination/header-induction-start-bounds.ll
index 12252ab36ca42..f80af575fd5c6 100644
--- a/llvm/test/Transforms/ConstraintElimination/header-induction-start-bounds.ll
+++ b/llvm/test/Transforms/ConstraintElimination/header-induction-start-bounds.ll
@@ -1,4 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals none --version 6
 ; RUN: opt -p constraint-elimination -S %s | FileCheck %s
 
 declare void @use(i1)
@@ -10,12 +10,9 @@ define void @relational_exit_cond(i32 %n) {
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 5, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge i32 [[IV]], 5
-; CHECK-NEXT:    call void @use(i1 [[T_1]])
-; CHECK-NEXT:    [[T_2:%.*]] = icmp sge i32 [[IV]], 5
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
-; CHECK-NEXT:    [[F_1:%.*]] = icmp ult i32 [[IV]], 5
-; CHECK-NEXT:    call void @use(i1 [[F_1]])
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    call void @use(i1 false)
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
 ; CHECK-NEXT:    [[EC:%.*]] = icmp ult i32 [[IV_NEXT]], [[N]]
 ; CHECK-NEXT:    br i1 [[EC]], label %[[LOOP]], label %[[EXIT:.*]]
@@ -49,8 +46,7 @@ define void @second_induction(i32 %n, i32 %s) {
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
 ; CHECK-NEXT:    [[IV_2:%.*]] = phi i32 [ [[S]], %[[ENTRY]] ], [ [[IV_2_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge i32 [[IV_2]], [[S]]
-; CHECK-NEXT:    call void @use(i1 [[T_1]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
 ; CHECK-NEXT:    [[IV_2_NEXT]] = add nuw i32 [[IV_2]], 3
 ; CHECK-NEXT:    [[EC:%.*]] = icmp ult i32 [[IV_NEXT]], [[N]]
@@ -145,8 +141,7 @@ define void @start_value_is_expression(i32 %a, i32 %n) {
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge i32 [[IV]], [[START]]
-; CHECK-NEXT:    call void @use(i1 [[T_1]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
 ; CHECK-NEXT:    [[EC:%.*]] = icmp ult i32 [[IV_NEXT]], [[N]]
 ; CHECK-NEXT:    br i1 [[EC]], label %[[LOOP]], label %[[EXIT:.*]]
@@ -177,8 +172,7 @@ define void @nuw_only(i32 %s, i32 %n) {
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[S]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge i32 [[IV]], [[S]]
-; CHECK-NEXT:    call void @use(i1 [[T_1]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp sge i32 [[IV]], [[S]]
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw i32 [[IV]], 1
@@ -212,8 +206,7 @@ define void @nsw_only(i32 %s, i32 %n) {
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ [[S]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[T_1:%.*]] = icmp sge i32 [[IV]], [[S]]
-; CHECK-NEXT:    call void @use(i1 [[T_1]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp uge i32 [[IV]], [[S]]
 ; CHECK-NEXT:    call void @use(i1 [[C_1]])
 ; CHECK-NEXT:    [[IV_NEXT]] = add nsw i32 [[IV]], 1
@@ -247,8 +240,7 @@ define void @pointer_induction_gep_nuw(ptr %p, i32 %n) {
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
 ; CHECK-NEXT:    [[PTR_IV:%.*]] = phi ptr [ [[P]], %[[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[P]]
-; CHECK-NEXT:    call void @use(i1 [[T_1]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[PTR_IV_NEXT]] = getelementptr nuw i32, ptr [[PTR_IV]], i64 1
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
 ; CHECK-NEXT:    [[EC:%.*]] = icmp ult i32 [[IV_NEXT]], [[N]]
@@ -282,8 +274,7 @@ define void @pointer_induction_gep_nusw(ptr %p, i32 %n) {
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
 ; CHECK-NEXT:    [[PTR_IV:%.*]] = phi ptr [ [[P]], %[[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[P]]
-; CHECK-NEXT:    call void @use(i1 [[T_1]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[PTR_IV_NEXT]] = getelementptr nusw i32, ptr [[PTR_IV]], i64 1
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
 ; CHECK-NEXT:    [[EC:%.*]] = icmp ult i32 [[IV_NEXT]], [[N]]
@@ -351,8 +342,7 @@ define void @pointer_induction_gep_negative_offset(ptr %p, i32 %n) {
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
 ; CHECK-NEXT:    [[PTR_IV:%.*]] = phi ptr [ [[P]], %[[ENTRY]] ], [ [[PTR_IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[C_1:%.*]] = icmp uge ptr [[PTR_IV]], [[P]]
-; CHECK-NEXT:    call void @use(i1 [[C_1]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[PTR_IV_NEXT]] = getelementptr nuw i32, ptr [[PTR_IV]], i64 -1
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
 ; CHECK-NEXT:    [[EC:%.*]] = icmp ult i32 [[IV_NEXT]], [[N]]
@@ -389,8 +379,7 @@ define void @nuw_only_signed_must_not_fold() {
 ; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ 127, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
 ; CHECK-NEXT:    [[MUST_NOT_FOLD:%.*]] = icmp sge i8 [[IV]], 127
 ; CHECK-NEXT:    call void @use(i1 [[MUST_NOT_FOLD]])
-; CHECK-NEXT:    [[MAY_FOLD:%.*]] = icmp uge i8 [[IV]], 127
-; CHECK-NEXT:    call void @use(i1 [[MAY_FOLD]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw i8 [[IV]], 1
 ; CHECK-NEXT:    [[EC:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[EC]], label %[[LOOP]], label %[[EXIT:.*]]
@@ -424,8 +413,7 @@ define void @nsw_only_unsigned_must_not_fold() {
 ; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ -1, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
 ; CHECK-NEXT:    [[MUST_NOT_FOLD:%.*]] = icmp uge i8 [[IV]], -1
 ; CHECK-NEXT:    call void @use(i1 [[MUST_NOT_FOLD]])
-; CHECK-NEXT:    [[MAY_FOLD:%.*]] = icmp sge i8 [[IV]], -1
-; CHECK-NEXT:    call void @use(i1 [[MAY_FOLD]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[IV_NEXT]] = add nsw i8 [[IV]], 1
 ; CHECK-NEXT:    [[EC:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[EC]], label %[[LOOP]], label %[[EXIT:.*]]
@@ -483,15 +471,16 @@ exit:
   ret void
 }
 
-define void @gep_negative_offset_must_not_fold(ptr %p) {
-; CHECK-LABEL: define void @gep_negative_offset_must_not_fold(
+; A gep nuw adds its offset as an unsigned number without wrapping, so the
+; address does not decrease even though the offset is negative.
+define void @gep_nuw_negative_offset(ptr %p) {
+; CHECK-LABEL: define void @gep_nuw_negative_offset(
 ; CHECK-SAME: ptr [[P:%.*]]) {
 ; CHECK-NEXT:  [[ENTRY:.*]]:
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[PV:%.*]] = phi ptr [ [[P]], %[[ENTRY]] ], [ [[PV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[MUST_NOT_FOLD:%.*]] = icmp uge ptr [[PV]], [[P]]
-; CHECK-NEXT:    call void @use(i1 [[MUST_NOT_FOLD]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[PV_NEXT]] = getelementptr nuw i8, ptr [[PV]], i64 -1
 ; CHECK-NEXT:    [[EC:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[EC]], label %[[LOOP]], label %[[EXIT:.*]]
@@ -503,8 +492,8 @@ entry:
 
 loop:
   %pv = phi ptr [ %p, %entry ], [ %pv.next, %loop ]
-  %must.not.fold = icmp uge ptr %pv, %p
-  call void @use(i1 %must.not.fold)
+  %c = icmp uge ptr %pv, %p
+  call void @use(i1 %c)
   %pv.next = getelementptr nuw i8, ptr %pv, i64 -1
   %ec = call i1 @cond()
   br i1 %ec, label %loop, label %exit
@@ -513,6 +502,36 @@ exit:
   ret void
 }
 
+; Same for a non-constant offset: nuw applies to it as well.
+define void @gep_nuw_variable_offset(ptr %p, i64 %off) {
+; CHECK-LABEL: define void @gep_nuw_variable_offset(
+; CHECK-SAME: ptr [[P:%.*]], i64 [[OFF:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[PV:%.*]] = phi ptr [ [[P]], %[[ENTRY]] ], [ [[PV_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    [[PV_NEXT]] = getelementptr nuw i8, ptr [[PV]], i64 [[OFF]]
+; CHECK-NEXT:    [[EC:%.*]] = call i1 @cond()
+; CHECK-NEXT:    br i1 [[EC]], label %[[LOOP]], label %[[EXIT:.*]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  br label %loop
+
+loop:
+  %pv = phi ptr [ %p, %entry ], [ %pv.next, %loop ]
+  %c = icmp uge ptr %pv, %p
+  call void @use(i1 %c)
+  %pv.next = getelementptr nuw i8, ptr %pv, i64 %off
+  %ec = call i1 @cond()
+  br i1 %ec, label %loop, label %exit
+
+exit:
+  ret void
+}
+
 ; gep with only nusw and a negative offset: nusw does not imply nuw here.
 define void @gep_nusw_negative_offset_must_not_fold(ptr %p) {
 ; CHECK-LABEL: define void @gep_nusw_negative_offset_must_not_fold(
diff --git a/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit-latch-counted.ll b/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit-latch-counted.ll
index 1ebe1754d4a0e..31ae62c564dd6 100644
--- a/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit-latch-counted.ll
+++ b/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit-latch-counted.ll
@@ -219,14 +219,13 @@ define i1 @single_block_header_is_latch(ptr %p, i64 %n) {
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 5, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[GE:%.*]] = icmp uge i64 [[IV]], 5
 ; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[P]], i64 [[IV]]
 ; CHECK-NEXT:    store i8 0, ptr [[GEP]], align 1
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
 ; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
 ; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
 ; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    ret i1 [[GE]]
+; CHECK-NEXT:    ret i1 true
 ;
 entry:
   br label %loop
diff --git a/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit-postinc.ll b/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit-postinc.ll
index 5f461545c6881..06336f5f3218a 100644
--- a/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit-postinc.ll
+++ b/llvm/test/Transforms/ConstraintElimination/induction-condition-in-loop-exit-postinc.ll
@@ -395,12 +395,10 @@ define void @latch_postinc_nuw_unsigned_lower_bound_folds(ptr %p) {
 ; CHECK-NEXT:    br label %[[LOOP:.*]]
 ; CHECK:       [[LOOP]]:
 ; CHECK-NEXT:    [[IV:%.*]] = phi i8 [ 100, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP]] ]
-; CHECK-NEXT:    [[LT:%.*]] = icmp ult i8 [[IV]], 100
-; CHECK-NEXT:    [[Z:%.*]] = zext i1 [[LT]] to i8
+; CHECK-NEXT:    [[Z:%.*]] = zext i1 false to i8
 ; CHECK-NEXT:    store i8 [[Z]], ptr [[P]], align 1
 ; CHECK-NEXT:    [[IV_NEXT]] = add nuw i8 [[IV]], 1
-; CHECK-NEXT:    [[DONE:%.*]] = icmp eq i8 [[IV_NEXT]], 100
-; CHECK-NEXT:    br i1 [[DONE]], label %[[EXIT:.*]], label %[[LOOP]]
+; CHECK-NEXT:    br i1 false, label %[[EXIT:.*]], label %[[LOOP]]
 ; CHECK:       [[EXIT]]:
 ; CHECK-NEXT:    ret void
 ;
diff --git a/llvm/test/Transforms/ConstraintElimination/induction-nowrap-from-scev-not-ir.ll b/llvm/test/Transforms/ConstraintElimination/induction-nowrap-from-scev-not-ir.ll
index 9592bedba54a2..393d5b626d807 100644
--- a/llvm/test/Transforms/ConstraintElimination/induction-nowrap-from-scev-not-ir.ll
+++ b/llvm/test/Transforms/ConstraintElimination/induction-nowrap-from-scev-not-ir.ll
@@ -139,8 +139,7 @@ define void @zero_step_addrec_of_outer_loop(i32 %n) {
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i32 [[IV]], [[N]]
 ; CHECK-NEXT:    br i1 [[CMP]], label %[[INNER_LATCH]], label %[[OUTER_LATCH]]
 ; CHECK:       [[INNER_LATCH]]:
-; CHECK-NEXT:    [[T:%.*]] = icmp uge i32 [[IV]], [[O]]
-; CHECK-NEXT:    call void @use(i1 [[T]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[IV_NEXT]] = add i32 [[IV]], 0
 ; CHECK-NEXT:    br label %[[INNER]]
 ; CHECK:       [[OUTER_LATCH]]:
diff --git a/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-base.ll b/llvm/test/Transforms/ConstraintElimination/loops-bottom-tested-base.ll
index 3dbea9496da8d..6510fbb9d260f 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
@@ -58,10 +56,8 @@ define void @loop_iv_cond_constant_bound() {
 ; 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:    [[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..5ff8798730077 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
@@ -299,10 +294,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
@@ -364,10 +357,8 @@ define void @loop_iv_cond_constant_bound() {
 ; 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:    [[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-pointer-cmps.ll b/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll
index 66aeb85bf0a93..57191a8ebc087 100644
--- a/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll
+++ b/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-cmps.ll
@@ -303,9 +303,9 @@ define void @test3(ptr %src, ptr %lower, ptr %upper, i8 %N) {
 ; CHECK-NEXT:    br i1 [[EC]], label [[LOOP_BODY:%.*]], label [[EXIT:%.*]]
 ; CHECK:       loop.body:
 ; CHECK-NEXT:    [[SRC_IV:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i8 [[IV]]
-; CHECK-NEXT:    [[CMP_IV_START:%.*]] = icmp ult ptr [[SRC_IV]], [[LOWER]]
 ; CHECK-NEXT:    [[CMP_IV_END:%.*]] = icmp uge ptr [[SRC_IV]], [[UPPER]]
-; CHECK-NEXT:    br i1 [[CMP_IV_END]], label [[TRAP_BB]], label [[LOOP_BODY_1:%.*]]
+; CHECK-NEXT:    [[OR_1:%.*]] = or i1 false, [[CMP_IV_END]]
+; CHECK-NEXT:    br i1 [[OR_1]], label [[TRAP_BB]], label [[LOOP_BODY_1:%.*]]
 ; CHECK:       loop.body.1:
 ; CHECK-NEXT:    [[SRC_IV_1:%.*]] = getelementptr inbounds i8, ptr [[SRC]], i8 [[NEXT]]
 ; CHECK-NEXT:    [[CMP_IV_1_END:%.*]] = icmp uge ptr [[SRC_IV_1]], [[UPPER]]
diff --git a/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-iv.ll b/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-iv.ll
index eb252d1a5444e..8863907ecfd50 100644
--- a/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-iv.ll
+++ b/llvm/test/Transforms/ConstraintElimination/loops-header-tested-pointer-iv.ll
@@ -12,8 +12,7 @@ define void @loop_pointer_iv(ptr %start, ptr %end, ptr %upper) {
 ; CHECK-NEXT:    [[IV:%.*]] = phi ptr [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ]
 ; CHECK-NEXT:    [[C_2:%.*]] = icmp ule ptr [[IV]], [[END]]
 ; CHECK-NEXT:    call void @use(i1 [[C_2]])
-; CHECK-NEXT:    [[T_2:%.*]] = icmp uge ptr [[IV]], [[START]]
-; CHECK-NEXT:    call void @use(i1 [[T_2]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ule ptr [[IV]], [[END]]
 ; CHECK-NEXT:    br i1 [[C_1]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-wrapping.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-wrapping.ll
index ab77f54533626..cd4afed80df59 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]]
@@ -132,8 +131,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/monotonic-pointer-phis-chain-of-exits.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-chain-of-exits.ll
index 6b128d9e525ca..16c8beff2780c 100644
--- a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-chain-of-exits.ll
+++ b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-chain-of-exits.ll
@@ -25,9 +25,8 @@ define void @test_monotonic_ptr_iv_inc_1_different_element_types_1_chain_of_2_ex
 ; CHECK-NEXT:    [[C_2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_2]], label [[LOOP_NEXT:%.*]], label [[EXIT]]
 ; CHECK:       loop.next:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[T_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
@@ -94,9 +93,8 @@ define void @test_monotonic_ptr_iv_inc_1_different_element_types_1_chain_of_3_ex
 ; CHECK-NEXT:    [[C_2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_2]], label [[LOOP_NEXT:%.*]], label [[EXIT]]
 ; CHECK:       loop.next:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[T_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
@@ -163,9 +161,8 @@ define void @test_monotonic_ptr_iv_inc_1_different_element_types_1_chain_of_2_ex
 ; CHECK-NEXT:    [[C_2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_2]], label [[LOOP_NEXT:%.*]], label [[EXIT]]
 ; CHECK:       loop.next:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[T_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
@@ -227,9 +224,8 @@ define void @test_header_not_exiting(ptr %start, i16 %len, i16 %x) {
 ; CHECK-NEXT:    [[C_2:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_2]], label [[LOOP_NEXT:%.*]], label [[EXIT]]
 ; CHECK:       loop.next:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[T_2]]
 ; CHECK-NEXT:    br i1 [[AND]], label [[LOOP_LATCH]], label [[EXIT]]
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-early-exits.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-early-exits.ll
index f05f324ef9322..07f10c342ac6f 100644
--- a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-early-exits.ll
+++ b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis-early-exits.ll
@@ -376,9 +376,8 @@ define void @test_monotonic_ptr_iv_cond_doesnt_control_exit(ptr %start, i16 %len
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ne ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[LOOP_LATCH]]
 ; CHECK:       then:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[T_2]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    br label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
@@ -437,9 +436,8 @@ define void @test_monotonic_ptr_iv_cond_doesnt_control_exit2(ptr %start, i16 %le
 ; CHECK-NEXT:    [[C_0:%.*]] = call i1 @cond()
 ; CHECK-NEXT:    br i1 [[C_0]], label [[EXIT]], label [[LOOP_LATCH]]
 ; CHECK:       then:
-; CHECK-NEXT:    [[T_1:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[T_2:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[T_1]], [[T_2]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[T_2]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    br label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
@@ -500,9 +498,8 @@ define void @test_monotonic_ptr_iv_cond_doesnt_dominate_checks(ptr %start, i16 %
 ; CHECK:       then:
 ; CHECK-NEXT:    br label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
-; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[C_3]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    call void @use(ptr [[PTR_IV]])
 ; CHECK-NEXT:    [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i16 1
@@ -619,9 +616,8 @@ define void @test_monotonic_ptr_iv_step_2_cond_doesnt_control_exit(ptr %start, i
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ne ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[LOOP_LATCH]]
 ; CHECK:       then:
-; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[C_3]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    br label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
@@ -680,9 +676,8 @@ define void @test_monotonic_ptr_iv_step_64_cond_doesnt_control_exit(ptr %start,
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ne ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[LOOP_LATCH]]
 ; CHECK:       then:
-; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[C_3]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    br label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
@@ -741,9 +736,8 @@ define void @test_monotonic_ptr_iv_step_80_cond_doesnt_control_exit(ptr %start,
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ne ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[LOOP_LATCH]]
 ; CHECK:       then:
-; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[C_3]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    br label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
@@ -807,9 +801,8 @@ define void @test_monotonic_ptr_iv_inc_1_check_outside_loop(ptr %start, i16 %len
 ; CHECK-NEXT:    [[C_1:%.*]] = icmp ne ptr [[PTR_IV]], [[UPPER]]
 ; CHECK-NEXT:    br i1 [[C_1]], label [[THEN:%.*]], label [[EXIT_2:%.*]]
 ; CHECK:       then:
-; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[C_3]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    br label [[EXIT_2]]
 ; CHECK:       exit.2:
diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll
index b3432695a96a5..f66a9e65aaaee 100644
--- a/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll
+++ b/llvm/test/Transforms/ConstraintElimination/monotonic-pointer-phis.ll
@@ -996,9 +996,8 @@ define void @test_monotonic_ptr_iv_inc_1_loop_exits_on_ne(ptr %start, i16 %len)
 ; CHECK-NEXT:    [[PTR_IV_NEXT]] = getelementptr inbounds i32, ptr [[PTR_IV]], i16 1
 ; CHECK-NEXT:    br label [[LOOP_HEADER]]
 ; CHECK:       exit:
-; CHECK-NEXT:    [[C_2:%.*]] = icmp uge ptr [[PTR_IV]], [[START]]
 ; CHECK-NEXT:    [[C_3:%.*]] = icmp ult ptr [[PTR_IV]], [[UPPER]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_2]], [[C_3]]
+; CHECK-NEXT:    [[AND:%.*]] = and i1 true, [[C_3]]
 ; CHECK-NEXT:    call void @use.i1(i1 [[AND]])
 ; CHECK-NEXT:    ret void
 ;



More information about the llvm-commits mailing list