diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp index 72a6e64ccdc10..8eeeccbc86523 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -2987,9 +2987,13 @@ static Instruction *foldFNegIntoConstant(Instruction &I, const DataLayout &DL) { return BinaryOperator::CreateFMulFMF(X, NegC, FMF); } // -(X / C) --> X / (-C) - if (match(FNegOp, m_FDiv(m_Value(X), m_Constant(C)))) - if (Constant *NegC = ConstantFoldUnaryOpOperand(Instruction::FNeg, C, DL)) - return BinaryOperator::CreateFDivFMF(X, NegC, &I); + if (match(FNegOp, m_FDiv(m_Value(X), m_Constant(C)))) { + if (Constant *NegC = ConstantFoldUnaryOpOperand(Instruction::FNeg, C, DL)) { + Instruction *FDiv = BinaryOperator::CreateFDivFMF(X, NegC, &I); + FDiv->copyMetadata(*FNegOp); + return FDiv; + } + } // -(C / X) --> (-C) / X if (match(FNegOp, m_FDiv(m_Constant(C), m_Value(X)))) if (Constant *NegC = ConstantFoldUnaryOpOperand(Instruction::FNeg, C, DL)) { @@ -3002,6 +3006,7 @@ static Instruction *foldFNegIntoConstant(Instruction &I, const DataLayout &DL) { FastMathFlags OpFMF = FNegOp->getFastMathFlags(); FDiv->setHasNoSignedZeros(FMF.noSignedZeros() && OpFMF.noSignedZeros()); FDiv->setHasNoInfs(FMF.noInfs() && OpFMF.noInfs()); + FDiv->copyMetadata(*FNegOp); return FDiv; } // With NSZ [ counter-example with -0.0: -(-0.0 + 0.0) != 0.0 + -0.0 ]: @@ -3024,8 +3029,10 @@ Instruction *InstCombinerImpl::hoistFNegAboveFMulFDiv(Value *FNegOp, } if (match(FNegOp, m_FDiv(m_Value(X), m_Value(Y)))) { - return cast(Builder.CreateFDivFMF( + auto *FDiv = cast(Builder.CreateFDivFMF( Builder.CreateFNegFMF(X, &FMFSource), Y, &FMFSource)); + FDiv->copyMetadata(*cast(FNegOp)); + return FDiv; } if (IntrinsicInst *II = dyn_cast(FNegOp)) { diff --git a/llvm/test/Transforms/InstCombine/fneg.ll b/llvm/test/Transforms/InstCombine/fneg.ll index 4e6477f804314..ed4d43eaea235 100644 --- a/llvm/test/Transforms/InstCombine/fneg.ll +++ b/llvm/test/Transforms/InstCombine/fneg.ll @@ -110,6 +110,19 @@ define <4 x double> @fmul_fneg_vec(<4 x double> %x) { ret <4 x double> %r } +; -(X / Y) --> (-X) / Y + +define float @fdiv_fneg_fpmath(float %x, float %y) { +; CHECK-LABEL: @fdiv_fneg_fpmath( +; CHECK-NEXT: [[NEG:%.*]] = fneg float [[X:%.*]] +; CHECK-NEXT: [[R:%.*]] = fdiv float [[NEG]], [[Y:%.*]], !fpmath +; CHECK-NEXT: ret float [[R]] +; + %z = fdiv arcp float %x, %y, !fpmath !{float 2.5} + %w = fneg float %z + ret float %w +} + ; -(X / C) --> X / (-C) define float @fdiv_op1_constant_fsub(float %x) { @@ -204,6 +217,16 @@ define <4 x double> @fdiv_op1_constant_fneg_vec(<4 x double> %x) { ret <4 x double> %r } +define float @fdiv_op1_constant_fneg_fpmath(float %x) { +; CHECK-LABEL: @fdiv_op1_constant_fneg_fpmath( +; CHECK-NEXT: [[R:%.*]] = fdiv float [[X:%.*]], 4.200000e+01, !fpmath +; CHECK-NEXT: ret float [[R]] +; + %d = fdiv float %x, -42.0, !fpmath !{float 2.5} + %r = fneg float %d + ret float %r +} + ; -(C / X) --> (-C) / X define float @fdiv_op0_constant_fsub(float %x) { @@ -308,6 +331,16 @@ define float @fdiv_op0_constant_fneg_nnan(float %x) { ret float %r } +define float @fdiv_op0_constant_fneg_fpmath(float %x) { +; CHECK-LABEL: @fdiv_op0_constant_fneg_fpmath( +; CHECK-NEXT: [[R:%.*]] = fdiv float -1.000000e+00, [[X:%.*]], !fpmath +; CHECK-NEXT: ret float [[R]] +; + %d = fdiv float 1.0, %x, !fpmath !{float 2.5} + %r = fneg float %d + ret float %r +} + ; Extra use prevents the fold. We don't want to replace the fneg with an fdiv. define float @fdiv_op0_constant_fsub_extra_use(float %x) {