diff options
| author | Dan Gohman <gohman@apple.com> | 2010-02-24 06:52:40 +0000 |
|---|---|---|
| committer | Dan Gohman <gohman@apple.com> | 2010-02-24 06:52:40 +0000 |
| commit | 38605214063d1689a0e876e2d79e929536d36a32 (patch) | |
| tree | 4a3842df0fa95eee3777a01791450fbda838d2eb /llvm/lib | |
| parent | 94732024eb0c9baec43d601830602a4fe78f6e4d (diff) | |
| download | bcm5719-llvm-38605214063d1689a0e876e2d79e929536d36a32.tar.gz bcm5719-llvm-38605214063d1689a0e876e2d79e929536d36a32.zip | |
When forming SSE min and max nodes for UGE and ULE comparisons, it's
necessary to swap the operands to handle NaN and negative zero properly.
Also, reintroduce logic for checking for NaN conditions when forming
SSE min and max instructions, fixed to take into consideration NaNs and
negative zeros. This allows forming min and max instructions in more
cases.
llvm-svn: 97025
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 23 | ||||
| -rw-r--r-- | llvm/lib/Target/X86/X86ISelLowering.cpp | 84 |
2 files changed, 97 insertions, 10 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index f8930b8ff0c..41050211b2e 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -2235,6 +2235,29 @@ bool SelectionDAG::isKnownNeverNaN(SDValue Op) const { return false; } +bool SelectionDAG::isKnownNeverZero(SDValue Op) const { + // If the value is a constant, we can obviously see if it is a zero or not. + if (const ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(Op)) + return !C->isZero(); + + // TODO: Recognize more cases here. + + return false; +} + +bool SelectionDAG::isEqualTo(SDValue A, SDValue B) const { + // Check the obvious case. + if (A == B) return true; + + // For for negative and positive zero. + if (const ConstantFPSDNode *CA = dyn_cast<ConstantFPSDNode>(A)) + if (const ConstantFPSDNode *CB = dyn_cast<ConstantFPSDNode>(B)) + if (CA->isZero() && CB->isZero()) return true; + + // Otherwise they may not be equal. + return false; +} + bool SelectionDAG::isVerifiedDebugInfoDesc(SDValue Op) const { GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op); if (!GA) return false; diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 3bbe5fb70f6..d2d76da838c 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -8833,18 +8833,35 @@ static SDValue PerformSELECTCombine(SDNode *N, SelectionDAG &DAG, unsigned Opcode = 0; // Check for x CC y ? x : y. - if (LHS == Cond.getOperand(0) && RHS == Cond.getOperand(1)) { + if (DAG.isEqualTo(LHS, Cond.getOperand(0)) && + DAG.isEqualTo(RHS, Cond.getOperand(1))) { switch (CC) { default: break; case ISD::SETULT: - if (!UnsafeFPMath) break; + // Converting this to a min would handle NaNs incorrectly, and swapping + // the operands would cause it to handle comparisons between positive + // and negative zero incorrectly. + if (!FiniteOnlyFPMath() && + (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))) { + if (!UnsafeFPMath && + !(DAG.isKnownNeverZero(LHS) || DAG.isKnownNeverZero(RHS))) + break; + std::swap(LHS, RHS); + } Opcode = X86ISD::FMIN; break; case ISD::SETOLE: - if (!UnsafeFPMath) break; + // Converting this to a min would handle comparisons between positive + // and negative zero incorrectly. + if (!UnsafeFPMath && + !DAG.isKnownNeverZero(LHS) && !DAG.isKnownNeverZero(RHS)) + break; Opcode = X86ISD::FMIN; break; case ISD::SETULE: + // Converting this to a min would handle both negative zeros and NaNs + // incorrectly, but we can swap the operands to fix both. + std::swap(LHS, RHS); case ISD::SETOLT: case ISD::SETLT: case ISD::SETLE: @@ -8852,14 +8869,30 @@ static SDValue PerformSELECTCombine(SDNode *N, SelectionDAG &DAG, break; case ISD::SETOGE: - if (!UnsafeFPMath) break; + // Converting this to a max would handle comparisons between positive + // and negative zero incorrectly. + if (!UnsafeFPMath && + !DAG.isKnownNeverZero(LHS) && !DAG.isKnownNeverZero(LHS)) + break; Opcode = X86ISD::FMAX; break; case ISD::SETUGT: - if (!UnsafeFPMath) break; + // Converting this to a max would handle NaNs incorrectly, and swapping + // the operands would cause it to handle comparisons between positive + // and negative zero incorrectly. + if (!FiniteOnlyFPMath() && + (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))) { + if (!UnsafeFPMath && + !(DAG.isKnownNeverZero(LHS) || DAG.isKnownNeverZero(RHS))) + break; + std::swap(LHS, RHS); + } Opcode = X86ISD::FMAX; break; case ISD::SETUGE: + // Converting this to a max would handle both negative zeros and NaNs + // incorrectly, but we can swap the operands to fix both. + std::swap(LHS, RHS); case ISD::SETOGT: case ISD::SETGT: case ISD::SETGE: @@ -8867,18 +8900,34 @@ static SDValue PerformSELECTCombine(SDNode *N, SelectionDAG &DAG, break; } // Check for x CC y ? y : x -- a min/max with reversed arms. - } else if (LHS == Cond.getOperand(1) && RHS == Cond.getOperand(0)) { + } else if (DAG.isEqualTo(LHS, Cond.getOperand(1)) && + DAG.isEqualTo(RHS, Cond.getOperand(0))) { switch (CC) { default: break; case ISD::SETOGE: - if (!UnsafeFPMath) break; + // Converting this to a min would handle comparisons between positive + // and negative zero incorrectly, and swapping the operands would + // cause it to handle NaNs incorrectly. + if (!UnsafeFPMath && + !(DAG.isKnownNeverZero(LHS) || DAG.isKnownNeverZero(RHS))) { + if (!FiniteOnlyFPMath() && + (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))) + break; + std::swap(LHS, RHS); + } Opcode = X86ISD::FMIN; break; case ISD::SETUGT: - if (!UnsafeFPMath) break; + // Converting this to a min would handle NaNs incorrectly. + if (!UnsafeFPMath && + (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))) + break; Opcode = X86ISD::FMIN; break; case ISD::SETUGE: + // Converting this to a min would handle both negative zeros and NaNs + // incorrectly, but we can swap the operands to fix both. + std::swap(LHS, RHS); case ISD::SETOGT: case ISD::SETGT: case ISD::SETGE: @@ -8886,14 +8935,29 @@ static SDValue PerformSELECTCombine(SDNode *N, SelectionDAG &DAG, break; case ISD::SETULT: - if (!UnsafeFPMath) break; + // Converting this to a max would handle NaNs incorrectly. + if (!FiniteOnlyFPMath() && + (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))) + break; Opcode = X86ISD::FMAX; break; case ISD::SETOLE: - if (!UnsafeFPMath) break; + // Converting this to a max would handle comparisons between positive + // and negative zero incorrectly, and swapping the operands would + // cause it to handle NaNs incorrectly. + if (!UnsafeFPMath && + !DAG.isKnownNeverZero(LHS) && !DAG.isKnownNeverZero(RHS)) { + if (!FiniteOnlyFPMath() && + (!DAG.isKnownNeverNaN(LHS) || !DAG.isKnownNeverNaN(RHS))) + break; + std::swap(LHS, RHS); + } Opcode = X86ISD::FMAX; break; case ISD::SETULE: + // Converting this to a max would handle both negative zeros and NaNs + // incorrectly, but we can swap the operands to fix both. + std::swap(LHS, RHS); case ISD::SETOLT: case ISD::SETLT: case ISD::SETLE: |

