diff options
-rw-r--r-- | include/llvm/CodeGen/SelectionDAG.h | 3 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 13 | ||||
-rw-r--r-- | lib/Target/X86/X86ISelLowering.cpp | 26 | ||||
-rw-r--r-- | test/CodeGen/X86/sse-minmax.ll | 73 |
4 files changed, 112 insertions, 3 deletions
diff --git a/include/llvm/CodeGen/SelectionDAG.h b/include/llvm/CodeGen/SelectionDAG.h index 7ce869050b..9ab04151cb 100644 --- a/include/llvm/CodeGen/SelectionDAG.h +++ b/include/llvm/CodeGen/SelectionDAG.h @@ -840,6 +840,9 @@ public: /// 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; diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 11f12c9475..0a523fa8dc 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -2198,6 +2198,19 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, unsigned Depth) 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); diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 9293755538..34e53f02ef 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -8250,8 +8250,18 @@ static SDValue PerformSELECTCombine(SDNode *N, SelectionDAG &DAG, } 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. @@ -8260,8 +8270,18 @@ static SDValue PerformSELECTCombine(SDNode *N, SelectionDAG &DAG, 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. diff --git a/test/CodeGen/X86/sse-minmax.ll b/test/CodeGen/X86/sse-minmax.ll new file mode 100644 index 0000000000..a346164c0f --- /dev/null +++ b/test/CodeGen/X86/sse-minmax.ll @@ -0,0 +1,73 @@ +; 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 +} |