Index: lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -622,7 +622,8 @@ Depth + 1); case ISD::FSUB: // We can't turn -(A-B) into B-A when we honor signed zeros. - if (!Options->UnsafeFPMath) return 0; + if (!Options->UnsafeFPMath && !Op.getNode()->getFlags()->hasNoSignedZeros()) + return 0; // fold (fneg (fsub A, B)) -> (fsub B, A) return 1; @@ -685,9 +686,6 @@ LegalOperations, Depth+1), Op.getOperand(0), Flags); case ISD::FSUB: - // We can't turn -(A-B) into B-A when we honor signed zeros. - assert(Options.UnsafeFPMath); - // fold (fneg (fsub 0, B)) -> B if (ConstantFPSDNode *N0CFP = dyn_cast(Op.getOperand(0))) if (N0CFP->isZero()) @@ -8399,17 +8397,20 @@ return DAG.getNode(ISD::FSUB, DL, VT, N1, GetNegatedExpression(N0, DAG, LegalOperations), Flags); + // FIXME: Auto-upgrade the target/function-level option. + if (Options.UnsafeFPMath || N->getFlags()->hasNoSignedZeros()) { + // fold (fadd A, 0) -> A + if (ConstantFPSDNode *N1C = isConstOrConstSplatFP(N1)) + if (N1C->isZero()) + return N0; + } + // If 'unsafe math' is enabled, fold lots of things. if (Options.UnsafeFPMath) { // No FP constant should be created after legalization as Instruction // Selection pass has a hard time dealing with FP constants. bool AllowNewConst = (Level < AfterLegalizeDAG); - // fold (fadd A, 0) -> A - if (ConstantFPSDNode *N1C = isConstOrConstSplatFP(N1)) - if (N1C->isZero()) - return N0; - // fold (fadd (fadd x, c1), c2) -> (fadd x, (fadd c1, c2)) if (N1CFP && N0.getOpcode() == ISD::FADD && N0.getNode()->hasOneUse() && isConstantFPBuildVectorOrConstantFP(N0.getOperand(1))) @@ -8536,12 +8537,8 @@ return DAG.getNode(ISD::FADD, dl, VT, N0, GetNegatedExpression(N1, DAG, LegalOperations), Flags); - // If 'unsafe math' is enabled, fold lots of things. - if (Options.UnsafeFPMath) { - // (fsub A, 0) -> A - if (N1CFP && N1CFP->isZero()) - return N0; - + // FIXME: Auto-upgrade the target/function-level option. + if (Options.UnsafeFPMath || N->getFlags()->hasNoSignedZeros()) { // (fsub 0, B) -> -B if (N0CFP && N0CFP->isZero()) { if (isNegatibleForFree(N1, LegalOperations, TLI, &Options)) @@ -8549,6 +8546,13 @@ if (!LegalOperations || TLI.isOperationLegal(ISD::FNEG, VT)) return DAG.getNode(ISD::FNEG, dl, VT, N1); } + } + + // If 'unsafe math' is enabled, fold lots of things. + if (Options.UnsafeFPMath) { + // (fsub A, 0) -> A + if (N1CFP && N1CFP->isZero()) + return N0; // (fsub x, x) -> 0.0 if (N0 == N1) Index: test/CodeGen/X86/negative-sin.ll =================================================================== --- test/CodeGen/X86/negative-sin.ll +++ test/CodeGen/X86/negative-sin.ll @@ -23,21 +23,13 @@ ret double %h } -; FIXME: ; 'fast' implies no-signed-zeros, so the negates fold away. ; The 'sin' does not need any fast-math-flags for this transform. define double @fast(double %e) nounwind { ; CHECK-LABEL: fast: ; CHECK: # BB#0: -; CHECK-NEXT: pushq %rax -; CHECK-NEXT: vxorpd %xmm1, %xmm1, %xmm1 -; CHECK-NEXT: vsubsd %xmm0, %xmm1, %xmm0 -; CHECK-NEXT: callq sin -; CHECK-NEXT: vxorpd %xmm1, %xmm1, %xmm1 -; CHECK-NEXT: vsubsd %xmm0, %xmm1, %xmm0 -; CHECK-NEXT: popq %rax -; CHECK-NEXT: retq +; CHECK-NEXT: jmp sin ; %f = fsub fast double 0.0, %e %g = call double @sin(double %f) readonly @@ -45,20 +37,12 @@ ret double %h } -; FIXME: ; No-signed-zeros is all that we need for this transform. define double @nsz(double %e) nounwind { ; CHECK-LABEL: nsz: ; CHECK: # BB#0: -; CHECK-NEXT: pushq %rax -; CHECK-NEXT: vxorpd %xmm1, %xmm1, %xmm1 -; CHECK-NEXT: vsubsd %xmm0, %xmm1, %xmm0 -; CHECK-NEXT: callq sin -; CHECK-NEXT: vxorpd %xmm1, %xmm1, %xmm1 -; CHECK-NEXT: vsubsd %xmm0, %xmm1, %xmm0 -; CHECK-NEXT: popq %rax -; CHECK-NEXT: retq +; CHECK-NEXT: jmp sin ; %f = fsub nsz double 0.0, %e %g = call double @sin(double %f) readonly @@ -66,7 +50,6 @@ ret double %h } -; FIXME: ; The 1st negate is strict, so we can't kill that sub, but the 2nd disappears. define double @semi_strict1(double %e) nounwind { @@ -76,8 +59,7 @@ ; CHECK-NEXT: vxorpd %xmm1, %xmm1, %xmm1 ; CHECK-NEXT: vsubsd %xmm0, %xmm1, %xmm0 ; CHECK-NEXT: callq sin -; CHECK-NEXT: vxorpd %xmm1, %xmm1, %xmm1 -; CHECK-NEXT: vsubsd %xmm0, %xmm1, %xmm0 +; CHECK-NEXT: vxorpd {{.*}}(%rip), %xmm0, %xmm0 ; CHECK-NEXT: popq %rax ; CHECK-NEXT: retq ; @@ -87,18 +69,15 @@ ret double %h } -; FIXME: ; The 2nd negate is strict, so we can't kill it. It becomes an add of zero instead. define double @semi_strict2(double %e) nounwind { ; CHECK-LABEL: semi_strict2: ; CHECK: # BB#0: ; CHECK-NEXT: pushq %rax -; CHECK-NEXT: vxorpd %xmm1, %xmm1, %xmm1 -; CHECK-NEXT: vsubsd %xmm0, %xmm1, %xmm0 ; CHECK-NEXT: callq sin ; CHECK-NEXT: vxorpd %xmm1, %xmm1, %xmm1 -; CHECK-NEXT: vsubsd %xmm0, %xmm1, %xmm0 +; CHECK-NEXT: vaddsd %xmm1, %xmm0, %xmm0 ; CHECK-NEXT: popq %rax ; CHECK-NEXT: retq ;