Index: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -12353,10 +12353,16 @@ if (N0CFP && N0CFP->isZero()) { if (N0CFP->isNegative() || (Options.NoSignedZerosFPMath || Flags.hasNoSignedZeros())) { - if (TLI.isNegatibleForFree(N1, DAG, LegalOperations, ForCodeSize)) - return TLI.getNegatedExpression(N1, DAG, LegalOperations, ForCodeSize); - if (!LegalOperations || TLI.isOperationLegal(ISD::FNEG, VT)) - return DAG.getNode(ISD::FNEG, DL, VT, N1, Flags); + // We cannot replace an FSUB(+-0.0,X) with FNEG(X) when denormals are + // flushed to zero. + DenormalMode DenormMode = DAG.getDenormalMode(VT); + if (DenormMode == DenormalMode::Invalid || + DenormMode == DenormalMode::IEEE) { + if (TLI.isNegatibleForFree(N1, DAG, LegalOperations, ForCodeSize)) + return TLI.getNegatedExpression(N1, DAG, LegalOperations, ForCodeSize); + if (!LegalOperations || TLI.isOperationLegal(ISD::FNEG, VT)) + return DAG.getNode(ISD::FNEG, DL, VT, N1, Flags); + } } } Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -2999,9 +2999,17 @@ if (isa(I.getOperand(0)) && I.getOperand(0) == ConstantFP::getZeroValueForNegation(Ty)) { SDValue Op2 = getValue(I.getOperand(1)); - setValue(&I, DAG.getNode(ISD::FNEG, getCurSDLoc(), - Op2.getValueType(), Op2)); - return; + EVT VT = Op2.getValueType(); + + // We cannot replace an FSUB(+-0.0,X) with FNEG(X) when denormals are + // flushed to zero. + DenormalMode DenormMode = DAG.getDenormalMode(VT); + if (DenormMode == DenormalMode::Invalid || + DenormMode == DenormalMode::IEEE) { + setValue(&I, DAG.getNode(ISD::FNEG, getCurSDLoc(), + VT, Op2)); + return; + } } visitBinary(I, ISD::FSUB); Index: llvm/test/CodeGen/X86/fp-denormals.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/fp-denormals.ll @@ -0,0 +1,51 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=x86_64-unknown | FileCheck %s + +; +; FSUB(+-0.0, X) -> FNEG(X) +; + +define float @fsub_fneg_default(float %a) #0 { +; CHECK-LABEL: fsub_fneg_default: +; CHECK: # %bb.0: +; CHECK-NEXT: xorps {{.*}}(%rip), %xmm0 +; CHECK-NEXT: retq + %1 = fsub float -0.0, %a + ret float %1 +} + +define float @fsub_fneg_ieee(float %a) #1 { +; CHECK-LABEL: fsub_fneg_ieee: +; CHECK: # %bb.0: +; CHECK-NEXT: xorps {{.*}}(%rip), %xmm0 +; CHECK-NEXT: retq + %1 = fsub float -0.0, %a + ret float %1 +} + +define float @fsub_fneg_preserve_sign(float %a) #2 { +; CHECK-LABEL: fsub_fneg_preserve_sign: +; CHECK: # %bb.0: +; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero +; CHECK-NEXT: subss %xmm0, %xmm1 +; CHECK-NEXT: movaps %xmm1, %xmm0 +; CHECK-NEXT: retq + %1 = fsub float -0.0, %a + ret float %1 +} + +define float @fsub_fneg_positive_zero(float %a) #3 { +; CHECK-LABEL: fsub_fneg_positive_zero: +; CHECK: # %bb.0: +; CHECK-NEXT: movss {{.*#+}} xmm1 = mem[0],zero,zero,zero +; CHECK-NEXT: subss %xmm0, %xmm1 +; CHECK-NEXT: movaps %xmm1, %xmm0 +; CHECK-NEXT: retq + %1 = fsub float -0.0, %a + ret float %1 +} + +attributes #0 = { "denormal-fp-math"="invalid" } +attributes #1 = { "denormal-fp-math"="ieee" } +attributes #2 = { "denormal-fp-math"="preserve-sign" } +attributes #3 = { "denormal-fp-math"="positive-zero" }