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

via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 17 10:45:23 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: AZero13 (AZero13)

<details>
<summary>Changes</summary>

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
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) {

``````````

</details>


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


More information about the llvm-commits mailing list