From 46716aada33d029010d92e6f52ef6a82a55ab10f Mon Sep 17 00:00:00 2001 From: Matt Pharr Date: Wed, 20 Jun 2012 13:24:09 -0700 Subject: [PATCH] Switch to unordered floating point compares. In particular, this gives us desired behavior for NaNs (all compares involving a NaN evaluate to true). This in turn allows writing the canonical isnan() function as "v != v". Added isnan() to the standard library as well. --- docs/ispc.rst | 11 +++++++++++ expr.cpp | 12 ++++++------ stdlib.ispc | 20 ++++++++++++++++++++ tests/half-1.ispc | 2 +- tests/half-3.ispc | 2 +- tests/half.ispc | 2 +- 6 files changed, 40 insertions(+), 9 deletions(-) diff --git a/docs/ispc.rst b/docs/ispc.rst index 1cd98b62..7ab01571 100644 --- a/docs/ispc.rst +++ b/docs/ispc.rst @@ -3099,6 +3099,17 @@ quite efficient.) uniform unsigned int low, uniform unsigned int high) +The ``isnan()`` functions test whether the given value is a floating-point +"not a number" value: + +:: + + bool isnan(float v) + uniform bool isnan(uniform float v) + bool isnan(double v) + uniform bool isnan(uniform double v) + + Transcendental Functions ------------------------ diff --git a/expr.cpp b/expr.cpp index 67e8a819..f2d83325 100644 --- a/expr.cpp +++ b/expr.cpp @@ -1569,31 +1569,31 @@ lEmitBinaryCmp(BinaryExpr::Op op, llvm::Value *e0Val, llvm::Value *e1Val, switch (op) { case BinaryExpr::Lt: opName = "less"; - pred = isFloatOp ? llvm::CmpInst::FCMP_OLT : + pred = isFloatOp ? llvm::CmpInst::FCMP_ULT : (isUnsignedOp ? llvm::CmpInst::ICMP_ULT : llvm::CmpInst::ICMP_SLT); break; case BinaryExpr::Gt: opName = "greater"; - pred = isFloatOp ? llvm::CmpInst::FCMP_OGT : + pred = isFloatOp ? llvm::CmpInst::FCMP_UGT : (isUnsignedOp ? llvm::CmpInst::ICMP_UGT : llvm::CmpInst::ICMP_SGT); break; case BinaryExpr::Le: opName = "lessequal"; - pred = isFloatOp ? llvm::CmpInst::FCMP_OLE : + pred = isFloatOp ? llvm::CmpInst::FCMP_ULE : (isUnsignedOp ? llvm::CmpInst::ICMP_ULE : llvm::CmpInst::ICMP_SLE); break; case BinaryExpr::Ge: opName = "greaterequal"; - pred = isFloatOp ? llvm::CmpInst::FCMP_OGE : + pred = isFloatOp ? llvm::CmpInst::FCMP_UGE : (isUnsignedOp ? llvm::CmpInst::ICMP_UGE : llvm::CmpInst::ICMP_SGE); break; case BinaryExpr::Equal: opName = "equal"; - pred = isFloatOp ? llvm::CmpInst::FCMP_OEQ : llvm::CmpInst::ICMP_EQ; + pred = isFloatOp ? llvm::CmpInst::FCMP_UEQ : llvm::CmpInst::ICMP_EQ; break; case BinaryExpr::NotEqual: opName = "notequal"; - pred = isFloatOp ? llvm::CmpInst::FCMP_ONE : llvm::CmpInst::ICMP_NE; + pred = isFloatOp ? llvm::CmpInst::FCMP_UNE : llvm::CmpInst::ICMP_NE; break; default: FATAL("error in lEmitBinaryCmp()"); diff --git a/stdlib.ispc b/stdlib.ispc index 801baade..84865d90 100644 --- a/stdlib.ispc +++ b/stdlib.ispc @@ -1120,6 +1120,26 @@ static inline uniform int64 clock() { /////////////////////////////////////////////////////////////////////////// // Floating-Point Math +__declspec(safe,cost1) +static inline uniform bool isnan(uniform float v) { + return v != v; +} + +__declspec(safe,cost1) +static inline bool isnan(float v) { + return v != v; +} + +__declspec(safe,cost1) +static inline uniform bool isnan(uniform double v) { + return v != v; +} + +__declspec(safe,cost1) +static inline bool isnan(double v) { + return v != v; +} + __declspec(safe,cost1) static inline float abs(float a) { // Floating-point hack: zeroing the high bit clears the sign diff --git a/tests/half-1.ispc b/tests/half-1.ispc index 72ef72ee..0ce76d40 100644 --- a/tests/half-1.ispc +++ b/tests/half-1.ispc @@ -10,7 +10,7 @@ export void f_v(uniform float RET[]) { h = float_to_half(f); // may return a different value back for NaNs.. - if (f == f && i != h) + if (!isnan(f) && i != h) ++errors; } RET[programIndex] = errors; diff --git a/tests/half-3.ispc b/tests/half-3.ispc index 2c7b4096..3f1fe5e7 100644 --- a/tests/half-3.ispc +++ b/tests/half-3.ispc @@ -9,7 +9,7 @@ export void f_v(uniform float RET[]) { float f = half_to_float(i); h = float_to_half(f); - int mismatches = (f == f && i != h); + int mismatches = (!isnan(f) && i != h); if (any(mismatches != 0)) print("mismatch: orig int16 % -> float % -> half %\n", i, f, h); errors += reduce_add(mismatches); diff --git a/tests/half.ispc b/tests/half.ispc index b0caeded..99a37953 100644 --- a/tests/half.ispc +++ b/tests/half.ispc @@ -10,7 +10,7 @@ export void f_v(uniform float RET[]) { h = float_to_half(f); // may return a different value back for NaNs.. - if (f == f && i != h) + if (!isnan(f) && i != h) ++errors; } RET[programIndex] = errors;