Index: lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -6941,6 +6941,7 @@ // Attempt different variants of (fadd (fmul a, b), c) -> fma or fmad static SDValue performFaddFmulCombines(unsigned FusedOpcode, bool Aggressive, + bool ArrangeFPExt, SDNode *N, const TargetLowering &TLI, SelectionDAG &DAG) { @@ -6948,10 +6949,12 @@ SDValue N1 = N->getOperand(1); EVT VT = N->getValueType(0); + SDLoc SL(N); + // fold (fadd (fmul x, y), z) -> (fma x, y, z) if (N0.getOpcode() == ISD::FMUL && (Aggressive || N0->hasOneUse())) { - return DAG.getNode(FusedOpcode, SDLoc(N), VT, + return DAG.getNode(FusedOpcode, SL, VT, N0.getOperand(0), N0.getOperand(1), N1); } @@ -6959,18 +6962,44 @@ // Note: Commutes FADD operands. if (N1.getOpcode() == ISD::FMUL && (Aggressive || N1->hasOneUse())) { - return DAG.getNode(FusedOpcode, SDLoc(N), VT, + return DAG.getNode(FusedOpcode, SL, VT, N1.getOperand(0), N1.getOperand(1), N0); } + // When possible, arrange FP_EXTEND nodes to do more combining. + if (ArrangeFPExt) { + // fold (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) + if (N0.getOpcode() == ISD::FP_EXTEND) { + SDValue N00 = N0.getOperand(0); + if (N00.getOpcode() == ISD::FMUL) + return DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N00.getOperand(0)), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N00.getOperand(1)), N1); + } + + // fold (fadd x, (fpext (fmul y, z)), z) -> (fma (fpext y), (fpext z), x) + // Note: Commutes FADD operands. + if (N1.getOpcode() == ISD::FP_EXTEND) { + SDValue N10 = N1.getOperand(0); + if (N10.getOpcode() == ISD::FMUL) + return DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N10.getOperand(0)), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N10.getOperand(1)), N0); + } + } + // More folding opportunities when target permits. if (Aggressive) { // fold (fadd (fma x, y, (fmul u, v)), z) -> (fma x, y (fma u, v, z)) if (N0.getOpcode() == ISD::FMA && N0.getOperand(2).getOpcode() == ISD::FMUL) { - return DAG.getNode(FusedOpcode, SDLoc(N), VT, + return DAG.getNode(FusedOpcode, SL, VT, N0.getOperand(0), N0.getOperand(1), - DAG.getNode(FusedOpcode, SDLoc(N), VT, + DAG.getNode(FusedOpcode, SL, VT, N0.getOperand(2).getOperand(0), N0.getOperand(2).getOperand(1), N1)); @@ -6979,13 +7008,95 @@ // fold (fadd x, (fma y, z, (fmul u, v)) -> (fma y, z (fma u, v, x)) if (N1->getOpcode() == ISD::FMA && N1.getOperand(2).getOpcode() == ISD::FMUL) { - return DAG.getNode(FusedOpcode, SDLoc(N), VT, + return DAG.getNode(FusedOpcode, SL, VT, N1.getOperand(0), N1.getOperand(1), - DAG.getNode(FusedOpcode, SDLoc(N), VT, + DAG.getNode(FusedOpcode, SL, VT, N1.getOperand(2).getOperand(0), N1.getOperand(2).getOperand(1), N0)); } + + if (ArrangeFPExt) { + // fold (fadd (fma x, y, (fpext (fmul u, v))), z) + // -> (fma x, y, (fma (fpext u), (fpext v), z)) + if (N0.getOpcode() == ISD::FMA) { + SDValue N02 = N0.getOperand(2); + if (N02.getOpcode() == ISD::FP_EXTEND) { + SDValue N020 = N02.getOperand(0); + if (N020.getOpcode() == ISD::FMUL) + return DAG.getNode(ISD::FMA, SL, VT, + N0.getOperand(0), + N0.getOperand(1), + DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N020.getOperand(0)), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N020.getOperand(1)), + N1)); + } + } + + // fold (fadd (fpext (fma x, y, (fmul u, v))), z) + // -> (fma (fpext x), (fpext y), (fma (fpext u), (fpext v), z)) + if (N0.getOpcode() == ISD::FP_EXTEND) { + SDValue N00 = N0.getOperand(0); + if (N00.getOpcode() == ISD::FMA) { + SDValue N002 = N00.getOperand(2); + if (N002.getOpcode() == ISD::FMUL) + return DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N00.getOperand(0)), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N00.getOperand(1)), + DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N002.getOperand(0)), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N002.getOperand(1)), + N1)); + } + } + + // fold (fadd x, (fma y, z, (fpext (fmul u, v))) + // -> (fma y, z, (fma (fpext u), (fpext v), x)) + if (N1.getOpcode() == ISD::FMA) { + SDValue N12 = N1.getOperand(2); + if (N12.getOpcode() == ISD::FP_EXTEND) { + SDValue N120 = N12.getOperand(0); + if (N120.getOpcode() == ISD::FMUL) + return DAG.getNode(ISD::FMA, SL, VT, + N1.getOperand(0), + N1.getOperand(1), + DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N120.getOperand(0)), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N120.getOperand(1)), + N0)); + } + } + + // fold (fadd x, (fpext (fma y, z, (fmul u, v))) + // -> (fma (fpext y), (fpext z), (fma (fpext u), (fpext v), x)) + if (N1.getOpcode() == ISD::FP_EXTEND) { + SDValue N10 = N1.getOperand(0); + if (N10.getOpcode() == ISD::FMA) { + SDValue N102 = N10.getOperand(2); + if (N102.getOpcode() == ISD::FMUL) + return DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N10.getOperand(0)), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N10.getOperand(1)), + DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N102.getOperand(0)), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N102.getOperand(1)), + N0)); + } + } + } } return SDValue(); @@ -6993,6 +7104,7 @@ static SDValue performFsubFmulCombines(unsigned FusedOpcode, bool Aggressive, + bool ArrangeFPExt, SDNode *N, const TargetLowering &TLI, SelectionDAG &DAG) { @@ -7030,18 +7142,85 @@ DAG.getNode(ISD::FNEG, SL, VT, N1)); } + // When possible, arrange FP_EXTEND nodes to do more combining. + if (ArrangeFPExt) { + // fold (fsub (fpext (fmul x, y)), z) + // -> (fma (fpext x), (fpext y), (fneg z)) + if (N0.getOpcode() == ISD::FP_EXTEND) { + SDValue N00 = N0.getOperand(0); + if (N00.getOpcode() == ISD::FMUL) + return DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N00.getOperand(0)), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N00.getOperand(1)), + DAG.getNode(ISD::FNEG, SL, VT, N1)); + } + + // fold (fsub x, (fpext (fmul y, z))) + // -> (fma (fneg (fpext y)), (fpext z), x) + // Note: Commutes FSUB operands. + if (N1.getOpcode() == ISD::FP_EXTEND) { + SDValue N10 = N1.getOperand(0); + if (N10.getOpcode() == ISD::FMUL) + return DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FNEG, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N10.getOperand(0))), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N10.getOperand(1)), + N0); + } + + // fold (fsub (fpext (fneg (fmul, x, y))), z) + // -> (fma (fneg (fpext x)), (fpext y), (fneg z)) + if (N0.getOpcode() == ISD::FP_EXTEND) { + SDValue N00 = N0.getOperand(0); + if (N00.getOpcode() == ISD::FNEG) { + SDValue N000 = N00.getOperand(0); + if (N000.getOpcode() == ISD::FMUL) { + return DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FNEG, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N000.getOperand(0))), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N000.getOperand(1)), + DAG.getNode(ISD::FNEG, SL, VT, N1)); + } + } + } + + // fold (fsub (fneg (fpext (fmul, x, y))), z) + // -> (fma (fneg (fpext x)), (fpext y), (fneg z)) + if (N0.getOpcode() == ISD::FNEG) { + SDValue N00 = N0.getOperand(0); + if (N00.getOpcode() == ISD::FP_EXTEND) { + SDValue N000 = N00.getOperand(0); + if (N000.getOpcode() == ISD::FMUL) { + return DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FNEG, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N000.getOperand(0))), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N000.getOperand(1)), + DAG.getNode(ISD::FNEG, SL, VT, N1)); + } + } + } + } + // More folding opportunities when target permits. if (Aggressive) { // fold (fsub (fma x, y, (fmul u, v)), z) // -> (fma x, y (fma u, v, (fneg z))) if (N0.getOpcode() == FusedOpcode && N0.getOperand(2).getOpcode() == ISD::FMUL) { - return DAG.getNode(FusedOpcode, SDLoc(N), VT, + return DAG.getNode(FusedOpcode, SL, VT, N0.getOperand(0), N0.getOperand(1), - DAG.getNode(FusedOpcode, SDLoc(N), VT, + DAG.getNode(FusedOpcode, SL, VT, N0.getOperand(2).getOperand(0), N0.getOperand(2).getOperand(1), - DAG.getNode(ISD::FNEG, SDLoc(N), VT, + DAG.getNode(ISD::FNEG, SL, VT, N1))); } @@ -7051,15 +7230,105 @@ N1.getOperand(2).getOpcode() == ISD::FMUL) { SDValue N20 = N1.getOperand(2).getOperand(0); SDValue N21 = N1.getOperand(2).getOperand(1); - return DAG.getNode(FusedOpcode, SDLoc(N), VT, - DAG.getNode(ISD::FNEG, SDLoc(N), VT, + return DAG.getNode(FusedOpcode, SL, VT, + DAG.getNode(ISD::FNEG, SL, VT, N1.getOperand(0)), N1.getOperand(1), - DAG.getNode(FusedOpcode, SDLoc(N), VT, - DAG.getNode(ISD::FNEG, SDLoc(N), VT, - N20), + DAG.getNode(FusedOpcode, SL, VT, + DAG.getNode(ISD::FNEG, SL, VT, N20), N21, N0)); } + + if (ArrangeFPExt) { + // fold (fsub (fma x, y, (fpext (fmul u, v))), z) + // -> (fma x, y (fma (fpext u), (fpext v), (fneg z))) + if (N0.getOpcode() == ISD::FMA) { + SDValue N02 = N0.getOperand(2); + if (N02.getOpcode() == ISD::FP_EXTEND) { + SDValue N020 = N02.getOperand(0); + if (N020.getOpcode() == ISD::FMUL) + return DAG.getNode(ISD::FMA, SL, VT, + N0.getOperand(0), N0.getOperand(1), + DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N020.getOperand(0)), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N020.getOperand(1)), + DAG.getNode(ISD::FNEG, SL, VT, + N1))); + } + } + + // fold (fsub (fpext (fma x, y, (fmul u, v))), z) + // -> (fma (fpext x), (fpext y), + // (fma (fpext u), (fpext v), (fneg z))) + if (N0.getOpcode() == ISD::FP_EXTEND) { + SDValue N00 = N0.getOperand(0); + if (N00.getOpcode() == ISD::FMA) { + SDValue N002 = N00.getOperand(2); + if (N002.getOpcode() == ISD::FMUL) + return DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N00.getOperand(0)), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N00.getOperand(1)), + DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N002.getOperand(0)), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N002.getOperand(1)), + DAG.getNode(ISD::FNEG, SL, VT, + N1))); + } + } + + // fold (fsub x, (fma y, z, (fpext (fmul u, v)))) + // -> (fma (fneg y), z, (fma (fneg (fpext u)), (fpext v), x)) + if (N1.getOpcode() == ISD::FMA && + N1.getOperand(2).getOpcode() == ISD::FP_EXTEND) { + SDValue N120 = N1.getOperand(2).getOperand(0); + if (N120.getOpcode() == ISD::FMUL) { + SDValue N1200 = N120.getOperand(0); + SDValue N1201 = N120.getOperand(1); + return DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FNEG, SL, VT, N1.getOperand(0)), + N1.getOperand(1), + DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FNEG, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, + VT, N1200)), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N1201), + N0)); + } + } + + // fold (fsub x, (fpext (fma y, z, (fmul u, v)))) + // -> (fma (fneg (fpext y)), (fpext z), + // (fma (fneg (fpext u)), (fpext v), x)) + if (N1.getOpcode() == ISD::FP_EXTEND && + N1.getOperand(0).getOpcode() == ISD::FMA) { + SDValue N100 = N1.getOperand(0).getOperand(0); + SDValue N101 = N1.getOperand(0).getOperand(1); + SDValue N102 = N1.getOperand(0).getOperand(2); + if (N102.getOpcode() == ISD::FMUL) { + SDValue N1020 = N102.getOperand(0); + SDValue N1021 = N102.getOperand(1); + return DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FNEG, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N100)), + DAG.getNode(ISD::FP_EXTEND, SL, VT, N101), + DAG.getNode(ISD::FMA, SL, VT, + DAG.getNode(ISD::FNEG, SL, VT, + DAG.getNode(ISD::FP_EXTEND, SL, + VT, N1020)), + DAG.getNode(ISD::FP_EXTEND, SL, VT, + N1021), + N0)); + } + } + } } return SDValue(); @@ -7207,7 +7476,7 @@ if (LegalOperations && TLI.isOperationLegal(ISD::FMAD, VT)) { // Assume if there is an fmad instruction that it should be aggressively // used. - if (SDValue Fused = performFaddFmulCombines(ISD::FMAD, true, N, TLI, DAG)) + if (SDValue Fused = performFaddFmulCombines(ISD::FMAD, true, false, N, TLI, DAG)) return Fused; } @@ -7221,38 +7490,11 @@ if (SDValue Fused = performFaddFmulCombines(ISD::FMA, TLI.enableAggressiveFMAFusion(VT), + TLI.isFPExtFree(VT), N, TLI, DAG)) { return Fused; } } - - // When FP_EXTEND nodes are free on the target, and there is an opportunity - // to combine into FMA, arrange such nodes accordingly. - if (TLI.isFPExtFree(VT)) { - - // fold (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z) - if (N0.getOpcode() == ISD::FP_EXTEND) { - SDValue N00 = N0.getOperand(0); - if (N00.getOpcode() == ISD::FMUL) - return DAG.getNode(ISD::FMA, SDLoc(N), VT, - DAG.getNode(ISD::FP_EXTEND, SDLoc(N), VT, - N00.getOperand(0)), - DAG.getNode(ISD::FP_EXTEND, SDLoc(N), VT, - N00.getOperand(1)), N1); - } - - // fold (fadd x, (fpext (fmul y, z)), z) -> (fma (fpext y), (fpext z), x) - // Note: Commutes FADD operands. - if (N1.getOpcode() == ISD::FP_EXTEND) { - SDValue N10 = N1.getOperand(0); - if (N10.getOpcode() == ISD::FMUL) - return DAG.getNode(ISD::FMA, SDLoc(N), VT, - DAG.getNode(ISD::FP_EXTEND, SDLoc(N), VT, - N10.getOperand(0)), - DAG.getNode(ISD::FP_EXTEND, SDLoc(N), VT, - N10.getOperand(1)), N0); - } - } } return SDValue(); @@ -7317,7 +7559,7 @@ if (LegalOperations && TLI.isOperationLegal(ISD::FMAD, VT)) { // Assume if there is an fmad instruction that it should be aggressively // used. - if (SDValue Fused = performFsubFmulCombines(ISD::FMAD, true, N, TLI, DAG)) + if (SDValue Fused = performFsubFmulCombines(ISD::FMAD, true, false, N, TLI, DAG)) return Fused; } @@ -7332,78 +7574,11 @@ if (SDValue Fused = performFsubFmulCombines(ISD::FMA, TLI.enableAggressiveFMAFusion(VT), + TLI.isFPExtFree(VT), N, TLI, DAG)) { return Fused; } } - - // When FP_EXTEND nodes are free on the target, and there is an opportunity - // to combine into FMA, arrange such nodes accordingly. - if (TLI.isFPExtFree(VT)) { - // fold (fsub (fpext (fmul x, y)), z) - // -> (fma (fpext x), (fpext y), (fneg z)) - if (N0.getOpcode() == ISD::FP_EXTEND) { - SDValue N00 = N0.getOperand(0); - if (N00.getOpcode() == ISD::FMUL) - return DAG.getNode(ISD::FMA, SDLoc(N), VT, - DAG.getNode(ISD::FP_EXTEND, SDLoc(N), VT, - N00.getOperand(0)), - DAG.getNode(ISD::FP_EXTEND, SDLoc(N), VT, - N00.getOperand(1)), - DAG.getNode(ISD::FNEG, SDLoc(N), VT, N1)); - } - - // fold (fsub x, (fpext (fmul y, z))) - // -> (fma (fneg (fpext y)), (fpext z), x) - // Note: Commutes FSUB operands. - if (N1.getOpcode() == ISD::FP_EXTEND) { - SDValue N10 = N1.getOperand(0); - if (N10.getOpcode() == ISD::FMUL) - return DAG.getNode(ISD::FMA, SDLoc(N), VT, - DAG.getNode(ISD::FNEG, SDLoc(N), VT, - DAG.getNode(ISD::FP_EXTEND, SDLoc(N), - VT, N10.getOperand(0))), - DAG.getNode(ISD::FP_EXTEND, SDLoc(N), VT, - N10.getOperand(1)), - N0); - } - - // fold (fsub (fpext (fneg (fmul, x, y))), z) - // -> (fma (fneg (fpext x)), (fpext y), (fneg z)) - if (N0.getOpcode() == ISD::FP_EXTEND) { - SDValue N00 = N0.getOperand(0); - if (N00.getOpcode() == ISD::FNEG) { - SDValue N000 = N00.getOperand(0); - if (N000.getOpcode() == ISD::FMUL) { - return DAG.getNode(ISD::FMA, dl, VT, - DAG.getNode(ISD::FNEG, dl, VT, - DAG.getNode(ISD::FP_EXTEND, SDLoc(N), - VT, N000.getOperand(0))), - DAG.getNode(ISD::FP_EXTEND, SDLoc(N), VT, - N000.getOperand(1)), - DAG.getNode(ISD::FNEG, dl, VT, N1)); - } - } - } - - // fold (fsub (fneg (fpext (fmul, x, y))), z) - // -> (fma (fneg (fpext x)), (fpext y), (fneg z)) - if (N0.getOpcode() == ISD::FNEG) { - SDValue N00 = N0.getOperand(0); - if (N00.getOpcode() == ISD::FP_EXTEND) { - SDValue N000 = N00.getOperand(0); - if (N000.getOpcode() == ISD::FMUL) { - return DAG.getNode(ISD::FMA, dl, VT, - DAG.getNode(ISD::FNEG, dl, VT, - DAG.getNode(ISD::FP_EXTEND, SDLoc(N), - VT, N000.getOperand(0))), - DAG.getNode(ISD::FP_EXTEND, SDLoc(N), VT, - N000.getOperand(1)), - DAG.getNode(ISD::FNEG, dl, VT, N1)); - } - } - } - } } return SDValue(); Index: test/CodeGen/PowerPC/fma-assoc.ll =================================================================== --- test/CodeGen/PowerPC/fma-assoc.ll +++ test/CodeGen/PowerPC/fma-assoc.ll @@ -77,3 +77,159 @@ ; CHECK-VSX-NEXT: blr } +define double @test_FMADD_ASSOC_EXT1(float %A, float %B, double %C, + double %D, double %E) { + %F = fmul float %A, %B ; [#uses=1] + %G = fpext float %F to double ; [#uses=1] + %H = fmul double %C, %D ; [#uses=1] + %I = fadd double %H, %G ; [#uses=1] + %J = fadd double %I, %E ; [#uses=1] + ret double %J +; CHECK-LABEL: test_FMADD_ASSOC_EXT1: +; CHECK: fmadd +; CHECK-NEXT: fmadd +; CHECK-NEXT: blr + +; CHECK-VSX-LABEL: test_FMADD_ASSOC_EXT1: +; CHECK-VSX: xsmaddmdp +; CHECK-VSX-NEXT: xsmaddadp +; CHECK-VSX-NEXT: blr +} + +define double @test_FMADD_ASSOC_EXT2(float %A, float %B, float %C, + float %D, double %E) { + %F = fmul float %A, %B ; [#uses=1] + %G = fmul float %C, %D ; [#uses=1] + %H = fadd float %F, %G ; [#uses=1] + %I = fpext float %H to double ; [#uses=1] + %J = fadd double %I, %E ; [#uses=1] + ret double %J +; CHECK-LABEL: test_FMADD_ASSOC_EXT2: +; CHECK: fmadd +; CHECK-NEXT: fmadd +; CHECK-NEXT: blr + +; CHECK-VSX-LABEL: test_FMADD_ASSOC_EXT2: +; CHECK-VSX: xsmaddmdp +; CHECK-VSX-NEXT: xsmaddadp +; CHECK-VSX-NEXT: fmr +; CHECK-VSX-NEXT: blr +} + +define double @test_FMADD_ASSOC_EXT3(float %A, float %B, double %C, + double %D, double %E) { + %F = fmul float %A, %B ; [#uses=1] + %G = fpext float %F to double ; [#uses=1] + %H = fmul double %C, %D ; [#uses=1] + %I = fadd double %H, %G ; [#uses=1] + %J = fadd double %E, %I ; [#uses=1] + ret double %J +; CHECK-LABEL: test_FMADD_ASSOC_EXT3: +; CHECK: fmadd +; CHECK-NEXT: fmadd +; CHECK-NEXT: blr + +; CHECK-VSX-LABEL: test_FMADD_ASSOC_EXT3: +; CHECK-VSX: xsmaddmdp +; CHECK-VSX-NEXT: xsmaddadp +; CHECK-VSX-NEXT: blr +} + +define double @test_FMADD_ASSOC_EXT4(float %A, float %B, float %C, + float %D, double %E) { + %F = fmul float %A, %B ; [#uses=1] + %G = fmul float %C, %D ; [#uses=1] + %H = fadd float %F, %G ; [#uses=1] + %I = fpext float %H to double ; [#uses=1] + %J = fadd double %E, %I ; [#uses=1] + ret double %J +; CHECK-LABEL: test_FMADD_ASSOC_EXT4: +; CHECK: fmadd +; CHECK-NEXT: fmadd +; CHECK-NEXT: blr + +; CHECK-VSX-LABEL: test_FMADD_ASSOC_EXT4: +; CHECK-VSX: xsmaddmdp +; CHECK-VSX-NEXT: xsmaddadp +; CHECK-VSX-NEXT: fmr +; CHECK-VSX-NEXT: blr +} + +define double @test_FMSUB_ASSOC_EXT1(float %A, float %B, double %C, + double %D, double %E) { + %F = fmul float %A, %B ; [#uses=1] + %G = fpext float %F to double ; [#uses=1] + %H = fmul double %C, %D ; [#uses=1] + %I = fadd double %H, %G ; [#uses=1] + %J = fsub double %I, %E ; [#uses=1] + ret double %J +; CHECK-LABEL: test_FMSUB_ASSOC_EXT1: +; CHECK: fmsub +; CHECK-NEXT: fmadd +; CHECK-NEXT: blr + +; CHECK-VSX-LABEL: test_FMSUB_ASSOC_EXT1: +; CHECK-VSX: xsmsubmdp +; CHECK-VSX-NEXT: xsmaddadp +; CHECK-VSX-NEXT: blr +} + +define double @test_FMSUB_ASSOC_EXT2(float %A, float %B, float %C, + float %D, double %E) { + %F = fmul float %A, %B ; [#uses=1] + %G = fmul float %C, %D ; [#uses=1] + %H = fadd float %F, %G ; [#uses=1] + %I = fpext float %H to double ; [#uses=1] + %J = fsub double %I, %E ; [#uses=1] + ret double %J +; CHECK-LABEL: test_FMSUB_ASSOC_EXT2: +; CHECK: fmsub +; CHECK-NEXT: fmadd +; CHECK-NEXT: blr + +; CHECK-VSX-LABEL: test_FMSUB_ASSOC_EXT2: +; CHECK-VSX: xsmsubmdp +; CHECK-VSX-NEXT: xsmaddadp +; CHECK-VSX-NEXT: fmr +; CHECK-VSX-NEXT: blr +} + +define double @test_FMSUB_ASSOC_EXT3(float %A, float %B, double %C, + double %D, double %E) { + %F = fmul float %A, %B ; [#uses=1] + %G = fpext float %F to double ; [#uses=1] + %H = fmul double %C, %D ; [#uses=1] + %I = fadd double %H, %G ; [#uses=1] + %J = fsub double %E, %I ; [#uses=1] + ret double %J +; CHECK-LABEL: test_FMSUB_ASSOC_EXT3: +; CHECK: fnmsub +; CHECK-NEXT: fnmsub +; CHECK-NEXT: blr + +; CHECK-VSX-LABEL: test_FMSUB_ASSOC_EXT3: +; CHECK-VSX: xsnmsubmdp +; CHECK-VSX-NEXT: xsnmsubadp +; CHECK-VSX-NEXT: fmr +; CHECK-VSX-NEXT: blr +} + +define double @test_FMSUB_ASSOC_EXT4(float %A, float %B, float %C, + float %D, double %E) { + %F = fmul float %A, %B ; [#uses=1] + %G = fmul float %C, %D ; [#uses=1] + %H = fadd float %F, %G ; [#uses=1] + %I = fpext float %H to double ; [#uses=1] + %J = fsub double %E, %I ; [#uses=1] + ret double %J +; CHECK-LABEL: test_FMSUB_ASSOC_EXT4: +; CHECK: fnmsub +; CHECK-NEXT: fnmsub +; CHECK-NEXT: blr + +; CHECK-VSX-LABEL: test_FMSUB_ASSOC_EXT4: +; CHECK-VSX: xsnmsubmdp +; CHECK-VSX-NEXT: xsnmsubadp +; CHECK-VSX-NEXT: fmr +; CHECK-VSX-NEXT: blr +} \ No newline at end of file