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;
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<ConstantFPSDNode>(Op.getOperand(0)))
if (N0CFP->isZero())
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)))
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))
return GetNegatedExpression(N1, DAG, LegalOperations);
if (!LegalOperations || TLI.isOperationLegal(ISD::FNEG, VT))
- return DAG.getNode(ISD::FNEG, DL, VT, N1);
+ return DAG.getNode(ISD::FNEG, DL, VT, N1, Flags);
}
+ }
+
+ // 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)
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
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
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 {
; 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
;
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
;