[llvm] [InstCombine] Preserve range information for `Op0 -nsw umin(X, Op0) --> usub.sat(Op0, X)` (PR #170989)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Sat Dec 6 09:17:50 PST 2025
https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/170989
This implements the first part discussed in https://github.com/llvm/llvm-project/issues/168880.
Alive2: https://alive2.llvm.org/ce/z/CXAcff
For `umin(X, Op0) - Op0` we can also preserve the information implied by the nsw flag. But it is a bit more complicated and doesn't benefit real-world cases (See https://github.com/dtcxzyw/llvm-opt-benchmark/issues/3123 and https://github.com/dtcxzyw/llvm-opt-benchmark/issues/3122).
>From e03de242e7b8b29e2e2d48cf3e5b102d34f995ab Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 7 Dec 2025 01:07:51 +0800
Subject: [PATCH 1/2] [InstCombine] Add pre-commit tests. NFC.
---
.../test/Transforms/InstCombine/sub-minmax.ll | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/sub-minmax.ll b/llvm/test/Transforms/InstCombine/sub-minmax.ll
index c5af57449bf71..394c96f602417 100644
--- a/llvm/test/Transforms/InstCombine/sub-minmax.ll
+++ b/llvm/test/Transforms/InstCombine/sub-minmax.ll
@@ -663,6 +663,28 @@ define i8 @umin_sub_op0_use(i8 %x, i8 %y) {
ret i8 %r
}
+define i8 @umin_nsw_sub_op1_rhs_nneg_constant(i8 %y) {
+; CHECK-LABEL: define {{[^@]+}}@umin_nsw_sub_op1_rhs_nneg_constant
+; CHECK-SAME: (i8 [[Y:%.*]]) {
+; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[Y]], i8 13)
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %u = call i8 @llvm.umin.i8(i8 %y, i8 13)
+ %r = sub nsw i8 %y, %u
+ ret i8 %r
+}
+
+define i8 @umin_nsw_sub_op1_rhs_neg_constant(i8 %y) {
+; CHECK-LABEL: define {{[^@]+}}@umin_nsw_sub_op1_rhs_neg_constant
+; CHECK-SAME: (i8 [[Y:%.*]]) {
+; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[Y]], i8 -13)
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %u = call i8 @llvm.umin.i8(i8 %y, i8 -13)
+ %r = sub nsw i8 %y, %u
+ ret i8 %r
+}
+
;
; sub(add(X,Y), s/umin(X,Y)) --> s/umax(X,Y)
; sub(add(X,Y), s/umax(X,Y)) --> s/umin(X,Y)
>From 84e67d34ad0bc752154583d41bc762a514fecda4 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 7 Dec 2025 01:12:13 +0800
Subject: [PATCH 2/2] [InstCombine] Preserve range information for `Op0 -
umin(X, Op0) --> usub.sat(Op0, X)`
---
.../InstCombine/InstCombineAddSub.cpp | 17 ++++++++++++++---
llvm/test/Transforms/InstCombine/sub-minmax.ll | 2 +-
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 9bee523c7b7e5..e98702cff66a9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -2857,9 +2857,20 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
I, Builder.CreateIntrinsic(Intrinsic::usub_sat, {Ty}, {X, Op1}));
// Op0 - umin(X, Op0) --> usub.sat(Op0, X)
- if (match(Op1, m_OneUse(m_c_UMin(m_Value(X), m_Specific(Op0)))))
- return replaceInstUsesWith(
- I, Builder.CreateIntrinsic(Intrinsic::usub_sat, {Ty}, {Op0, X}));
+ if (match(Op1, m_OneUse(m_c_UMin(m_Value(X), m_Specific(Op0))))) {
+ Value *USub = Builder.CreateIntrinsic(Intrinsic::usub_sat, {Ty}, {Op0, X});
+ if (auto *USubCall = dyn_cast<CallInst>(USub)) {
+ // Preserve range information implied by the nsw flag.
+ const APInt *C;
+ if (I.hasNoSignedWrap() && match(X, m_NonNegative(C))) {
+ ConstantRange CR = ConstantRange::makeExactNoWrapRegion(
+ Instruction::Sub, *C, OverflowingBinaryOperator::NoSignedWrap);
+ USubCall->addParamAttr(
+ 0, Attribute::get(I.getContext(), Attribute::Range, CR));
+ }
+ }
+ return replaceInstUsesWith(I, USub);
+ }
// Op0 - umax(X, Op0) --> 0 - usub.sat(X, Op0)
if (match(Op1, m_OneUse(m_c_UMax(m_Value(X), m_Specific(Op0))))) {
diff --git a/llvm/test/Transforms/InstCombine/sub-minmax.ll b/llvm/test/Transforms/InstCombine/sub-minmax.ll
index 394c96f602417..36b487f5570f3 100644
--- a/llvm/test/Transforms/InstCombine/sub-minmax.ll
+++ b/llvm/test/Transforms/InstCombine/sub-minmax.ll
@@ -666,7 +666,7 @@ define i8 @umin_sub_op0_use(i8 %x, i8 %y) {
define i8 @umin_nsw_sub_op1_rhs_nneg_constant(i8 %y) {
; CHECK-LABEL: define {{[^@]+}}@umin_nsw_sub_op1_rhs_nneg_constant
; CHECK-SAME: (i8 [[Y:%.*]]) {
-; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[Y]], i8 13)
+; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.usub.sat.i8(i8 range(i8 -115, -128) [[Y]], i8 13)
; CHECK-NEXT: ret i8 [[R]]
;
%u = call i8 @llvm.umin.i8(i8 %y, i8 13)
More information about the llvm-commits
mailing list