Index: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -12637,6 +12637,20 @@ DAG.getConstantFP(-1.0, DL, VT), Flags), Flags); } + + if (N2.getOpcode() == ISD::FNEG && !TLI.isFNegFree(VT)) { + // (fma (fneg x), y, (fneg z)) -> fneg (fma x, y, z) + if (N0.getOpcode() == ISD::FNEG && (N2.hasOneUse() || N0.hasOneUse())) + return DAG.getNode(ISD::FNEG, DL, VT, + DAG.getNode(ISD::FMA, DL, VT, N0.getOperand(0), N1, + N2.getOperand(0), Flags), Flags); + + // (fma x, (fneg y), (fneg z)) -> fneg (fma x, y, z) + if (N1.getOpcode() == ISD::FNEG && (N2.hasOneUse() || N1.hasOneUse())) + return DAG.getNode(ISD::FNEG, DL, VT, + DAG.getNode(ISD::FMA, DL, VT, N0, N1.getOperand(0), + N2.getOperand(0), Flags), Flags); + } } return SDValue(); Index: llvm/test/CodeGen/PowerPC/fma-combine.ll =================================================================== --- llvm/test/CodeGen/PowerPC/fma-combine.ll +++ llvm/test/CodeGen/PowerPC/fma-combine.ll @@ -6,14 +6,12 @@ define double @fma_combine1(double %a, double %b, double %c) { ; CHECK-FAST-LABEL: fma_combine1: ; CHECK-FAST: # %bb.0: # %entry -; CHECK-FAST-NEXT: xsnegdp 0, 3 -; CHECK-FAST-NEXT: xsmsubadp 1, 0, 2 +; CHECK-FAST-NEXT: xsnmaddadp 1, 3, 2 ; CHECK-FAST-NEXT: blr ; ; CHECK-FAST-NOVSX-LABEL: fma_combine1: ; CHECK-FAST-NOVSX: # %bb.0: # %entry -; CHECK-FAST-NOVSX-NEXT: fneg 0, 3 -; CHECK-FAST-NOVSX-NEXT: fmsub 1, 0, 2, 1 +; CHECK-FAST-NOVSX-NEXT: fnmadd 1, 3, 2, 1 ; CHECK-FAST-NOVSX-NEXT: blr ; ; CHECK-LABEL: fma_combine1: @@ -32,14 +30,12 @@ define double @fma_combine2(double %a, double %b, double %c) { ; CHECK-FAST-LABEL: fma_combine2: ; CHECK-FAST: # %bb.0: # %entry -; CHECK-FAST-NEXT: xsnegdp 0, 3 -; CHECK-FAST-NEXT: xsmsubadp 1, 2, 0 +; CHECK-FAST-NEXT: xsnmaddadp 1, 2, 3 ; CHECK-FAST-NEXT: blr ; ; CHECK-FAST-NOVSX-LABEL: fma_combine2: ; CHECK-FAST-NOVSX: # %bb.0: # %entry -; CHECK-FAST-NOVSX-NEXT: fneg 0, 3 -; CHECK-FAST-NOVSX-NEXT: fmsub 1, 2, 0, 1 +; CHECK-FAST-NOVSX-NEXT: fnmadd 1, 2, 3, 1 ; CHECK-FAST-NOVSX-NEXT: blr ; ; CHECK-LABEL: fma_combine2: @@ -106,19 +102,17 @@ define double @fma_combine_one_use(double %a, double %b, double %c) { ; CHECK-FAST-LABEL: fma_combine_one_use: ; CHECK-FAST: # %bb.0: # %entry -; CHECK-FAST-NEXT: xsnegdp 0, 3 +; CHECK-FAST-NEXT: xsnegdp 0, 1 ; CHECK-FAST-NEXT: addis 3, 2, v@toc@ha -; CHECK-FAST-NEXT: xsnegdp 3, 1 -; CHECK-FAST-NEXT: xsmsubadp 1, 0, 2 -; CHECK-FAST-NEXT: stfd 3, v@toc@l(3) +; CHECK-FAST-NEXT: xsnmaddadp 1, 3, 2 +; CHECK-FAST-NEXT: stfd 0, v@toc@l(3) ; CHECK-FAST-NEXT: blr ; ; CHECK-FAST-NOVSX-LABEL: fma_combine_one_use: ; CHECK-FAST-NOVSX: # %bb.0: # %entry -; CHECK-FAST-NOVSX-NEXT: fneg 0, 3 -; CHECK-FAST-NOVSX-NEXT: addis 3, 2, v@toc@ha -; CHECK-FAST-NOVSX-NEXT: fmsub 0, 0, 2, 1 +; CHECK-FAST-NOVSX-NEXT: fnmadd 0, 3, 2, 1 ; CHECK-FAST-NOVSX-NEXT: fneg 2, 1 +; CHECK-FAST-NOVSX-NEXT: addis 3, 2, v@toc@ha ; CHECK-FAST-NOVSX-NEXT: fmr 1, 0 ; CHECK-FAST-NOVSX-NEXT: stfd 2, v@toc@l(3) ; CHECK-FAST-NOVSX-NEXT: blr