diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -13054,11 +13054,13 @@ } // (fdiv (fneg X), (fneg Y)) -> (fdiv X, Y) - if (isCheaperToUseNegatedFPOps(N0, N1)) - return DAG.getNode( - ISD::FDIV, SDLoc(N), VT, - TLI.getNegatedExpression(N0, DAG, LegalOperations, ForCodeSize), - TLI.getNegatedExpression(N1, DAG, LegalOperations, ForCodeSize), Flags); + if (isCheaperToUseNegatedFPOps(N0, N1)) { + SDValue Neg0 = + TLI.getNegatedExpression(N0, DAG, LegalOperations, ForCodeSize); + SDValue Neg1 = + TLI.getNegatedExpression(N1, DAG, LegalOperations, ForCodeSize); + return DAG.getNode(ISD::FDIV, SDLoc(N), VT, Neg0, Neg1, Flags); + } return SDValue(); } diff --git a/llvm/test/CodeGen/X86/fdiv.ll b/llvm/test/CodeGen/X86/fdiv.ll --- a/llvm/test/CodeGen/X86/fdiv.ll +++ b/llvm/test/CodeGen/X86/fdiv.ll @@ -76,5 +76,29 @@ ret <4 x float> %div } +; This test used to fail, depending on how llc was built (e.g. using +; clang/gcc), due to order of argument evaluation not being well defined. We +; ended up hitting llvm_unreachable in getNegatedExpression when building with +; gcc. Just make sure that we get a deterministic result. +define float @fdiv_fneg_combine(float %a0, float %a1, float %a2) #0 { +; CHECK-LABEL: fdiv_fneg_combine: +; CHECK: # %bb.0: +; CHECK-NEXT: movaps %xmm0, %xmm3 +; CHECK-NEXT: subss %xmm1, %xmm3 +; CHECK-NEXT: subss %xmm0, %xmm1 +; CHECK-NEXT: mulss %xmm2, %xmm1 +; CHECK-NEXT: subss %xmm2, %xmm3 +; CHECK-NEXT: divss %xmm3, %xmm1 +; CHECK-NEXT: movaps %xmm1, %xmm0 +; CHECK-NEXT: retq + %sub1 = fsub fast float %a0, %a1 + %mul2 = fmul fast float %sub1, %a2 + %neg = fneg fast float %a0 + %add3 = fadd fast float %a1, %neg + %sub4 = fadd fast float %add3, %a2 + %div5 = fdiv fast float %mul2, %sub4 + ret float %div5 +} + attributes #0 = { "unsafe-fp-math"="false" }