Index: llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp @@ -236,8 +236,27 @@ // `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()) { + // Propagate flag nsw/nuw only when the single use of the I to avoid + // affecting other users. + auto *User = *I->users().begin(); + Instruction *UI = dyn_cast(User); + if (UI && UI->getOpcode() == Instruction::Sub) { + Value *Op0; + // Make sure the UI is a negation operand + if (match(UI, m_NSWSub(m_Value(Op0), m_Value())) && + match(Op0, m_ZeroInt()) && UI->hasNoSignedWrap()) { + 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, 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