From 49c09771941f183f317540c082cbf459c0476cb8 Mon Sep 17 00:00:00 2001 From: Rose Date: Thu, 17 Jul 2025 13:31:05 -0400 Subject: [PATCH] [InstCombine] Propagate nsw in (sub (and Op1, (neg X)), Op1) --> neg (and Op1, (add X, -1)) https://alive2.llvm.org/ce/z/xSs-jy --- .../InstCombine/InstCombineAddSub.cpp | 23 +++++++++-- .../hoist-negation-out-of-bias-calculation.ll | 39 +++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) 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) {