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