[llvm] [ConstraintElim] decompose nsw subtract with guard as precondition (PR #209615)
Abhay Kanhere via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 15 19:27:37 PDT 2026
https://github.com/AbhayKanhere updated https://github.com/llvm/llvm-project/pull/209615
>From c991c2441a6d1663f9a464774b801afe4914e9aa Mon Sep 17 00:00:00 2001
From: Abhay Kanhere <a_kanhere at apple.com>
Date: Tue, 14 Jul 2026 12:59:51 -0700
Subject: [PATCH] [ConstraintElim] decompose subtract with Unsigned<= guard as
precondition
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
ConstraintElimination's unsigned constraint system already decomposes
sub nuw a, b into a ā b (nuw guarantees b ⤠a),
Here we decompose 'sub nsw a, b' and general 'sub a,b' into 'a ā b'
with precondition b u⤠a provided by dominating guard.
Motivating example is a bound check of the form
int f_signed(const int *a, int len, int k) {
if (k <= len) {
int off = len - k; // sub nsw
if (off <= len) // redundant bounds check we want CE to fold
return a[off];
}
return -1;
}
https://alive2.llvm.org/ce/z/e8vka7 sub nsw
https://alive2.llvm.org/ce/z/StmQDv sub without nsw nuw
---
.../Scalar/ConstraintElimination.cpp | 9 +++++++
.../Transforms/ConstraintElimination/sub.ll | 27 +++++++++++++++++++
2 files changed, 36 insertions(+)
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index b244445c6e51f..5b3138e3c8b0b 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -664,6 +664,15 @@ static Decomposition decompose(Value *V,
return V;
}
+ if (match(V, m_Sub(m_Value(Op0), m_Value(Op1)))) {
+ Preconditions.emplace_back(CmpInst::ICMP_ULE, Op1, Op0);
+ auto ResA = decompose(Op0, Preconditions, IsSigned, DL);
+ auto ResB = decompose(Op1, Preconditions, IsSigned, DL);
+ if (!ResA.sub(ResB))
+ return ResA;
+ return V;
+ }
+
return V;
}
diff --git a/llvm/test/Transforms/ConstraintElimination/sub.ll b/llvm/test/Transforms/ConstraintElimination/sub.ll
index 78143dc62883c..0e63a8d7a0f50 100644
--- a/llvm/test/Transforms/ConstraintElimination/sub.ll
+++ b/llvm/test/Transforms/ConstraintElimination/sub.ll
@@ -239,3 +239,30 @@ if.end: ; preds = %entry
declare void @use(i1)
+
+; A `sub` without nsw/nuw is decomposed in the unsigned system under the
+; recorded precondition (Op1 u<= Op0). Given `%b u<= %a`, `%a - %b u<= %a` is
+; therefore known and the check folds to true.
+define i1 @sub_no_wrap_flags_ule(i8 %a, i8 %b) {
+; CHECK-LABEL: @sub_no_wrap_flags_ule(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[PRECOND:%.*]] = icmp ule i8 [[B:%.*]], [[A:%.*]]
+; CHECK-NEXT: br i1 [[PRECOND]], label [[THEN:%.*]], label [[ELSE:%.*]]
+; CHECK: then:
+; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[A]], [[B]]
+; CHECK-NEXT: ret i1 true
+; CHECK: else:
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %precond = icmp ule i8 %b, %a
+ br i1 %precond, label %then, label %else
+
+then:
+ %sub = sub i8 %a, %b
+ %c = icmp ule i8 %sub, %a
+ ret i1 %c
+
+else:
+ ret i1 false
+}
More information about the llvm-commits
mailing list