Index: llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -2058,7 +2058,13 @@ m_Select(m_Value(), m_Specific(Op1), m_Specific(&I))) || match(UI, m_Select(m_Value(), m_Specific(&I), m_Specific(Op1))); })) { - if (Value *NegOp1 = Negator::Negate(IsNegation, Op1, *this)) + Instruction *UI = dyn_cast(Op1); + // Make sure neg-sub sequence + bool IsSub = false; + if (UI && UI->getOpcode() == Instruction::Sub) + IsSub = true; + if (Value *NegOp1 = Negator::Negate( + IsNegation, IsSub && I.hasNoSignedWrap(), Op1, *this)) return BinaryOperator::CreateAdd(NegOp1, Op0); } if (IsNegation) Index: llvm/lib/Transforms/InstCombine/InstCombineInternal.h =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -693,11 +693,12 @@ const DominatorTree &DT; const bool IsTrulyNegation; + const bool HasNSW; SmallDenseMap NegationsCache; Negator(LLVMContext &C, const DataLayout &DL, AssumptionCache &AC, - const DominatorTree &DT, bool IsTrulyNegation); + const DominatorTree &DT, bool IsTrulyNegation, bool HasNSW); #if LLVM_ENABLE_STATS unsigned NumValuesVisitedInThisNegator = 0; @@ -725,7 +726,7 @@ public: /// Attempt to negate \p Root. Retuns nullptr if negation can't be performed, /// otherwise returns negated value. - [[nodiscard]] static Value *Negate(bool LHSIsZero, Value *Root, + [[nodiscard]] static Value *Negate(bool LHSIsZero, bool HasNSW, Value *Root, InstCombinerImpl &IC); }; Index: llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -258,7 +258,8 @@ if (Op0->hasOneUse() && match(Op1, m_NegatedPower2())) { // Interpret X * (-1<(Op1)), I.getName()); Index: llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp @@ -99,13 +99,13 @@ "check for viability of negation sinking.")); Negator::Negator(LLVMContext &C, const DataLayout &DL_, AssumptionCache &AC_, - const DominatorTree &DT_, bool IsTrulyNegation_) + const DominatorTree &DT_, bool IsTrulyNegation_, bool HasNSW_) : Builder(C, TargetFolder(DL_), IRBuilderCallbackInserter([&](Instruction *I) { ++NegatorNumInstructionsCreatedTotal; NewInstructions.push_back(I); })), - DL(DL_), AC(AC_), DT(DT_), IsTrulyNegation(IsTrulyNegation_) {} + DL(DL_), AC(AC_), DT(DT_), IsTrulyNegation(IsTrulyNegation_), HasNSW(HasNSW_) {} #if LLVM_ENABLE_STATS Negator::~Negator() { @@ -236,8 +236,18 @@ // `sub` is always negatible. // However, only do this either if the old `sub` doesn't stick around, or // it was subtracting from a constant. Otherwise, this isn't profitable. - return Builder.CreateSub(I->getOperand(1), I->getOperand(0), - I->getName() + ".neg"); + bool Flag = false; + if (I->hasOneUse() && I->hasNoSignedWrap() && IsTrulyNegation && HasNSW) { + // Propagate flag nsw only when the single use of the I to avoid + // affecting other users. + Flag = true; + } + auto *BO = Builder.CreateSub(I->getOperand(1), I->getOperand(0), + I->getName() + ".neg"); + auto *NewI = dyn_cast(BO); + if (Flag && NewI) + NewI->setHasNoSignedWrap(); + return BO; } // Some other cases, while still don't require recursion, @@ -525,7 +535,7 @@ return std::make_pair(ArrayRef(NewInstructions), Negated); } -[[nodiscard]] Value *Negator::Negate(bool LHSIsZero, Value *Root, +[[nodiscard]] Value *Negator::Negate(bool LHSIsZero, bool HasNSW, Value *Root, InstCombinerImpl &IC) { ++NegatorTotalNegationsAttempted; LLVM_DEBUG(dbgs() << "Negator: attempting to sink negation into " << *Root @@ -535,7 +545,7 @@ return nullptr; Negator N(Root->getContext(), IC.getDataLayout(), IC.getAssumptionCache(), - IC.getDominatorTree(), LHSIsZero); + IC.getDominatorTree(), LHSIsZero, HasNSW); std::optional Res = N.run(Root); if (!Res) { // Negation failed. LLVM_DEBUG(dbgs() << "Negator: failed to sink negation into " << *Root Index: llvm/test/Transforms/InstCombine/abs-intrinsic.ll =================================================================== --- llvm/test/Transforms/InstCombine/abs-intrinsic.ll +++ llvm/test/Transforms/InstCombine/abs-intrinsic.ll @@ -486,7 +486,7 @@ ; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp slt i32 [[Y:%.*]], [[X:%.*]] ; CHECK-NEXT: br i1 [[CMP_NOT]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]] ; CHECK: cond.true: -; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i32 [[Y]], [[X]] +; CHECK-NEXT: [[SUB_NEG:%.*]] = sub nsw i32 [[Y]], [[X]] ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: ; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[SUB_NEG]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] @@ -513,7 +513,7 @@ ; CHECK-NEXT: [[CMP_NOT_NOT:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: br i1 [[CMP_NOT_NOT]], label [[COND_FALSE:%.*]], label [[COND_END:%.*]] ; CHECK: cond.false: -; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i32 [[Y]], [[X]] +; CHECK-NEXT: [[SUB_NEG:%.*]] = sub nsw i32 [[Y]], [[X]] ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: ; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[SUB_NEG]], [[COND_FALSE]] ], [ 0, [[ENTRY:%.*]] ] @@ -539,7 +539,7 @@ ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] ; CHECK: cond.true: -; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i32 [[Y]], [[X]] +; CHECK-NEXT: [[SUB_NEG:%.*]] = sub nsw i32 [[Y]], [[X]] ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: ; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[SUB_NEG]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] @@ -566,7 +566,7 @@ ; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: br i1 [[CMP_NOT]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]] ; CHECK: cond.true: -; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i32 [[Y]], [[X]] +; CHECK-NEXT: [[SUB_NEG:%.*]] = sub nsw i32 [[Y]], [[X]] ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: ; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[SUB_NEG]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] @@ -619,7 +619,7 @@ ; CHECK-NEXT: [[CMP_NOT:%.*]] = icmp sgt i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: br i1 [[CMP_NOT]], label [[COND_END:%.*]], label [[COND_TRUE:%.*]] ; CHECK: cond.true: -; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i8 [[Y]], [[X]] +; CHECK-NEXT: [[SUB_NEG:%.*]] = sub nsw i8 [[Y]], [[X]] ; CHECK-NEXT: br label [[COND_END]] ; CHECK: cond.end: ; CHECK-NEXT: [[R:%.*]] = phi i8 [ [[SUB_NEG]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] Index: llvm/test/Transforms/InstCombine/nsw.ll =================================================================== --- llvm/test/Transforms/InstCombine/nsw.ll +++ llvm/test/Transforms/InstCombine/nsw.ll @@ -1,6 +1,8 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -passes=instcombine -S | FileCheck %s +declare void @foo(i32) + define i32 @sub1(i32 %x) { ; CHECK-LABEL: @sub1( ; CHECK-NEXT: [[Y:%.*]] = sub i32 0, [[X:%.*]] @@ -145,7 +147,7 @@ define i32 @neg_sub0_sub_nsw_nsw(i32 %a, i32 %b) { ; CHECK-LABEL: @neg_sub0_sub_nsw_nsw( -; CHECK-NEXT: [[C_NEG:%.*]] = sub i32 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[C_NEG:%.*]] = sub nsw i32 [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: ret i32 [[C_NEG]] ; %c = sub nsw i32 %a, %b @@ -153,6 +155,35 @@ ret i32 %d } +; Negative test: more than one use, https://alive2.llvm.org/ce/z/4QqC-i +define i32 @neg_sub_both_nsw_other_use(i32 %x, i32 %y) { +; CHECK-LABEL: @neg_sub_both_nsw_other_use( +; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[NEG:%.*]] = sub nsw i32 0, [[SUB]] +; CHECK-NEXT: call void @foo(i32 [[SUB]]) +; CHECK-NEXT: ret i32 [[NEG]] +; + %sub = sub nsw i32 %x, %y + %neg = sub nsw i32 0, %sub + call void @foo (i32 %sub) + ret i32 %neg +} + +; Negative test: only process neg sub sequences, https://alive2.llvm.org/ce/z/Q_MiP4 +define i32 @neg_and_shl_sub(i32 %x, i32 %y) { +; CHECK-LABEL: @neg_and_shl_sub( +; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[X:%.*]] +; CHECK-NEXT: [[SHL_NEG:%.*]] = shl i32 -1, [[NEG]] +; CHECK-NEXT: [[SUB_NEG:%.*]] = sub i32 [[SHL_NEG]], [[Y:%.*]] +; CHECK-NEXT: ret i32 [[SUB_NEG]] +; + %neg = sub i32 0, %x + %shl = shl i32 1, %neg + %sub = add nsw i32 %shl, %y + %neg2 = sub nsw i32 0, %sub + ret i32 %neg2 +} + ; Must not propagate nsw. define i32 @neg_sub_sub_nsw0(i32 %a, i32 %b) { @@ -181,7 +212,7 @@ define i32 @neg_mul_sub_nsw_nsw(i32 %a, i32 %b) { ; CHECK-LABEL: @neg_mul_sub_nsw_nsw( -; CHECK-NEXT: [[C_NEG:%.*]] = sub i32 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[C_NEG:%.*]] = sub nsw i32 [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: ret i32 [[C_NEG]] ; %c = sub nsw i32 %a, %b