[llvm] dd3a4ed - [ConstraintElim] Tighten bounds using inequalities with constants. (#213049)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 30 12:48:39 PDT 2026


Author: Florian Hahn
Date: 2026-07-30T20:48:34+01:00
New Revision: dd3a4ed6fbca3696b724b46e2934f3c27534f245

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

LOG: [ConstraintElim] Tighten bounds using inequalities with constants. (#213049)

Update ConstraintElimination to tighten existing bounds using
inequalities. Given an inequality %a != %b and %a >= %b, we can tighten
the fact to %a > %b.

For now this is limited to constant %b.

This helps to remove some checks in practice:
https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/819

Compile-time impact in the noise:
https://llvm-compile-time-tracker.com/compare.php?from=2f08dff5138a4ce908b6d4511a9439e859fedf86&to=fafe1d0d9d012654bc10e2b68d50ffe3b9fdbdcd&stat=instructions:u

PR: https://github.com/llvm/llvm-project/pull/213049

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
    llvm/test/Transforms/ConstraintElimination/ne-tightening.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index bc79bd7068f14..efe1920486df6 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -324,6 +324,11 @@ class ConstraintInfo {
   void addFactImpl(CmpInst::Predicate Pred, Value *A, Value *B, unsigned NumIn,
                    unsigned NumOut, SmallVectorImpl<StackEntry> &DFSInStack,
                    bool ForceSignedSystem);
+
+  /// Try to use the inequality \p A != \p B to tighten a non-strict bound the
+  /// system already implies to the corresponding strict bound.
+  void tightenBoundUsingNe(Value *A, Value *B, unsigned NumIn, unsigned NumOut,
+                           SmallVectorImpl<StackEntry> &DFSInStack);
 };
 
 /// Represents a (Coefficient * Variable) entry after IR decomposition.
@@ -1781,6 +1786,49 @@ void ConstraintInfo::addFact(CmpInst::Predicate Pred, Value *A, Value *B,
   // If the Pred is eq/ne, also add the fact to signed system.
   if (CmpInst::isEquality(Pred))
     addFactImpl(Pred, A, B, NumIn, NumOut, DFSInStack, true);
+  if (Pred == CmpInst::ICMP_NE)
+    tightenBoundUsingNe(A, B, NumIn, NumOut, DFSInStack);
+}
+
+void ConstraintInfo::tightenBoundUsingNe(
+    Value *A, Value *B, unsigned NumIn, unsigned NumOut,
+    SmallVectorImpl<StackEntry> &DFSInStack) {
+  if (!isa<ConstantInt>(B) || !A->getType()->isIntegerTy())
+    return;
+
+  for (bool IsSigned : {false, true}) {
+    // In the unsigned system `A u>= 0` holds for every A, so getConstraint
+    // already turned `A != 0` into `A u> 0`.
+    if (!IsSigned && match(B, m_Zero()))
+      continue;
+
+    // Skip if there are any unknown variables.
+    const auto &Value2Index = getValue2Index(IsSigned);
+    if (any_of(decompose(A, *this, IsSigned, DL).Vars,
+               [&Value2Index](const DecompEntry &E) {
+                 return !Value2Index.contains(E.Variable);
+               }))
+      continue;
+
+    // If the system implies `A >= B` then together with `A != B` we get the
+    // strict `A > B`; symmetrically `A <= B` becomes `A < B`.
+    CmpInst::Predicate GEPred =
+        IsSigned ? CmpInst::ICMP_SGE : CmpInst::ICMP_UGE;
+    CmpInst::Predicate LEPred =
+        IsSigned ? CmpInst::ICMP_SLE : CmpInst::ICMP_ULE;
+    for (CmpInst::Predicate NonStrict : {GEPred, LEPred}) {
+      if (!doesHold(NonStrict, A, B))
+        continue;
+      CmpInst::Predicate Strict = CmpInst::getStrictPredicate(NonStrict);
+      LLVM_DEBUG(dbgs() << "Tightening '";
+                 dumpUnpackedICmp(dbgs(), NonStrict, A, B); dbgs() << "' to '";
+                 dumpUnpackedICmp(dbgs(), Strict, A, B);
+                 dbgs() << "' using inequality\n");
+      addFactImpl(Strict, A, B, NumIn, NumOut, DFSInStack,
+                  /*ForceSignedSystem=*/false);
+      break;
+    }
+  }
 }
 
 void ConstraintInfo::addFactImpl(CmpInst::Predicate Pred, Value *A, Value *B,

diff  --git a/llvm/test/Transforms/ConstraintElimination/ne-tightening.ll b/llvm/test/Transforms/ConstraintElimination/ne-tightening.ll
index a7967e9b09051..baf44151a4b61 100644
--- a/llvm/test/Transforms/ConstraintElimination/ne-tightening.ll
+++ b/llvm/test/Transforms/ConstraintElimination/ne-tightening.ll
@@ -10,8 +10,7 @@ define i1 @sge_zero_and_ne_zero_implies_sgt_zero(i64 %n) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[A]])
 ; CHECK-NEXT:    [[B:%.*]] = icmp ne i64 [[N]], 0
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[B]])
-; CHECK-NEXT:    [[C:%.*]] = icmp sgt i64 [[N]], 0
-; CHECK-NEXT:    ret i1 [[C]]
+; CHECK-NEXT:    ret i1 true
 ;
   %a = icmp sge i64 %n, 0
   call void @llvm.assume(i1 %a)
@@ -30,8 +29,7 @@ define i1 @sge_zero_and_ne_zero_from_branch(i64 %n) {
 ; CHECK-NEXT:    [[Z:%.*]] = icmp eq i64 [[N]], 0
 ; CHECK-NEXT:    br i1 [[Z]], label %[[ELSE:.*]], label %[[CONT:.*]]
 ; CHECK:       [[CONT]]:
-; CHECK-NEXT:    [[C:%.*]] = icmp sgt i64 [[N]], 0
-; CHECK-NEXT:    ret i1 [[C]]
+; CHECK-NEXT:    ret i1 true
 ; CHECK:       [[ELSE]]:
 ; CHECK-NEXT:    ret i1 false
 ;
@@ -56,8 +54,7 @@ define i1 @sle_zero_and_ne_zero_implies_slt_zero(i64 %n) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[A]])
 ; CHECK-NEXT:    [[B:%.*]] = icmp ne i64 [[N]], 0
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[B]])
-; CHECK-NEXT:    [[C:%.*]] = icmp slt i64 [[N]], 0
-; CHECK-NEXT:    ret i1 [[C]]
+; CHECK-NEXT:    ret i1 true
 ;
   %a = icmp sle i64 %n, 0
   call void @llvm.assume(i1 %a)
@@ -74,8 +71,7 @@ define i1 @sge_const_and_ne_const_implies_sge_const_plus_one(i64 %n) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[A]])
 ; CHECK-NEXT:    [[B:%.*]] = icmp ne i64 [[N]], 10
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[B]])
-; CHECK-NEXT:    [[C:%.*]] = icmp sge i64 [[N]], 11
-; CHECK-NEXT:    ret i1 [[C]]
+; CHECK-NEXT:    ret i1 true
 ;
   %a = icmp sge i64 %n, 10
   call void @llvm.assume(i1 %a)
@@ -92,8 +88,7 @@ define i1 @sle_const_and_ne_const_implies_sle_const_minus_one(i64 %n) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[A]])
 ; CHECK-NEXT:    [[B:%.*]] = icmp ne i64 [[N]], 10
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[B]])
-; CHECK-NEXT:    [[C:%.*]] = icmp sle i64 [[N]], 9
-; CHECK-NEXT:    ret i1 [[C]]
+; CHECK-NEXT:    ret i1 true
 ;
   %a = icmp sle i64 %n, 10
   call void @llvm.assume(i1 %a)
@@ -110,8 +105,7 @@ define i1 @uge_const_and_ne_const_implies_ugt_const(i64 %n) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[A]])
 ; CHECK-NEXT:    [[B:%.*]] = icmp ne i64 [[N]], 10
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[B]])
-; CHECK-NEXT:    [[C:%.*]] = icmp ugt i64 [[N]], 10
-; CHECK-NEXT:    ret i1 [[C]]
+; CHECK-NEXT:    ret i1 true
 ;
   %a = icmp uge i64 %n, 10
   call void @llvm.assume(i1 %a)
@@ -129,8 +123,7 @@ define i1 @ule_const_and_ne_const_implies_ult_const(i64 %n) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[A]])
 ; CHECK-NEXT:    [[B:%.*]] = icmp ne i64 [[N]], 10
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[B]])
-; CHECK-NEXT:    [[C:%.*]] = icmp ult i64 [[N]], 10
-; CHECK-NEXT:    ret i1 [[C]]
+; CHECK-NEXT:    ret i1 true
 ;
   %a = icmp ule i64 %n, 10
   call void @llvm.assume(i1 %a)
@@ -148,8 +141,7 @@ define i1 @sge_and_ne_on_add(i64 %n) {
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[A]])
 ; CHECK-NEXT:    [[B:%.*]] = icmp ne i64 [[ADD]], 0
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[B]])
-; CHECK-NEXT:    [[C:%.*]] = icmp sge i64 [[N]], 0
-; CHECK-NEXT:    ret i1 [[C]]
+; CHECK-NEXT:    ret i1 true
 ;
   %add = add nsw i64 %n, 1
   %a = icmp sge i64 %add, 0


        


More information about the llvm-commits mailing list