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:
@@ -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
|
||||
------------------------
|
||||
|
||||
|
||||
12
expr.cpp
12
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()");
|
||||
|
||||
20
stdlib.ispc
20
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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user