[llvm] [ConstraintElim] Use largest usable bound to check no-wrap regions. (PR #222295)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 9 03:57:20 PDT 2026
https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/222295
The unsigned no-wrap region of an add with a constant operand has
UMAX - C as upper bound. For 64 bit operations, the upper bound is
usually larger than MaxConstraintValue, so it will be decomposed as
variable instead of a constant value.
This improves results end-to-end in a few more cases, without any
additional queries:
https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/1234.
>From a1dd4ce8127d2e1ea398fed52d9d16fcb32c579e Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 9 Sep 2026 11:01:54 +0100
Subject: [PATCH 1/2] [ConstraintElim] Precommit test
---
.../ConstraintElimination/add-nsw.ll | 39 +++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/llvm/test/Transforms/ConstraintElimination/add-nsw.ll b/llvm/test/Transforms/ConstraintElimination/add-nsw.ll
index 34a6ea0910e03..283b44e29e41d 100644
--- a/llvm/test/Transforms/ConstraintElimination/add-nsw.ll
+++ b/llvm/test/Transforms/ConstraintElimination/add-nsw.ll
@@ -1166,3 +1166,42 @@ define i8 @add_nsw_no_nuw(i8 %x) {
%add = add nsw i8 %x, 20
ret i8 %add
}
+
+; %x <=u 100 implies %x + 3 does not wrap unsigned.
+define i64 @add_i64_gains_nuw_with_large_bound(i64 %x) {
+; CHECK-LABEL: @add_i64_gains_nuw_with_large_bound(
+; CHECK-NEXT: [[C:%.*]] = icmp ule i64 [[X:%.*]], 100
+; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
+; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[X]], 3
+; CHECK-NEXT: ret i64 [[ADD]]
+;
+ %c = icmp ule i64 %x, 100
+ call void @llvm.assume(i1 %c)
+ %add = add i64 %x, 3
+ ret i64 %add
+}
+
+; No bound on %x, so no flags can be added.
+define i64 @add_i64_no_bound(i64 %x) {
+; CHECK-LABEL: @add_i64_no_bound(
+; CHECK-NEXT: [[ADD:%.*]] = add i64 [[X:%.*]], 3
+; CHECK-NEXT: ret i64 [[ADD]]
+;
+ %add = add i64 %x, 3
+ ret i64 %add
+}
+
+; %x <=u 2^63 also implies %x + 3 does not wrap unsigned, but the assumed bound
+; is too large to represent as constant in the constraint system.
+define i64 @add_i64_bound_above_max_constraint_value(i64 %x) {
+; CHECK-LABEL: @add_i64_bound_above_max_constraint_value(
+; CHECK-NEXT: [[C:%.*]] = icmp ule i64 [[X:%.*]], -9223372036854775808
+; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
+; CHECK-NEXT: [[ADD:%.*]] = add i64 [[X]], 3
+; CHECK-NEXT: ret i64 [[ADD]]
+;
+ %c = icmp ule i64 %x, -9223372036854775808
+ call void @llvm.assume(i1 %c)
+ %add = add i64 %x, 3
+ ret i64 %add
+}
>From 223548734d6dffdfb234e4ea8ec3a523e6e894c1 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 8 Sep 2026 12:58:21 +0100
Subject: [PATCH 2/2] [ConstraintElim] Use largest usable bound to check
no-wrap regions.
The unsigned no-wrap region of an add with a constant operand has
UMAX - C as upper bound. For 64 bit operations, the upper bound is
usually larger than MaxConstraintValue, so it will be decomposed as
variable instead of a constant value.
This improves results end-to-end in a few more cases, without any
additional queries:
https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/1234.
---
llvm/lib/Transforms/Scalar/ConstraintElimination.cpp | 4 ++++
llvm/test/Transforms/ConstraintElimination/add-nsw.ll | 2 +-
llvm/test/Transforms/ConstraintElimination/pr70510.ll | 4 ++--
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index e33c6c3fdd116..3f96887d16fec 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1361,6 +1361,10 @@ static bool doesHoldInRange(const ConstraintInfo &Info, Value *Op,
: APInt::getMinValue(BitWidth);
APInt MaxVal = Signed ? APInt::getSignedMaxValue(BitWidth)
: APInt::getMaxValue(BitWidth);
+ // Replace bound too large to be decomposed by the largest usable one.
+ if (!Signed && Max.uge(MaxConstraintValue))
+ Max = APInt(BitWidth, MaxConstraintValue - 1);
+
Type *Ty = Op->getType();
if (Min != MinVal &&
!Info.doesHold(Signed ? CmpInst::ICMP_SGE : CmpInst::ICMP_UGE, Op,
diff --git a/llvm/test/Transforms/ConstraintElimination/add-nsw.ll b/llvm/test/Transforms/ConstraintElimination/add-nsw.ll
index 283b44e29e41d..8d9c61cb0c7c5 100644
--- a/llvm/test/Transforms/ConstraintElimination/add-nsw.ll
+++ b/llvm/test/Transforms/ConstraintElimination/add-nsw.ll
@@ -1172,7 +1172,7 @@ define i64 @add_i64_gains_nuw_with_large_bound(i64 %x) {
; CHECK-LABEL: @add_i64_gains_nuw_with_large_bound(
; CHECK-NEXT: [[C:%.*]] = icmp ule i64 [[X:%.*]], 100
; CHECK-NEXT: call void @llvm.assume(i1 [[C]])
-; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[X]], 3
+; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i64 [[X]], 3
; CHECK-NEXT: ret i64 [[ADD]]
;
%c = icmp ule i64 %x, 100
diff --git a/llvm/test/Transforms/ConstraintElimination/pr70510.ll b/llvm/test/Transforms/ConstraintElimination/pr70510.ll
index 31d0a85d8c210..99e69383709f0 100644
--- a/llvm/test/Transforms/ConstraintElimination/pr70510.ll
+++ b/llvm/test/Transforms/ConstraintElimination/pr70510.ll
@@ -13,7 +13,7 @@ define i32 @test_loop_varying_bound_add_rec() {
; CHECK-NEXT: br i1 [[CMP6]], label [[EXIT1:%.*]], label [[FOR_LATCH]]
; CHECK: for.latch:
; CHECK-NEXT: [[IND2_I]] = add i64 [[IND2]], 1
-; CHECK-NEXT: [[IND1_I]] = add nsw i64 [[IND1]], 1
+; CHECK-NEXT: [[IND1_I]] = add nuw nsw i64 [[IND1]], 1
; CHECK-NEXT: [[COND:%.*]] = icmp eq i64 [[IND1_I]], 8
; CHECK-NEXT: br i1 [[COND]], label [[EXIT2:%.*]], label [[FOR_HEADER]]
; CHECK: exit2:
@@ -60,7 +60,7 @@ define i32 @test_loop_varying_bound_call() {
; CHECK-NEXT: [[CMP6:%.*]] = icmp eq i64 [[IND1]], [[VAL]]
; CHECK-NEXT: br i1 [[CMP6]], label [[EXIT1:%.*]], label [[FOR_LATCH]]
; CHECK: for.latch:
-; CHECK-NEXT: [[IND1_I]] = add nsw i64 [[IND1]], 1
+; CHECK-NEXT: [[IND1_I]] = add nuw nsw i64 [[IND1]], 1
; CHECK-NEXT: [[COND:%.*]] = icmp eq i64 [[IND1_I]], 8
; CHECK-NEXT: br i1 [[COND]], label [[EXIT2:%.*]], label [[FOR_HEADER]]
; CHECK: exit2:
More information about the llvm-commits
mailing list