[llvm] [InstCombine] Fold signed-max sub-or pattern (PR #202274)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 8 00:19:02 PDT 2026
https://github.com/mygitljf created https://github.com/llvm/llvm-project/pull/202274
added a small InstCombine fold for a missed simplification where subtracting a value with all low bits forced on can be reduced to a sign-bit mask. I kept it conservative around overflow flags so it does not change poison behavior.
I added scalar, small integer, vector, and no-wrap coverage.
Fixes #202249
>From 1c57ba15a9705b3c5c3286a7cee4a761675df78c Mon Sep 17 00:00:00 2001
From: mygitljf <2410316423 at qq.com>
Date: Mon, 8 Jun 2026 07:09:16 +0000
Subject: [PATCH] [InstCombine] Fold signed-max sub-or pattern
---
.../InstCombine/InstCombineAddSub.cpp | 11 ++++
llvm/test/Transforms/InstCombine/sub.ll | 52 +++++++++++++++++++
2 files changed, 63 insertions(+)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 8c0dcc8029a1e..3942574723f16 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -2427,6 +2427,17 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
}
}
+ {
+ const APInt *C, *OrC;
+ Value *X;
+ if (!I.hasNoSignedWrap() && !I.hasNoUnsignedWrap() &&
+ match(Op0, m_APInt(C)) && C->isMaxSignedValue() &&
+ match(Op1, m_OneUse(m_Or(m_Value(X), m_APInt(OrC)))) && *OrC == *C)
+ return BinaryOperator::CreateAnd(
+ X, Constant::getIntegerValue(I.getType(),
+ APInt::getSignMask(C->getBitWidth())));
+ }
+
auto TryToNarrowDeduceFlags = [this, &I, &Op0, &Op1]() -> Instruction * {
if (Instruction *Ext = narrowMathIfNoOverflow(I))
return Ext;
diff --git a/llvm/test/Transforms/InstCombine/sub.ll b/llvm/test/Transforms/InstCombine/sub.ll
index 1e7fa477c362c..8b72f01722bc9 100644
--- a/llvm/test/Transforms/InstCombine/sub.ll
+++ b/llvm/test/Transforms/InstCombine/sub.ll
@@ -50,6 +50,58 @@ define <4 x i32> @sub_constant_expression_vec(<4 x i32> %x) {
ret <4 x i32> %r
}
+define i32 @sub_smax_or_i32(i32 %x) {
+; CHECK-LABEL: @sub_smax_or_i32(
+; CHECK-NEXT: [[R:%.*]] = and i32 [[X:%.*]], -2147483648
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %or = or i32 %x, 2147483647
+ %r = sub i32 2147483647, %or
+ ret i32 %r
+}
+
+define i8 @sub_smax_or_i8(i8 %x) {
+; CHECK-LABEL: @sub_smax_or_i8(
+; CHECK-NEXT: [[R:%.*]] = and i8 [[X:%.*]], -128
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %or = or i8 %x, 127
+ %r = sub i8 127, %or
+ ret i8 %r
+}
+
+define <2 x i32> @sub_smax_or_vec(<2 x i32> %x) {
+; CHECK-LABEL: @sub_smax_or_vec(
+; CHECK-NEXT: [[R:%.*]] = and <2 x i32> [[X:%.*]], splat (i32 -2147483648)
+; CHECK-NEXT: ret <2 x i32> [[R]]
+;
+ %or = or <2 x i32> %x, <i32 2147483647, i32 2147483647>
+ %r = sub <2 x i32> <i32 2147483647, i32 2147483647>, %or
+ ret <2 x i32> %r
+}
+
+define i32 @sub_smax_or_nsw(i32 %x) {
+; CHECK-LABEL: @sub_smax_or_nsw(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], 2147483647
+; CHECK-NEXT: [[R:%.*]] = sub nsw i32 2147483647, [[OR]]
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %or = or i32 %x, 2147483647
+ %r = sub nsw i32 2147483647, %or
+ ret i32 %r
+}
+
+define i32 @sub_smax_or_nuw(i32 %x) {
+; CHECK-LABEL: @sub_smax_or_nuw(
+; CHECK-NEXT: [[OR:%.*]] = or i32 [[X:%.*]], 2147483647
+; CHECK-NEXT: [[R:%.*]] = sub nuw i32 2147483647, [[OR]]
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %or = or i32 %x, 2147483647
+ %r = sub nuw i32 2147483647, %or
+ ret i32 %r
+}
+
define i32 @neg_sub(i32 %x, i32 %y) {
; CHECK-LABEL: @neg_sub(
; CHECK-NEXT: [[R:%.*]] = add i32 [[Y:%.*]], [[X:%.*]]
More information about the llvm-commits
mailing list