[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