diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index e9a38b1b437..f6dc9384ee3 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -701,6 +701,27 @@ static ConstantSDNode *isConstOrConstSplat(SDValue N) { return nullptr; } +// \brief Returns the SDNode if it is a constant splat BuildVector or constant +// float. +static ConstantFPSDNode *isConstOrConstSplatFP(SDValue N) { + if (ConstantFPSDNode *CN = dyn_cast(N)) + return CN; + + if (BuildVectorSDNode *BV = dyn_cast(N)) { + BitVector UndefElements; + ConstantFPSDNode *CN = BV->getConstantFPSplatNode(&UndefElements); + + // BuildVectors can truncate their operands. Ignore that case here. + // FIXME: We blindly ignore splats which include undef which is overly + // pessimistic. + if (CN && UndefElements.none() && + CN->getValueType(0) == N.getValueType().getScalarType()) + return CN; + } + + return nullptr; +} + SDValue DAGCombiner::ReassociateOps(unsigned Opc, SDLoc DL, SDValue N0, SDValue N1) { EVT VT = N0.getValueType(); @@ -6830,8 +6851,8 @@ SDValue DAGCombiner::visitFSUB(SDNode *N) { SDValue DAGCombiner::visitFMUL(SDNode *N) { SDValue N0 = N->getOperand(0); SDValue N1 = N->getOperand(1); - ConstantFPSDNode *N0CFP = dyn_cast(N0); - ConstantFPSDNode *N1CFP = dyn_cast(N1); + ConstantFPSDNode *N0CFP = isConstOrConstSplatFP(N0); + ConstantFPSDNode *N1CFP = isConstOrConstSplatFP(N1); EVT VT = N->getValueType(0); const TargetLowering &TLI = DAG.getTargetLoweringInfo(); @@ -6851,13 +6872,10 @@ SDValue DAGCombiner::visitFMUL(SDNode *N) { if (DAG.getTarget().Options.UnsafeFPMath && N1CFP && N1CFP->getValueAPF().isZero()) return N1; - // fold (fmul A, 0) -> 0, vector edition. - if (DAG.getTarget().Options.UnsafeFPMath && - ISD::isBuildVectorAllZeros(N1.getNode())) - return N1; // fold (fmul A, 1.0) -> A if (N1CFP && N1CFP->isExactlyValue(1.0)) return N0; + // fold (fmul X, 2.0) -> (fadd X, X) if (N1CFP && N1CFP->isExactlyValue(+2.0)) return DAG.getNode(ISD::FADD, SDLoc(N), VT, N0, N0); @@ -6883,10 +6901,11 @@ SDValue DAGCombiner::visitFMUL(SDNode *N) { // If allowed, fold (fmul (fmul x, c1), c2) -> (fmul x, (fmul c1, c2)) if (DAG.getTarget().Options.UnsafeFPMath && N1CFP && N0.getOpcode() == ISD::FMUL && - N0.getNode()->hasOneUse() && isa(N0.getOperand(1))) + N0.getNode()->hasOneUse() && isConstOrConstSplatFP(N0.getOperand(1))) { return DAG.getNode(ISD::FMUL, SDLoc(N), VT, N0.getOperand(0), DAG.getNode(ISD::FMUL, SDLoc(N), VT, N0.getOperand(1), N1)); + } return SDValue(); } diff --git a/test/CodeGen/Mips/msa/arithmetic_float.ll b/test/CodeGen/Mips/msa/arithmetic_float.ll index 86e57ac85a3..9aae284fe53 100644 --- a/test/CodeGen/Mips/msa/arithmetic_float.ll +++ b/test/CodeGen/Mips/msa/arithmetic_float.ll @@ -276,8 +276,8 @@ define void @fexp2_v4f32_2(<4 x float>* %c, <4 x float>* %a) nounwind { ; CHECK-DAG: ld.w [[R1:\$w[0-9]+]], 0($5) %2 = tail call <4 x float> @llvm.exp2.v4f32 (<4 x float> %1) %3 = fmul <4 x float> , %2 - ; CHECK-DAG: lui [[R3:\$[0-9]+]], 16384 - ; CHECK-DAG: fill.w [[R4:\$w[0-9]+]], [[R3]] + ; CHECK-DAG: ldi.w [[R3:\$w[0-9]+]], 1 + ; CHECK-DAG: ffint_u.w [[R4:\$w[0-9]+]], [[R3]] ; CHECK-DAG: fexp2.w [[R5:\$w[0-9]+]], [[R4]], [[R1]] store <4 x float> %3, <4 x float>* %c ; CHECK-DAG: st.w [[R5]], 0($4) @@ -287,16 +287,14 @@ define void @fexp2_v4f32_2(<4 x float>* %c, <4 x float>* %a) nounwind { } define void @fexp2_v2f64_2(<2 x double>* %c, <2 x double>* %a) nounwind { - ; CHECK: .8byte 4611686018427387904 - ; CHECK-NEXT: .8byte 4611686018427387904 ; CHECK: fexp2_v2f64_2: %1 = load <2 x double>* %a ; CHECK-DAG: ld.d [[R1:\$w[0-9]+]], 0($5) %2 = tail call <2 x double> @llvm.exp2.v2f64 (<2 x double> %1) %3 = fmul <2 x double> , %2 - ; CHECK-DAG: addiu [[G_PTR:\$[0-9]+]], {{.*}}, %lo($ - ; CHECK-DAG: ld.d [[R3:\$w[0-9]+]], 0([[G_PTR]]) + ; CHECK-DAG: ldi.d [[R2:\$w[0-9]+]], 1 + ; CHECK-DAG: ffint_u.d [[R3:\$w[0-9]+]], [[R2]] ; CHECK-DAG: fexp2.d [[R4:\$w[0-9]+]], [[R3]], [[R1]] store <2 x double> %3, <2 x double>* %c ; CHECK-DAG: st.d [[R4]], 0($4) diff --git a/test/CodeGen/X86/fmul-combines.ll b/test/CodeGen/X86/fmul-combines.ll new file mode 100644 index 00000000000..22632d3dd3e --- /dev/null +++ b/test/CodeGen/X86/fmul-combines.ll @@ -0,0 +1,99 @@ +; RUN: llc -march=x86-64 < %s | FileCheck %s + +; CHECK-LABEL: fmul2_f32: +; CHECK: addss %xmm0, %xmm0 +define float @fmul2_f32(float %x) { + %y = fmul float %x, 2.0 + ret float %y +} + +; fmul 2.0, x -> fadd x, x for vectors. + +; CHECK-LABEL: fmul2_v4f32: +; CHECK: addps %xmm0, %xmm0 +; CHECK-NEXT: retq +define <4 x float> @fmul2_v4f32(<4 x float> %x) { + %y = fmul <4 x float> %x, + ret <4 x float> %y +} + +; CHECK-LABEL: constant_fold_fmul_v4f32: +; CHECK: movaps +; CHECK-NEXT: ret +define <4 x float> @constant_fold_fmul_v4f32(<4 x float> %x) { + %y = fmul <4 x float> , + ret <4 x float> %y +} + +; CHECK-LABEL: fmul0_v4f32: +; CHECK: xorps %xmm0, %xmm0 +; CHECK-NEXT: retq +define <4 x float> @fmul0_v4f32(<4 x float> %x) #0 { + %y = fmul <4 x float> %x, + ret <4 x float> %y +} + +; CHECK-LABEL: fmul_c2_c4_v4f32: +; CHECK-NOT: addps +; CHECK: mulps +; CHECK-NOT: mulps +; CHECK-NEXT: ret +define <4 x float> @fmul_c2_c4_v4f32(<4 x float> %x) #0 { + %y = fmul <4 x float> %x, + %z = fmul <4 x float> %y, + ret <4 x float> %z +} + +; CHECK-LABEL: fmul_c3_c4_v4f32: +; CHECK-NOT: addps +; CHECK: mulps +; CHECK-NOT: mulps +; CHECK-NEXT: ret +define <4 x float> @fmul_c3_c4_v4f32(<4 x float> %x) #0 { + %y = fmul <4 x float> %x, + %z = fmul <4 x float> %y, + ret <4 x float> %z +} + +; CHECK-LABEL: fmul_c2_c4_f32: +; CHECK-NOT: addss +; CHECK: mulss +; CHECK-NOT: mulss +; CHECK-NEXT: ret +define float @fmul_c2_c4_f32(float %x) #0 { + %y = fmul float %x, 2.0 + %z = fmul float %y, 4.0 + ret float %z +} + +; CHECK-LABEL: fmul_c3_c4_f32: +; CHECK-NOT: addss +; CHECK: mulss +; CHECK-NOT: mulss +; CHECK-NET: ret +define float @fmul_c3_c4_f32(float %x) #0 { + %y = fmul float %x, 3.0 + %z = fmul float %y, 4.0 + ret float %z +} + +; CHECK-LABEL: fmul_fneg_fneg_f32: +; CHECK: mulss %xmm1, %xmm0 +; CHECK-NEXT: retq +define float @fmul_fneg_fneg_f32(float %x, float %y) { + %x.neg = fsub float -0.0, %x + %y.neg = fsub float -0.0, %y + %mul = fmul float %x.neg, %y.neg + ret float %mul +} +; CHECK-LABEL: fmul_fneg_fneg_v4f32: +; CHECK: mulps %xmm1, %xmm0 +; CHECK-NEXT: retq +define <4 x float> @fmul_fneg_fneg_v4f32(<4 x float> %x, <4 x float> %y) { + %x.neg = fsub <4 x float> , %x + %y.neg = fsub <4 x float> , %y + %mul = fmul <4 x float> %x.neg, %y.neg + ret <4 x float> %mul +} + +attributes #0 = { "less-precise-fpmad"="true" "no-infs-fp-math"="true" "no-nans-fp-math"="true" "unsafe-fp-math"="true" }