diff --git a/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/lib/Transforms/InstCombine/InstCombineAddSub.cpp index 2e0d3bf0a24..2ed616f4ed7 100644 --- a/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -2143,9 +2143,19 @@ static Instruction *foldFNegIntoConstant(Instruction &I) { if (match(FNegOp, m_FDiv(m_Value(X), m_Constant(C)))) return BinaryOperator::CreateFDivFMF(X, ConstantExpr::getFNeg(C), &I); // -(C / X) --> (-C) / X - if (match(FNegOp, m_FDiv(m_Constant(C), m_Value(X)))) - return BinaryOperator::CreateFDivFMF(ConstantExpr::getFNeg(C), X, &I); + if (match(FNegOp, m_FDiv(m_Constant(C), m_Value(X)))) { + Instruction *FDiv = + BinaryOperator::CreateFDivFMF(ConstantExpr::getFNeg(C), X, &I); + // Intersect 'nsz' and 'ninf' because those special value exceptions may not + // apply to the fdiv. Everything else propagates from the fneg. + // TODO: We could propagate nsz/ninf from fdiv alone? + FastMathFlags FMF = I.getFastMathFlags(); + FastMathFlags OpFMF = FNegOp->getFastMathFlags(); + FDiv->setHasNoSignedZeros(FMF.noSignedZeros() & OpFMF.noSignedZeros()); + FDiv->setHasNoInfs(FMF.noInfs() & OpFMF.noInfs()); + return FDiv; + } // With NSZ [ counter-example with -0.0: -(-0.0 + 0.0) != 0.0 + -0.0 ]: // -(X + C) --> -X + -C --> -C - X if (I.hasNoSignedZeros() && match(FNegOp, m_FAdd(m_Value(X), m_Constant(C)))) diff --git a/test/Transforms/InstCombine/fneg.ll b/test/Transforms/InstCombine/fneg.ll index 62d2f105e69..50371f60932 100644 --- a/test/Transforms/InstCombine/fneg.ll +++ b/test/Transforms/InstCombine/fneg.ll @@ -237,7 +237,7 @@ define float @fdiv_op0_constant_fneg_fast_fast(float %x) { define float @fdiv_op0_constant_fneg_fast(float %x) { ; CHECK-LABEL: @fdiv_op0_constant_fneg_fast( -; CHECK-NEXT: [[R:%.*]] = fdiv fast float -4.200000e+01, [[X:%.*]] +; CHECK-NEXT: [[R:%.*]] = fdiv reassoc nnan arcp contract afn float -4.200000e+01, [[X:%.*]] ; CHECK-NEXT: ret float [[R]] ; %d = fdiv float 42.0, %x @@ -257,7 +257,7 @@ define float @fdiv_op0_constant_fneg_nsz_nsz(float %x) { define float @fdiv_op0_constant_fneg_nsz(float %x) { ; CHECK-LABEL: @fdiv_op0_constant_fneg_nsz( -; CHECK-NEXT: [[R:%.*]] = fdiv nsz float -4.200000e+01, [[X:%.*]] +; CHECK-NEXT: [[R:%.*]] = fdiv float -4.200000e+01, [[X:%.*]] ; CHECK-NEXT: ret float [[R]] ; %d = fdiv float 42.0, %x @@ -277,7 +277,7 @@ define float @fdiv_op0_constant_fneg_ninf_ninf(float %x) { define float @fdiv_op0_constant_fneg_ninf(float %x) { ; CHECK-LABEL: @fdiv_op0_constant_fneg_ninf( -; CHECK-NEXT: [[R:%.*]] = fdiv ninf float -4.200000e+01, [[X:%.*]] +; CHECK-NEXT: [[R:%.*]] = fdiv float -4.200000e+01, [[X:%.*]] ; CHECK-NEXT: ret float [[R]] ; %d = fdiv float 42.0, %x