[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