[llvm] [ConstraintElim] Set NSW on sub when simplifying ssub.with.overflow. (PR #213532)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 3 09:50:43 PDT 2026
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/213532
>From 2ae9a1c09004d2033f0745af9ec270a54c7a3445 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 28 Jul 2026 14:28:05 +0100
Subject: [PATCH] [ConstraintElim] Set NSW on sub when simplifying
ssub.with.overflow.
When simplifying ssub.with.overflow to a plain sub, we already proven
that the sub does not sign wrap. Replace it with `sub nsw`.
No changes on https://github.com/dtcxzyw/llvm-opt-benchmark-nightly/pull/842,
but there is very little usage of ssub.with.overflow in default C/C++
builds.
It improves optimizations for code where ssub.with.overflow is used more
widely, like Clang + UBSan or Swift where checked arithmetic is the
default.
A simple C example is https://clang.godbolt.org/z/cv5MbYsrz
---
llvm/lib/Transforms/Scalar/ConstraintElimination.cpp | 2 +-
.../Transforms/ConstraintElimination/ssub-with-overflow.ll | 6 +++---
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 8b7018f6c8433..07498dcb6ef7f 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1901,7 +1901,7 @@ static bool replaceSubOverflowUses(IntrinsicInst *II, Value *A, Value *B,
for (User *U : make_early_inc_range(II->users())) {
if (match(U, m_ExtractValue<0>(m_Value()))) {
if (!Sub)
- Sub = Builder.CreateSub(A, B);
+ Sub = Builder.CreateNSWSub(A, B);
U->replaceAllUsesWith(Sub);
Changed = true;
} else if (match(U, m_ExtractValue<1>(m_Value()))) {
diff --git a/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll b/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll
index 254a6a662025e..4a270881bebf8 100644
--- a/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll
+++ b/llvm/test/Transforms/ConstraintElimination/ssub-with-overflow.ll
@@ -11,7 +11,7 @@ define i8 @ssub_no_overflow_due_to_or_conds(i8 %a, i8 %b) {
; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[C_2]], [[C_1]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]]
; CHECK: math:
-; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[B]], [[A]]
+; CHECK-NEXT: [[TMP0:%.*]] = sub nsw i8 [[B]], [[A]]
; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
; CHECK: exit.ok:
; CHECK-NEXT: ret i8 [[TMP0]]
@@ -47,7 +47,7 @@ define i8 @ssub_no_overflow_due_to_or_conds_result_used(i8 %a, i8 %b) {
; CHECK-NEXT: [[OR_COND:%.*]] = or i1 [[C_2]], [[C_1]]
; CHECK-NEXT: br i1 [[OR_COND]], label [[EXIT_FAIL:%.*]], label [[MATH:%.*]]
; CHECK: math:
-; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[B]], [[A]]
+; CHECK-NEXT: [[TMP0:%.*]] = sub nsw i8 [[B]], [[A]]
; CHECK-NEXT: [[OP:%.*]] = tail call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[B]], i8 [[A]])
; CHECK-NEXT: call void @use_res({ i8, i1 } [[OP]])
; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
@@ -84,7 +84,7 @@ define i8 @ssub_no_overflow_due_to_and_conds(i8 %a, i8 %b) {
; CHECK-NEXT: [[AND:%.*]] = and i1 [[C_2]], [[C_1]]
; CHECK-NEXT: br i1 [[AND]], label [[MATH:%.*]], label [[EXIT_FAIL:%.*]]
; CHECK: math:
-; CHECK-NEXT: [[TMP0:%.*]] = sub i8 [[B]], [[A]]
+; CHECK-NEXT: [[TMP0:%.*]] = sub nsw i8 [[B]], [[A]]
; CHECK-NEXT: br i1 false, label [[EXIT_FAIL]], label [[EXIT_OK:%.*]]
; CHECK: exit.ok:
; CHECK-NEXT: ret i8 [[TMP0]]
More information about the llvm-commits
mailing list