/// class to allow target nodes to be understood.
unsigned ComputeNumSignBits(SDValue Op, unsigned Depth = 0) const;
+ /// isKnownNeverNan - Test whether the given SDValue is known to never be NaN.
+ bool isKnownNeverNaN(SDValue Op) const;
+
/// isVerifiedDebugInfoDesc - Returns true if the specified SDValue has
/// been verified as a debug information descriptor.
bool isVerifiedDebugInfoDesc(SDValue Op) const;
return std::max(FirstAnswer, std::min(VTBits, Mask.countLeadingZeros()));
}
+bool SelectionDAG::isKnownNeverNaN(SDValue Op) const {
+ // If we're told that NaNs won't happen, assume they won't.
+ if (FiniteOnlyFPMath())
+ return true;
+
+ // If the value is a constant, we can obviously see if it is a NaN or not.
+ if (const ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Op))
+ return !C->getValueAPF().isNaN();
+
+ // TODO: Recognize more cases here.
+
+ return false;
+}
bool SelectionDAG::isVerifiedDebugInfoDesc(SDValue Op) const {
GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op);
} else if (LHS == Cond.getOperand(1) && RHS == Cond.getOperand(0)) {
switch (CC) {
default: break;
- case ISD::SETOGT: // (X > Y) ? Y : X -> min
- case ISD::SETUGT:
+ case ISD::SETOGT:
+ // This can use a min only if the LHS isn't NaN.
+ if (DAG.isKnownNeverNaN(LHS))
+ Opcode = X86ISD::FMIN;
+ else if (DAG.isKnownNeverNaN(RHS)) {
+ Opcode = X86ISD::FMIN;
+ // Put the potential NaN in the RHS so that SSE will preserve it.
+ std::swap(LHS, RHS);
+ }
+ break;
+
+ case ISD::SETUGT: // (X > Y) ? Y : X -> min
case ISD::SETGT:
if (!UnsafeFPMath) break;
// FALL THROUGH.
Opcode = X86ISD::FMIN;
break;
- case ISD::SETOLE: // (X <= Y) ? Y : X -> max
case ISD::SETULE:
+ // This can use a max only if the LHS isn't NaN.
+ if (DAG.isKnownNeverNaN(LHS))
+ Opcode = X86ISD::FMAX;
+ else if (DAG.isKnownNeverNaN(RHS)) {
+ Opcode = X86ISD::FMAX;
+ // Put the potential NaN in the RHS so that SSE will preserve it.
+ std::swap(LHS, RHS);
+ }
+ break;
+
+ case ISD::SETOLE: // (X <= Y) ? Y : X -> max
case ISD::SETLE:
if (!UnsafeFPMath) break;
// FALL THROUGH.
--- /dev/null
+; RUN: llvm-as < %s | llc -march=x86-64 | FileCheck %s
+
+; CHECK: clampTo3k_a:
+; CHECK: minsd
+define double @clampTo3k_a(double %x) nounwind readnone {
+entry:
+ %0 = fcmp ogt double %x, 3.000000e+03 ; <i1> [#uses=1]
+ %x_addr.0 = select i1 %0, double 3.000000e+03, double %x ; <double> [#uses=1]
+ ret double %x_addr.0
+}
+
+; CHECK: clampTo3k_b:
+; CHECK: minsd
+define double @clampTo3k_b(double %x) nounwind readnone {
+entry:
+ %0 = fcmp uge double %x, 3.000000e+03 ; <i1> [#uses=1]
+ %x_addr.0 = select i1 %0, double 3.000000e+03, double %x ; <double> [#uses=1]
+ ret double %x_addr.0
+}
+
+; CHECK: clampTo3k_c:
+; CHECK: maxsd
+define double @clampTo3k_c(double %x) nounwind readnone {
+entry:
+ %0 = fcmp olt double %x, 3.000000e+03 ; <i1> [#uses=1]
+ %x_addr.0 = select i1 %0, double 3.000000e+03, double %x ; <double> [#uses=1]
+ ret double %x_addr.0
+}
+
+; CHECK: clampTo3k_d:
+; CHECK: maxsd
+define double @clampTo3k_d(double %x) nounwind readnone {
+entry:
+ %0 = fcmp ule double %x, 3.000000e+03 ; <i1> [#uses=1]
+ %x_addr.0 = select i1 %0, double 3.000000e+03, double %x ; <double> [#uses=1]
+ ret double %x_addr.0
+}
+
+; CHECK: clampTo3k_e:
+; CHECK: maxsd
+define double @clampTo3k_e(double %x) nounwind readnone {
+entry:
+ %0 = fcmp olt double %x, 3.000000e+03 ; <i1> [#uses=1]
+ %x_addr.0 = select i1 %0, double 3.000000e+03, double %x ; <double> [#uses=1]
+ ret double %x_addr.0
+}
+
+; CHECK: clampTo3k_f:
+; CHECK: maxsd
+define double @clampTo3k_f(double %x) nounwind readnone {
+entry:
+ %0 = fcmp ule double %x, 3.000000e+03 ; <i1> [#uses=1]
+ %x_addr.0 = select i1 %0, double 3.000000e+03, double %x ; <double> [#uses=1]
+ ret double %x_addr.0
+}
+
+; CHECK: clampTo3k_g:
+; CHECK: minsd
+define double @clampTo3k_g(double %x) nounwind readnone {
+entry:
+ %0 = fcmp ogt double %x, 3.000000e+03 ; <i1> [#uses=1]
+ %x_addr.0 = select i1 %0, double 3.000000e+03, double %x ; <double> [#uses=1]
+ ret double %x_addr.0
+}
+
+; CHECK: clampTo3k_h:
+; CHECK: minsd
+define double @clampTo3k_h(double %x) nounwind readnone {
+entry:
+ %0 = fcmp uge double %x, 3.000000e+03 ; <i1> [#uses=1]
+ %x_addr.0 = select i1 %0, double 3.000000e+03, double %x ; <double> [#uses=1]
+ ret double %x_addr.0
+}