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.
This commit is contained in:
Matt Pharr
2012-06-20 13:24:09 -07:00
parent 3bc66136b2
commit 46716aada3
6 changed files with 40 additions and 9 deletions

View File

@@ -3099,6 +3099,17 @@ quite efficient.)
uniform unsigned int low, uniform unsigned int low,
uniform unsigned int high) 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 Transcendental Functions
------------------------ ------------------------

View File

@@ -1569,31 +1569,31 @@ lEmitBinaryCmp(BinaryExpr::Op op, llvm::Value *e0Val, llvm::Value *e1Val,
switch (op) { switch (op) {
case BinaryExpr::Lt: case BinaryExpr::Lt:
opName = "less"; opName = "less";
pred = isFloatOp ? llvm::CmpInst::FCMP_OLT : pred = isFloatOp ? llvm::CmpInst::FCMP_ULT :
(isUnsignedOp ? llvm::CmpInst::ICMP_ULT : llvm::CmpInst::ICMP_SLT); (isUnsignedOp ? llvm::CmpInst::ICMP_ULT : llvm::CmpInst::ICMP_SLT);
break; break;
case BinaryExpr::Gt: case BinaryExpr::Gt:
opName = "greater"; opName = "greater";
pred = isFloatOp ? llvm::CmpInst::FCMP_OGT : pred = isFloatOp ? llvm::CmpInst::FCMP_UGT :
(isUnsignedOp ? llvm::CmpInst::ICMP_UGT : llvm::CmpInst::ICMP_SGT); (isUnsignedOp ? llvm::CmpInst::ICMP_UGT : llvm::CmpInst::ICMP_SGT);
break; break;
case BinaryExpr::Le: case BinaryExpr::Le:
opName = "lessequal"; opName = "lessequal";
pred = isFloatOp ? llvm::CmpInst::FCMP_OLE : pred = isFloatOp ? llvm::CmpInst::FCMP_ULE :
(isUnsignedOp ? llvm::CmpInst::ICMP_ULE : llvm::CmpInst::ICMP_SLE); (isUnsignedOp ? llvm::CmpInst::ICMP_ULE : llvm::CmpInst::ICMP_SLE);
break; break;
case BinaryExpr::Ge: case BinaryExpr::Ge:
opName = "greaterequal"; opName = "greaterequal";
pred = isFloatOp ? llvm::CmpInst::FCMP_OGE : pred = isFloatOp ? llvm::CmpInst::FCMP_UGE :
(isUnsignedOp ? llvm::CmpInst::ICMP_UGE : llvm::CmpInst::ICMP_SGE); (isUnsignedOp ? llvm::CmpInst::ICMP_UGE : llvm::CmpInst::ICMP_SGE);
break; break;
case BinaryExpr::Equal: case BinaryExpr::Equal:
opName = "equal"; opName = "equal";
pred = isFloatOp ? llvm::CmpInst::FCMP_OEQ : llvm::CmpInst::ICMP_EQ; pred = isFloatOp ? llvm::CmpInst::FCMP_UEQ : llvm::CmpInst::ICMP_EQ;
break; break;
case BinaryExpr::NotEqual: case BinaryExpr::NotEqual:
opName = "notequal"; opName = "notequal";
pred = isFloatOp ? llvm::CmpInst::FCMP_ONE : llvm::CmpInst::ICMP_NE; pred = isFloatOp ? llvm::CmpInst::FCMP_UNE : llvm::CmpInst::ICMP_NE;
break; break;
default: default:
FATAL("error in lEmitBinaryCmp()"); FATAL("error in lEmitBinaryCmp()");

View File

@@ -1120,6 +1120,26 @@ static inline uniform int64 clock() {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// Floating-Point Math // 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) __declspec(safe,cost1)
static inline float abs(float a) { static inline float abs(float a) {
// Floating-point hack: zeroing the high bit clears the sign // Floating-point hack: zeroing the high bit clears the sign

View File

@@ -10,7 +10,7 @@ export void f_v(uniform float RET[]) {
h = float_to_half(f); h = float_to_half(f);
// may return a different value back for NaNs.. // may return a different value back for NaNs..
if (f == f && i != h) if (!isnan(f) && i != h)
++errors; ++errors;
} }
RET[programIndex] = errors; RET[programIndex] = errors;

View File

@@ -9,7 +9,7 @@ export void f_v(uniform float RET[]) {
float f = half_to_float(i); float f = half_to_float(i);
h = float_to_half(f); h = float_to_half(f);
int mismatches = (f == f && i != h); int mismatches = (!isnan(f) && i != h);
if (any(mismatches != 0)) if (any(mismatches != 0))
print("mismatch: orig int16 % -> float % -> half %\n", i, f, h); print("mismatch: orig int16 % -> float % -> half %\n", i, f, h);
errors += reduce_add(mismatches); errors += reduce_add(mismatches);

View File

@@ -10,7 +10,7 @@ export void f_v(uniform float RET[]) {
h = float_to_half(f); h = float_to_half(f);
// may return a different value back for NaNs.. // may return a different value back for NaNs..
if (f == f && i != h) if (!isnan(f) && i != h)
++errors; ++errors;
} }
RET[programIndex] = errors; RET[programIndex] = errors;