Index: llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -2058,8 +2058,21 @@ 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, Op1, *this)) { + auto *InstOp1 = dyn_cast(NegOp1); + // Propagate flag nsw/nuw only when the single use of the Op1 to avoid + // affecting other users. + if (InstOp1 && InstOp1->getOpcode() == Instruction::Sub && + isa(Op1) && IsNegation && Op1->hasOneUse()) { + auto *Op1Inst = cast(Op1); + // Make sure the sub and neg have the same type flag. + if (I.hasNoUnsignedWrap() && Op1Inst->hasNoUnsignedWrap()) + InstOp1->setHasNoUnsignedWrap(); + if (I.hasNoSignedWrap() && Op1Inst->hasNoSignedWrap()) + InstOp1->setHasNoSignedWrap(); + } return BinaryOperator::CreateAdd(NegOp1, Op0); + } } if (IsNegation) return TryToNarrowDeduceFlags(); // Should have been handled in Negator! 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,20 @@ ret i32 %d } +; Negative test: more than one use, https://alive2.llvm.org/ce/z/4QqC-i +define i32 @src_neg_sub_both_nsw_other_use(i32 %x, i32 %y) { +; CHECK-LABEL: @src_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 +} + ; Must not propagate nsw. define i32 @neg_sub_sub_nsw0(i32 %a, i32 %b) { @@ -181,7 +197,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