Index: llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1823,7 +1823,8 @@ 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)) + if (Value *NegOp1 = + Negator::Negate(IsNegation, 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 @@ -763,11 +763,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; @@ -795,7 +796,7 @@ public: /// Attempt to negate \p Root. Retuns nullptr if negation can't be performed, /// otherwise returns negated value. - LLVM_NODISCARD static Value *Negate(bool LHSIsZero, Value *Root, + LLVM_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 @@ -208,7 +208,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 @@ -101,13 +101,14 @@ "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() { @@ -238,8 +239,9 @@ // `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. + bool NSW = I->hasNoSignedWrap() && HasNSW && IsTrulyNegation && Depth == 0; return Builder.CreateSub(I->getOperand(1), I->getOperand(0), - I->getName() + ".neg"); + I->getName() + ".neg", false, NSW); } // Some other cases, while still don't require recursion, @@ -514,7 +516,7 @@ return std::make_pair(ArrayRef(NewInstructions), Negated); } -LLVM_NODISCARD Value *Negator::Negate(bool LHSIsZero, Value *Root, +LLVM_NODISCARD Value *Negator::Negate(bool LHSIsZero, bool HasNSW, Value *Root, InstCombinerImpl &IC) { ++NegatorTotalNegationsAttempted; LLVM_DEBUG(dbgs() << "Negator: attempting to sink negation into " << *Root @@ -524,7 +526,7 @@ return nullptr; Negator N(Root->getContext(), IC.getDataLayout(), IC.getAssumptionCache(), - IC.getDominatorTree(), LHSIsZero); + IC.getDominatorTree(), LHSIsZero, HasNSW); Optional Res = N.run(Root); if (!Res) { // Negation failed. LLVM_DEBUG(dbgs() << "Negator: failed to sink negation into " << *Root Index: llvm/test/Transforms/InstCombine/nsw.ll =================================================================== --- llvm/test/Transforms/InstCombine/nsw.ll +++ llvm/test/Transforms/InstCombine/nsw.ll @@ -140,3 +140,95 @@ %t3 = mul %shuf, %xx ret %t3 } + +define i32 @neg_sub0_sub_nsw_nsw(i32 %a, i32 %b) { +; CHECK-LABEL: @neg_sub0_sub_nsw_nsw( +; CHECK-NEXT: [[C_NEG:%.*]] = sub nsw i32 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[C_NEG]] +; + %c = sub nsw i32 %a, %b + %d = sub nsw i32 0, %c + ret i32 %d +} + +define i32 @neg_sub_sub_nsw0(i32 %a, i32 %b) { +; CHECK-LABEL: @neg_sub_sub_nsw0( +; CHECK-NEXT: [[C_NEG:%.*]] = sub i32 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[C_NEG]] +; + %c = sub nsw i32 %a, %b + %d = sub i32 0, %c + ret i32 %d +} + +define i32 @neg_sub_sub_nsw1(i32 %a, i32 %b) { +; CHECK-LABEL: @neg_sub_sub_nsw1( +; CHECK-NEXT: [[C_NEG:%.*]] = sub i32 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[C_NEG]] +; + %c = sub i32 %a, %b + %d = sub nsw i32 0, %c + ret i32 %d +} + +define i32 @neg_sub_sub(i32 %a, i32 %b) { +; CHECK-LABEL: @neg_sub_sub( +; CHECK-NEXT: [[C_NEG:%.*]] = sub i32 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[C_NEG]] +; + %c = sub nsw i32 %a, %b + %d = sub i32 0, %c + ret i32 %d +} + +define i32 @neg_mul_sub_nsw_nsw(i32 %a, i32 %b) { +; CHECK-LABEL: @neg_mul_sub_nsw_nsw( +; CHECK-NEXT: [[C_NEG:%.*]] = sub nsw i32 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[C_NEG]] +; + %c = sub nsw i32 %a, %b + %d = mul nsw i32 -1, %c + ret i32 %d +} + +define i32 @neg_mul_sub_nsw0(i32 %a, i32 %b) { +; CHECK-LABEL: @neg_mul_sub_nsw0( +; CHECK-NEXT: [[C_NEG:%.*]] = sub i32 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[C_NEG]] +; + %c = sub nsw i32 %a, %b + %d = mul i32 -1, %c + ret i32 %d +} + +define i32 @neg_mul_sub_nsw1(i32 %a, i32 %b) { +; CHECK-LABEL: @neg_mul_sub_nsw1( +; CHECK-NEXT: [[C_NEG:%.*]] = sub i32 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[C_NEG]] +; + %c = sub i32 %a, %b + %d = mul nsw i32 -1, %c + ret i32 %d +} + +define i32 @neg_mul_sub(i32 %a, i32 %b) { +; CHECK-LABEL: @neg_mul_sub( +; CHECK-NEXT: [[C_NEG:%.*]] = sub i32 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: ret i32 [[C_NEG]] +; + %c = sub nsw i32 %a, %b + %d = mul i32 -1, %c + ret i32 %d +} + +define i8 @neg_sub_sub2(i16 %a, i16 %b) { +; CHECK-LABEL: @neg_sub_sub2( +; CHECK-NEXT: [[C_NEG:%.*]] = sub i16 [[B:%.*]], [[A:%.*]] +; CHECK-NEXT: [[D_NEG:%.*]] = trunc i16 [[C_NEG]] to i8 +; CHECK-NEXT: ret i8 [[D_NEG]] +; + %c = sub nsw i16 %a, %b + %d = trunc i16 %c to i8 + %e = sub nsw i8 0, %d + ret i8 %e +}