diff --git a/llvm/lib/Transforms/Scalar/Reassociate.cpp b/llvm/lib/Transforms/Scalar/Reassociate.cpp index d91320863e241..971cf88c3394d 100644 --- a/llvm/lib/Transforms/Scalar/Reassociate.cpp +++ b/llvm/lib/Transforms/Scalar/Reassociate.cpp @@ -287,11 +287,15 @@ static Instruction *CreateNeg(Value *S1, const Twine &Name, static BinaryOperator *LowerNegateToMultiply(Instruction *Neg) { assert((isa(Neg) || isa(Neg)) && "Expected a Negate!"); - // FIXME: It's not safe to lower a unary FNeg into a FMul by -1.0. unsigned OpNo = isa(Neg) ? 1 : 0; Type *Ty = Neg->getType(); - Constant *NegOne = Ty->isIntOrIntVectorTy() ? - ConstantInt::getAllOnesValue(Ty) : ConstantFP::get(Ty, -1.0); + // Only lower to FMul if the operation is not a unary FNeg or Neg has the + // correct flags. + if (Ty->isFPOrFPVectorTy() && isa(Neg) && !Neg->hasNoNaNs()) + return nullptr; + + Constant *NegOne = Ty->isIntOrIntVectorTy() ? ConstantInt::getAllOnesValue(Ty) + : ConstantFP::get(Ty, -1.0); BinaryOperator *Res = CreateMul(Neg->getOperand(OpNo), NegOne, "", Neg->getIterator(), Neg); diff --git a/llvm/test/Transforms/Reassociate/fast-basictest.ll b/llvm/test/Transforms/Reassociate/fast-basictest.ll index c1842d0cde456..cd0be7aed86c3 100644 --- a/llvm/test/Transforms/Reassociate/fast-basictest.ll +++ b/llvm/test/Transforms/Reassociate/fast-basictest.ll @@ -578,3 +578,61 @@ define float @test18(float %A, float %B) { %Z = fadd fast float %Y, 1.200000e+01 ret float %Z } + +; Do not fneg fast float unless it has nnan + +define float @scalar(float %a) { +; CHECK-LABEL: @scalar( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[NEG:%.*]] = fmul fast float [[A:%.*]], 2.000000e+00 +; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[NEG]], [[A]] +; CHECK-NEXT: ret float [[MUL]] +; +entry: + %b = fmul fast float %a, -2.0 + %neg = fneg fast float %a + %mul = fmul fast float %neg, %b + ret float %mul +} + +define float @scalar_nnan(float %a) { +; CHECK-LABEL: @scalar_nnan( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[NEG:%.*]] = fmul fast float [[A:%.*]], 2.000000e+00 +; CHECK-NEXT: [[MUL:%.*]] = fmul fast float [[NEG]], [[A]] +; CHECK-NEXT: ret float [[MUL]] +; +entry: + %b = fmul fast nnan float %a, -2.0 + %neg = fneg fast nnan float %a + %mul = fmul fast nnan float %neg, %b + ret float %mul +} + +define <4 x float> @vector(<4 x float> %a) { +; CHECK-LABEL: @vector( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[NEG:%.*]] = fmul fast <4 x float> [[A:%.*]], +; CHECK-NEXT: [[MUL:%.*]] = fmul fast <4 x float> [[NEG]], [[A]] +; CHECK-NEXT: ret <4 x float> [[MUL]] +; +entry: + %b = fmul fast <4 x float> %a, + %neg = fneg fast <4 x float> %a + %mul = fmul fast <4 x float> %neg, %b + ret <4 x float> %mul +} + +define <4 x float> @vector_nnan(<4 x float> %a) { +; CHECK-LABEL: @vector_nnan( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[NEG:%.*]] = fmul fast <4 x float> [[A:%.*]], +; CHECK-NEXT: [[MUL:%.*]] = fmul fast <4 x float> [[NEG]], [[A]] +; CHECK-NEXT: ret <4 x float> [[MUL]] +; +entry: + %b = fmul fast nnan <4 x float> %a, + %neg = fneg fast nnan <4 x float> %a + %mul = fmul fast <4 x float> %neg, %b + ret <4 x float> %mul +}