Index: lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -9713,6 +9713,20 @@ return DAG.getNode(ISD::FSUB, DL, VT, N1IsFMul ? N0 : N1, Add, Flags); } + // fold (fadd (fmul (fmul B, -2.0) C), A) -> (fsub A, (fmul (fadd B, B) C) + // fold (fadd A, (fmul (fmul B, -2.0) C)) -> (fsub A, (fmul (fadd B, B) C) + SDValue N0N0 = N0->getOperand(0); + SDValue N1N0 = N1->getOperand(0); + if ((isFMulNegTwo(N0N0) && N0N0.hasOneUse()) || + (isFMulNegTwo(N1N0) && N1N0.hasOneUse())) { + bool N1N0IsFMul = isFMulNegTwo(N1N0); + SDValue AddOp = N1N0IsFMul ? N1N0.getOperand(0) : N0N0.getOperand(0); + SDValue MulOp = N1N0IsFMul ? N1->getOperand(1) : N0->getOperand(1); + SDValue Add = DAG.getNode(ISD::FADD, DL, VT, AddOp, AddOp, Flags); + SDValue Mul = DAG.getNode(ISD::FMUL, DL, VT, Add, MulOp, Flags); + return DAG.getNode(ISD::FSUB, DL, VT, N1N0IsFMul ? N0 : N1, Mul, Flags); + } + // FIXME: Auto-upgrade the target/function-level option. if (Options.NoSignedZerosFPMath || N->getFlags().hasNoSignedZeros()) { // fold (fadd A, 0) -> A Index: test/CodeGen/AArch64/fadd-combines.ll =================================================================== --- test/CodeGen/AArch64/fadd-combines.ll +++ test/CodeGen/AArch64/fadd-combines.ll @@ -76,3 +76,28 @@ } declare void @use(double) + +; CHECK-LABEL: test8: +; CHECK: fadd d1, d1, d1 +; CHECK: fmul d1, d1, d2 +; CHECK: fsub d0, d0, d1 +define double @test8(double %a, double %b, double %c) local_unnamed_addr #0 { +entry: + %mul = fmul double %b, -2.000000e+00 + %mul1 = fmul double %mul, %c + %add = fadd double %mul1, %a + ret double %add +} + +; DAGCombine will canonicalize 'a - 2.0*b*c' to 'a + -2.0*b*c' +; CHECK-LABEL: test9: +; CHECK: fadd d1, d1, d1 +; CHECK: fmul d1, d1, d2 +; CHECK: fsub d0, d0, d1 +define double @test9(double %a, double %b, double %c) local_unnamed_addr #0 { +entry: + %mul = fmul double %b, 2.000000e+00 + %mul1 = fmul double %mul, %c + %sub = fsub double %a, %mul1 + ret double %sub +}