Skip to content

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