Skip to content

[InstCombine] Propagate nsw in (sub (and Op1, (neg X)), Op1) --> neg (and Op1, (add X, -1)) #149366

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

AZero13
Copy link
Contributor

@AZero13 AZero13 commented Jul 17, 2025

@AZero13 AZero13 requested a review from nikic as a code owner July 17, 2025 17:44
@llvmbot llvmbot added llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms labels Jul 17, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 17, 2025

@llvm/pr-subscribers-llvm-transforms

Author: AZero13 (AZero13)

Changes

https://alive2.llvm.org/ce/z/xSs-jy


Full diff: https://github.com/llvm/llvm-project/pull/149366.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp (+19-4)
  • (modified) llvm/test/Transforms/InstCombine/hoist-negation-out-of-bias-calculation.ll (+39)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 981c5271fb3f6..afc11a4cfbabf 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -2588,10 +2588,25 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
   {
     // (sub (and Op1, (neg X)), Op1) --> neg (and Op1, (add X, -1))
     Value *X;
-    if (match(Op0, m_OneUse(m_c_And(m_Specific(Op1),
-                                    m_OneUse(m_Neg(m_Value(X))))))) {
-      return BinaryOperator::CreateNeg(Builder.CreateAnd(
-          Op1, Builder.CreateAdd(X, Constant::getAllOnesValue(I.getType()))));
+    BinaryOperator *NegInst;
+    if (match(Op0,
+              m_OneUse(m_c_And(m_Specific(Op1), m_OneUse(m_BinOp(NegInst))))) &&
+        match(NegInst, m_Neg(m_Value(X)))) {
+
+      // If neg X is nsw, then X - 1 must be too
+      bool AddHasNSW = NegInst->hasNoSignedWrap();
+
+      // If the original sub is nsw, then the final neg must be too
+      bool NegHasNSW = I.hasNoSignedWrap();
+
+      Value *Add =
+          Builder.CreateAdd(X, Constant::getAllOnesValue(I.getType()), "",
+                            /*HasNUW=*/false, /*HasNSW=*/AddHasNSW);
+      Value *And = Builder.CreateAnd(Op1, Add);
+
+      // Use CreateNSWNeg or CreateNeg based on the flag
+      return NegHasNSW ? BinaryOperator::CreateNSWNeg(And)
+                       : BinaryOperator::CreateNeg(And);
     }
   }
 
diff --git a/llvm/test/Transforms/InstCombine/hoist-negation-out-of-bias-calculation.ll b/llvm/test/Transforms/InstCombine/hoist-negation-out-of-bias-calculation.ll
index d4aa8b5dbf505..455fb1a292050 100644
--- a/llvm/test/Transforms/InstCombine/hoist-negation-out-of-bias-calculation.ll
+++ b/llvm/test/Transforms/InstCombine/hoist-negation-out-of-bias-calculation.ll
@@ -25,6 +25,45 @@ define i8 @t0(i8 %x, i8 %y) {
   ret i8 %negbias
 }
 
+define i8 @t0_nsw(i8 %x, i8 %y) {
+; CHECK-LABEL: @t0_nsw(
+; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i8 [[Y:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i8 [[X:%.*]], [[TMP1]]
+; CHECK-NEXT:    [[NEGBIAS:%.*]] = sub i8 0, [[TMP2]]
+; CHECK-NEXT:    ret i8 [[NEGBIAS]]
+;
+  %negy = sub nsw i8 0, %y
+  %unbiasedx = and i8 %negy, %x
+  %negbias = sub i8 %unbiasedx, %x
+  ret i8 %negbias
+}
+
+define i8 @t0_nsw_2(i8 %x, i8 %y) {
+; CHECK-LABEL: @t0_nsw_2(
+; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[Y:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i8 [[X:%.*]], [[TMP1]]
+; CHECK-NEXT:    [[NEGBIAS:%.*]] = sub nsw i8 0, [[TMP2]]
+; CHECK-NEXT:    ret i8 [[NEGBIAS]]
+;
+  %negy = sub i8 0, %y
+  %unbiasedx = and i8 %negy, %x
+  %negbias = sub nsw i8 %unbiasedx, %x
+  ret i8 %negbias
+}
+
+define i8 @t0_nsw_3(i8 %x, i8 %y) {
+; CHECK-LABEL: @t0_nsw_3(
+; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i8 [[Y:%.*]], -1
+; CHECK-NEXT:    [[TMP2:%.*]] = and i8 [[X:%.*]], [[TMP1]]
+; CHECK-NEXT:    [[NEGBIAS:%.*]] = sub nsw i8 0, [[TMP2]]
+; CHECK-NEXT:    ret i8 [[NEGBIAS]]
+;
+  %negy = sub nsw i8 0, %y
+  %unbiasedx = and i8 %negy, %x
+  %negbias = sub nsw i8 %unbiasedx, %x
+  ret i8 %negbias
+}
+
 declare i8 @gen8()
 
 define i8 @t1_commutative(i8 %y) {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants