[llvm] [ConstraintElim] Add min/max bounds from KnownBits (PR #176607)

Ramkumar Ramachandra via llvm-commits llvm-commits at lists.llvm.org
Sun Jan 18 06:08:25 PST 2026


https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/176607

>From e7a3dab7819d73e4ae75494753c73274adf39713 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <artagnon at tenstorrent.com>
Date: Sat, 17 Jan 2026 22:49:52 +0000
Subject: [PATCH 1/3] [ConstraintElim] Add min/max bounds from KnownBits

Co-authored-by: John Regehr <regehr at cs.utah.edu>
---
 .../Scalar/ConstraintElimination.cpp          | 103 +++++++++++-------
 .../monotonic-int-phis-signed.ll              |  12 +-
 .../Transforms/ConstraintElimination/trunc.ll |   3 +-
 3 files changed, 75 insertions(+), 43 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 480ab8b822595..457c500e3acb2 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -335,13 +335,16 @@ class ConstraintInfo {
 struct DecompEntry {
   int64_t Coefficient;
   Value *Variable;
-  /// True if the variable is known positive in the current constraint.
-  bool IsKnownNonNegative;
+  /// Value is always greater than or equal to this value.
+  std::optional<APInt> MinValue;
+  /// Value is always less than or equal to this value.
+  std::optional<APInt> MaxValue;
 
   DecompEntry(int64_t Coefficient, Value *Variable,
-              bool IsKnownNonNegative = false)
-      : Coefficient(Coefficient), Variable(Variable),
-        IsKnownNonNegative(IsKnownNonNegative) {}
+              std::optional<APInt> MinValue = {},
+              std::optional<APInt> MaxValue = {})
+      : Coefficient(Coefficient), Variable(Variable), MinValue(MinValue),
+        MaxValue(MaxValue) {}
 };
 
 /// Represents an Offset + Coefficient1 * Variable1 + ... decomposition.
@@ -350,8 +353,10 @@ struct Decomposition {
   SmallVector<DecompEntry, 3> Vars;
 
   Decomposition(int64_t Offset) : Offset(Offset) {}
-  Decomposition(Value *V, bool IsKnownNonNegative = false) {
-    Vars.emplace_back(1, V, IsKnownNonNegative);
+  Decomposition(Value *V) { Vars.emplace_back(1, V); }
+  Decomposition(Value *V, std::optional<APInt> MinValue,
+                std::optional<APInt> MaxValue) {
+    Vars.emplace_back(1, V, MinValue, MaxValue);
   }
   Decomposition(int64_t Offset, ArrayRef<DecompEntry> Vars)
       : Offset(Offset), Vars(Vars) {}
@@ -522,7 +527,12 @@ static Decomposition decompose(Value *V,
   if (!Ty->isIntegerTy() || Ty->getIntegerBitWidth() > 64)
     return V;
 
-  bool IsKnownNonNegative = false;
+  std::optional<APInt> MinValue, MaxValue;
+  KnownBits Known = computeKnownBits(V, DL);
+  if (!Known.isUnknown()) {
+    MinValue = IsSigned ? Known.getSignedMinValue() : Known.getMinValue();
+    MaxValue = IsSigned ? Known.getSignedMaxValue() : Known.getMaxValue();
+  }
 
   // Decompose \p V used with a signed predicate.
   if (IsSigned) {
@@ -537,7 +547,6 @@ static Decomposition decompose(Value *V,
       V = Op0;
     else if (match(V, m_NNegZExt(m_Value(Op0)))) {
       V = Op0;
-      IsKnownNonNegative = true;
     } else if (match(V, m_NSWTrunc(m_Value(Op0)))) {
       if (Op0->getType()->getScalarSizeInBits() <= 64)
         V = Op0;
@@ -546,7 +555,7 @@ static Decomposition decompose(Value *V,
     if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1)))) {
       if (auto Decomp = MergeResults(Op0, Op1, IsSigned))
         return *Decomp;
-      return {V, IsKnownNonNegative};
+      return {V, MinValue, MaxValue};
     }
 
     if (match(V, m_NSWSub(m_Value(Op0), m_Value(Op1)))) {
@@ -554,7 +563,7 @@ static Decomposition decompose(Value *V,
       auto ResB = decompose(Op1, Preconditions, IsSigned, DL);
       if (!ResA.sub(ResB))
         return ResA;
-      return {V, IsKnownNonNegative};
+      return {V, MinValue, MaxValue};
     }
 
     ConstantInt *CI;
@@ -562,7 +571,7 @@ static Decomposition decompose(Value *V,
       auto Result = decompose(Op0, Preconditions, IsSigned, DL);
       if (!Result.mul(CI->getSExtValue()))
         return Result;
-      return {V, IsKnownNonNegative};
+      return {V, MinValue, MaxValue};
     }
 
     // (shl nsw x, shift) is (mul nsw x, (1<<shift)), with the exception of
@@ -574,11 +583,11 @@ static Decomposition decompose(Value *V,
         auto Result = decompose(Op0, Preconditions, IsSigned, DL);
         if (!Result.mul(int64_t(1) << Shift))
           return Result;
-        return {V, IsKnownNonNegative};
+        return {V, MinValue, MaxValue};
       }
     }
 
-    return {V, IsKnownNonNegative};
+    return {V, MinValue, MaxValue};
   }
 
   if (auto *CI = dyn_cast<ConstantInt>(V)) {
@@ -589,7 +598,6 @@ static Decomposition decompose(Value *V,
 
   Value *Op0;
   if (match(V, m_ZExt(m_Value(Op0)))) {
-    IsKnownNonNegative = true;
     V = Op0;
   } else if (match(V, m_SExt(m_Value(Op0)))) {
     V = Op0;
@@ -611,7 +619,7 @@ static Decomposition decompose(Value *V,
   if (match(V, m_NUWAdd(m_Value(Op0), m_Value(Op1)))) {
     if (auto Decomp = MergeResults(Op0, Op1, IsSigned))
       return *Decomp;
-    return {V, IsKnownNonNegative};
+    return {V, MinValue, MaxValue};
   }
 
   if (match(V, m_Add(m_Value(Op0), m_ConstantInt(CI))) && CI->isNegative() &&
@@ -621,7 +629,7 @@ static Decomposition decompose(Value *V,
         ConstantInt::get(Op0->getType(), CI->getSExtValue() * -1));
     if (auto Decomp = MergeResults(Op0, CI, true))
       return *Decomp;
-    return {V, IsKnownNonNegative};
+    return {V, MinValue, MaxValue};
   }
 
   if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1)))) {
@@ -634,23 +642,23 @@ static Decomposition decompose(Value *V,
 
     if (auto Decomp = MergeResults(Op0, Op1, IsSigned))
       return *Decomp;
-    return {V, IsKnownNonNegative};
+    return {V, MinValue, MaxValue};
   }
 
   // Decompose or as an add if there are no common bits between the operands.
   if (match(V, m_DisjointOr(m_Value(Op0), m_ConstantInt(CI)))) {
     if (auto Decomp = MergeResults(Op0, CI, IsSigned))
       return *Decomp;
-    return {V, IsKnownNonNegative};
+    return {V, MinValue, MaxValue};
   }
 
   if (match(V, m_NUWShl(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI)) {
     if (CI->getSExtValue() < 0 || CI->getSExtValue() >= 64)
-      return {V, IsKnownNonNegative};
+      return {V, MinValue, MaxValue};
     auto Result = decompose(Op1, Preconditions, IsSigned, DL);
     if (!Result.mul(int64_t{1} << CI->getSExtValue()))
       return Result;
-    return {V, IsKnownNonNegative};
+    return {V, MinValue, MaxValue};
   }
 
   if (match(V, m_NUWMul(m_Value(Op1), m_ConstantInt(CI))) && canUseSExt(CI) &&
@@ -658,7 +666,7 @@ static Decomposition decompose(Value *V,
     auto Result = decompose(Op1, Preconditions, IsSigned, DL);
     if (!Result.mul(CI->getSExtValue()))
       return Result;
-    return {V, IsKnownNonNegative};
+    return {V, MinValue, MaxValue};
   }
 
   if (match(V, m_NUWSub(m_Value(Op0), m_Value(Op1)))) {
@@ -666,10 +674,10 @@ static Decomposition decompose(Value *V,
     auto ResB = decompose(Op1, Preconditions, IsSigned, DL);
     if (!ResA.sub(ResB))
       return ResA;
-    return {V, IsKnownNonNegative};
+    return {V, MinValue, MaxValue};
   }
 
-  return {V, IsKnownNonNegative};
+  return {V, MinValue, MaxValue};
 }
 
 ConstraintTy
@@ -758,22 +766,30 @@ ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
       IsSigned, IsEq, IsNe);
   // Collect variables that are known to be positive in all uses in the
   // constraint.
-  SmallDenseMap<Value *, bool> KnownNonNegativeVariables;
+  SmallDenseMap<Value *, std::pair<std::optional<APInt>, std::optional<APInt>>>
+      VariableBounds;
   auto &R = Res.Coefficients;
+  auto MergeMinMax = [&](const DecompEntry &KV) {
+    auto [It, _] = VariableBounds.try_emplace(
+        KV.Variable, std::make_pair(KV.MinValue, KV.MaxValue));
+    auto &[Min, Max] = It->second;
+    if (!Min || (KV.MinValue && IsSigned ? Min->slt(*KV.MinValue)
+                                         : Min->ult(*KV.MinValue)))
+      Min = KV.MinValue;
+    if (!Max || (KV.MaxValue && IsSigned ? Max->sgt(*KV.MaxValue)
+                                         : Max->ugt(*KV.MaxValue)))
+      Max = KV.MaxValue;
+  };
   for (const auto &KV : VariablesA) {
     R[GetOrAddIndex(KV.Variable)] += KV.Coefficient;
-    auto I =
-        KnownNonNegativeVariables.insert({KV.Variable, KV.IsKnownNonNegative});
-    I.first->second &= KV.IsKnownNonNegative;
+    MergeMinMax(KV);
   }
 
   for (const auto &KV : VariablesB) {
     auto &Coeff = R[GetOrAddIndex(KV.Variable)];
     if (SubOverflow(Coeff, KV.Coefficient, Coeff))
       return {};
-    auto I =
-        KnownNonNegativeVariables.insert({KV.Variable, KV.IsKnownNonNegative});
-    I.first->second &= KV.IsKnownNonNegative;
+    MergeMinMax(KV);
   }
 
   int64_t OffsetSum;
@@ -796,14 +812,25 @@ ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
     NewIndexMap.erase(RemovedV);
   }
 
-  // Add extra constraints for variables that are known positive.
-  for (auto &KV : KnownNonNegativeVariables) {
-    if (!KV.second ||
-        (!Value2Index.contains(KV.first) && !NewIndexMap.contains(KV.first)))
+  // Add extra constraints for Min and Max values of variables.
+  for (auto &KV : VariableBounds) {
+    auto &[Min, Max] = KV.second;
+    if (!Value2Index.contains(KV.first) && !NewIndexMap.contains(KV.first))
       continue;
-    auto &C = Res.ExtraInfo.emplace_back(
-        Value2Index.size() + NewVariables.size() + 1, 0);
-    C[GetOrAddIndex(KV.first)] = -1;
+
+    if (Min) {
+      auto &C = Res.ExtraInfo.emplace_back(
+          Value2Index.size() + NewVariables.size() + 1, 0);
+      C[0] = (IsSigned ? (-*Min).getSExtValue() : (-*Min).getZExtValue());
+      C[GetOrAddIndex(KV.first)] = -1;
+    }
+
+    if (Max) {
+      auto &C = Res.ExtraInfo.emplace_back(
+          Value2Index.size() + NewVariables.size() + 1, 0);
+      C[0] = (IsSigned ? Max->getSExtValue() : Max->getZExtValue());
+      C[GetOrAddIndex(KV.first)] = 1;
+    }
   }
   return Res;
 }
diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-signed.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-signed.ll
index 7273469fc59e8..5ee1d5e68f968 100644
--- a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-signed.ll
+++ b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-signed.ll
@@ -55,8 +55,10 @@ define void @signed_iv_step_4(i64 %count) {
 ; CHECK-NEXT:    [[CMP_I_NOT:%.*]] = icmp eq i64 [[IV]], [[END]]
 ; CHECK-NEXT:    br i1 [[CMP_I_NOT]], label [[EXIT]], label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
-; CHECK-NEXT:    call void @use(i1 true)
-; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[IV]], [[END]]
+; CHECK-NEXT:    call void @use(i1 [[CMP2]])
+; CHECK-NEXT:    [[CMP3:%.*]] = icmp sge i64 [[IV]], 0
+; CHECK-NEXT:    call void @use(i1 [[CMP3]])
 ; CHECK-NEXT:    br label [[LOOP]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret void
@@ -139,8 +141,10 @@ define void @signed_iv_step_4_start_4(i64 %count) {
 ; CHECK-NEXT:    [[CMP_I_NOT:%.*]] = icmp eq i64 [[IV]], [[END]]
 ; CHECK-NEXT:    br i1 [[CMP_I_NOT]], label [[EXIT]], label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
-; CHECK-NEXT:    call void @use(i1 true)
-; CHECK-NEXT:    call void @use(i1 true)
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[IV]], [[END]]
+; CHECK-NEXT:    call void @use(i1 [[CMP2]])
+; CHECK-NEXT:    [[CMP3:%.*]] = icmp sge i64 [[IV]], 4
+; CHECK-NEXT:    call void @use(i1 [[CMP3]])
 ; CHECK-NEXT:    br label [[LOOP]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret void
diff --git a/llvm/test/Transforms/ConstraintElimination/trunc.ll b/llvm/test/Transforms/ConstraintElimination/trunc.ll
index 620d978149874..c33b65aa3247c 100644
--- a/llvm/test/Transforms/ConstraintElimination/trunc.ll
+++ b/llvm/test/Transforms/ConstraintElimination/trunc.ll
@@ -99,7 +99,8 @@ define i1 @test2(i32 %n) {
 ; CHECK-NEXT:    br i1 [[COND2]], label %[[FOR_BODY]], label %[[FOR_END:.*]]
 ; CHECK:       [[FOR_END]]:
 ; CHECK-NEXT:    [[TRUNC:%.*]] = trunc nsw i64 [[INDVAR_NEXT]] to i32
-; CHECK-NEXT:    ret i1 true
+; CHECK-NEXT:    [[RES:%.*]] = icmp sgt i32 [[N]], [[TRUNC]]
+; CHECK-NEXT:    ret i1 [[RES]]
 ; CHECK:       [[IF_ELSE]]:
 ; CHECK-NEXT:    ret i1 false
 ;

>From 51e53594463a655287643d4f4483aa70f209515f Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <artagnon at tenstorrent.com>
Date: Sun, 18 Jan 2026 01:30:13 +0000
Subject: [PATCH 2/3] [ConstraintElim] Fix some issues

---
 .../Scalar/ConstraintElimination.cpp          | 39 ++++++++++---------
 .../monotonic-int-phis-signed.ll              |  6 +--
 .../Transforms/ConstraintElimination/trunc.ll |  3 +-
 3 files changed, 23 insertions(+), 25 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 457c500e3acb2..567d726df0654 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -336,13 +336,13 @@ struct DecompEntry {
   int64_t Coefficient;
   Value *Variable;
   /// Value is always greater than or equal to this value.
-  std::optional<APInt> MinValue;
+  int64_t MinValue = MinSignedConstraintValue;
   /// Value is always less than or equal to this value.
-  std::optional<APInt> MaxValue;
+  int64_t MaxValue = MaxConstraintValue;
 
   DecompEntry(int64_t Coefficient, Value *Variable,
-              std::optional<APInt> MinValue = {},
-              std::optional<APInt> MaxValue = {})
+              int64_t MinValue = MinSignedConstraintValue,
+              int64_t MaxValue = MaxConstraintValue)
       : Coefficient(Coefficient), Variable(Variable), MinValue(MinValue),
         MaxValue(MaxValue) {}
 };
@@ -354,8 +354,7 @@ struct Decomposition {
 
   Decomposition(int64_t Offset) : Offset(Offset) {}
   Decomposition(Value *V) { Vars.emplace_back(1, V); }
-  Decomposition(Value *V, std::optional<APInt> MinValue,
-                std::optional<APInt> MaxValue) {
+  Decomposition(Value *V, int64_t MinValue, int64_t MaxValue) {
     Vars.emplace_back(1, V, MinValue, MaxValue);
   }
   Decomposition(int64_t Offset, ArrayRef<DecompEntry> Vars)
@@ -527,11 +526,14 @@ static Decomposition decompose(Value *V,
   if (!Ty->isIntegerTy() || Ty->getIntegerBitWidth() > 64)
     return V;
 
-  std::optional<APInt> MinValue, MaxValue;
+  int64_t MinValue = MinSignedConstraintValue;
+  int64_t MaxValue = MaxConstraintValue;
   KnownBits Known = computeKnownBits(V, DL);
   if (!Known.isUnknown()) {
-    MinValue = IsSigned ? Known.getSignedMinValue() : Known.getMinValue();
-    MaxValue = IsSigned ? Known.getSignedMaxValue() : Known.getMaxValue();
+    MinValue = IsSigned ? Known.getSignedMinValue().getSExtValue()
+                        : Known.getMinValue().getZExtValue();
+    MaxValue = IsSigned ? Known.getSignedMaxValue().getSExtValue()
+                        : Known.getMaxValue().getZExtValue();
   }
 
   // Decompose \p V used with a signed predicate.
@@ -547,6 +549,7 @@ static Decomposition decompose(Value *V,
       V = Op0;
     else if (match(V, m_NNegZExt(m_Value(Op0)))) {
       V = Op0;
+      MinValue = std::max<int64_t>(MinValue, 0);
     } else if (match(V, m_NSWTrunc(m_Value(Op0)))) {
       if (Op0->getType()->getScalarSizeInBits() <= 64)
         V = Op0;
@@ -598,6 +601,7 @@ static Decomposition decompose(Value *V,
 
   Value *Op0;
   if (match(V, m_ZExt(m_Value(Op0)))) {
+    MinValue = std::max<int64_t>(MinValue, 0);
     V = Op0;
   } else if (match(V, m_SExt(m_Value(Op0)))) {
     V = Op0;
@@ -766,18 +770,15 @@ ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
       IsSigned, IsEq, IsNe);
   // Collect variables that are known to be positive in all uses in the
   // constraint.
-  SmallDenseMap<Value *, std::pair<std::optional<APInt>, std::optional<APInt>>>
-      VariableBounds;
+  SmallDenseMap<Value *, std::pair<int64_t, int64_t>> VariableBounds;
   auto &R = Res.Coefficients;
   auto MergeMinMax = [&](const DecompEntry &KV) {
     auto [It, _] = VariableBounds.try_emplace(
         KV.Variable, std::make_pair(KV.MinValue, KV.MaxValue));
     auto &[Min, Max] = It->second;
-    if (!Min || (KV.MinValue && IsSigned ? Min->slt(*KV.MinValue)
-                                         : Min->ult(*KV.MinValue)))
+    if (Min < KV.MinValue)
       Min = KV.MinValue;
-    if (!Max || (KV.MaxValue && IsSigned ? Max->sgt(*KV.MaxValue)
-                                         : Max->ugt(*KV.MaxValue)))
+    if (Max > KV.MaxValue)
       Max = KV.MaxValue;
   };
   for (const auto &KV : VariablesA) {
@@ -818,17 +819,17 @@ ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
     if (!Value2Index.contains(KV.first) && !NewIndexMap.contains(KV.first))
       continue;
 
-    if (Min) {
+    if (Min != MinSignedConstraintValue) {
       auto &C = Res.ExtraInfo.emplace_back(
           Value2Index.size() + NewVariables.size() + 1, 0);
-      C[0] = (IsSigned ? (-*Min).getSExtValue() : (-*Min).getZExtValue());
+      C[0] = -Min;
       C[GetOrAddIndex(KV.first)] = -1;
     }
 
-    if (Max) {
+    if (Max != MaxConstraintValue) {
       auto &C = Res.ExtraInfo.emplace_back(
           Value2Index.size() + NewVariables.size() + 1, 0);
-      C[0] = (IsSigned ? Max->getSExtValue() : Max->getZExtValue());
+      C[0] = Max;
       C[GetOrAddIndex(KV.first)] = 1;
     }
   }
diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-signed.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-signed.ll
index 5ee1d5e68f968..75f31ea97ed0f 100644
--- a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-signed.ll
+++ b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-signed.ll
@@ -57,8 +57,7 @@ define void @signed_iv_step_4(i64 %count) {
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[IV]], [[END]]
 ; CHECK-NEXT:    call void @use(i1 [[CMP2]])
-; CHECK-NEXT:    [[CMP3:%.*]] = icmp sge i64 [[IV]], 0
-; CHECK-NEXT:    call void @use(i1 [[CMP3]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    br label [[LOOP]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret void
@@ -143,8 +142,7 @@ define void @signed_iv_step_4_start_4(i64 %count) {
 ; CHECK:       loop.latch:
 ; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[IV]], [[END]]
 ; CHECK-NEXT:    call void @use(i1 [[CMP2]])
-; CHECK-NEXT:    [[CMP3:%.*]] = icmp sge i64 [[IV]], 4
-; CHECK-NEXT:    call void @use(i1 [[CMP3]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    br label [[LOOP]]
 ; CHECK:       exit:
 ; CHECK-NEXT:    ret void
diff --git a/llvm/test/Transforms/ConstraintElimination/trunc.ll b/llvm/test/Transforms/ConstraintElimination/trunc.ll
index c33b65aa3247c..620d978149874 100644
--- a/llvm/test/Transforms/ConstraintElimination/trunc.ll
+++ b/llvm/test/Transforms/ConstraintElimination/trunc.ll
@@ -99,8 +99,7 @@ define i1 @test2(i32 %n) {
 ; CHECK-NEXT:    br i1 [[COND2]], label %[[FOR_BODY]], label %[[FOR_END:.*]]
 ; CHECK:       [[FOR_END]]:
 ; CHECK-NEXT:    [[TRUNC:%.*]] = trunc nsw i64 [[INDVAR_NEXT]] to i32
-; CHECK-NEXT:    [[RES:%.*]] = icmp sgt i32 [[N]], [[TRUNC]]
-; CHECK-NEXT:    ret i1 [[RES]]
+; CHECK-NEXT:    ret i1 true
 ; CHECK:       [[IF_ELSE]]:
 ; CHECK-NEXT:    ret i1 false
 ;

>From c66df6c03ed9255ed358898dda00d5892b710b8a Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <artagnon at tenstorrent.com>
Date: Sun, 18 Jan 2026 14:02:35 +0000
Subject: [PATCH 3/3] [ConstraintElim] Fix final error

---
 .../Transforms/Scalar/ConstraintElimination.cpp | 17 ++++++++---------
 .../monotonic-int-phis-signed.ll                |  6 ++----
 2 files changed, 10 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 567d726df0654..1ba44e6d6a6e8 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -340,9 +340,10 @@ struct DecompEntry {
   /// Value is always less than or equal to this value.
   int64_t MaxValue = MaxConstraintValue;
 
-  DecompEntry(int64_t Coefficient, Value *Variable,
-              int64_t MinValue = MinSignedConstraintValue,
-              int64_t MaxValue = MaxConstraintValue)
+  DecompEntry(int64_t Coefficient, Value *Variable)
+      : Coefficient(Coefficient), Variable(Variable) {}
+  DecompEntry(int64_t Coefficient, Value *Variable, int64_t MinValue,
+              int64_t MaxValue)
       : Coefficient(Coefficient), Variable(Variable), MinValue(MinValue),
         MaxValue(MaxValue) {}
 };
@@ -532,8 +533,8 @@ static Decomposition decompose(Value *V,
   if (!Known.isUnknown()) {
     MinValue = IsSigned ? Known.getSignedMinValue().getSExtValue()
                         : Known.getMinValue().getZExtValue();
-    MaxValue = IsSigned ? Known.getSignedMaxValue().getSExtValue()
-                        : Known.getMaxValue().getZExtValue();
+    MaxValue = IsSigned ? Known.getMaxValue().getSExtValue()
+                        : Known.getSignedMaxValue().getZExtValue();
   }
 
   // Decompose \p V used with a signed predicate.
@@ -776,10 +777,8 @@ ConstraintInfo::getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1,
     auto [It, _] = VariableBounds.try_emplace(
         KV.Variable, std::make_pair(KV.MinValue, KV.MaxValue));
     auto &[Min, Max] = It->second;
-    if (Min < KV.MinValue)
-      Min = KV.MinValue;
-    if (Max > KV.MaxValue)
-      Max = KV.MaxValue;
+    Min = std::max(Min, KV.MinValue);
+    Max = std::min(Max, KV.MaxValue);
   };
   for (const auto &KV : VariablesA) {
     R[GetOrAddIndex(KV.Variable)] += KV.Coefficient;
diff --git a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-signed.ll b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-signed.ll
index 75f31ea97ed0f..7273469fc59e8 100644
--- a/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-signed.ll
+++ b/llvm/test/Transforms/ConstraintElimination/monotonic-int-phis-signed.ll
@@ -55,8 +55,7 @@ define void @signed_iv_step_4(i64 %count) {
 ; CHECK-NEXT:    [[CMP_I_NOT:%.*]] = icmp eq i64 [[IV]], [[END]]
 ; CHECK-NEXT:    br i1 [[CMP_I_NOT]], label [[EXIT]], label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[IV]], [[END]]
-; CHECK-NEXT:    call void @use(i1 [[CMP2]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    br label [[LOOP]]
 ; CHECK:       exit:
@@ -140,8 +139,7 @@ define void @signed_iv_step_4_start_4(i64 %count) {
 ; CHECK-NEXT:    [[CMP_I_NOT:%.*]] = icmp eq i64 [[IV]], [[END]]
 ; CHECK-NEXT:    br i1 [[CMP_I_NOT]], label [[EXIT]], label [[LOOP_LATCH]]
 ; CHECK:       loop.latch:
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp slt i64 [[IV]], [[END]]
-; CHECK-NEXT:    call void @use(i1 [[CMP2]])
+; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    call void @use(i1 true)
 ; CHECK-NEXT:    br label [[LOOP]]
 ; CHECK:       exit:



More information about the llvm-commits mailing list