Fix clamping of NaN values.

We pass integer uniforms as floating-point ones, which can cause an
exception when converting them to fixed-point values. For example an
integer value of -1 would be 0xFFFFFFFF which is Not-a-Number in
IEEE-754 floating-point and can't be cast to an integer.

In this case we don't actually care about the result because the fixed-
point number is only used by the fixed-function pipeline. A safe but
still fast way to compare floating-point numbers including NaNs is to
treat them as one's complement integers, which can easily be converted
into two's complement representation.

Also rename bitCast<> to bit_cast<> to match the C++20 function.

Change-Id: Id588d25ab70d31eda2800c24a8df539d6a3411d4
Reviewed-on: https://swiftshader-review.googlesource.com/c/21708
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Common/Math.hpp b/src/Common/Math.hpp
index a35d2e0..7343cc9 100644
--- a/src/Common/Math.hpp
+++ b/src/Common/Math.hpp
@@ -75,7 +75,7 @@
 	}
 
 	template <typename destType, typename sourceType>
-	destType bitCast(const sourceType &source)
+	destType bit_cast(const sourceType &source)
 	{
 		union
 		{
@@ -196,6 +196,26 @@
 		return clamp(x, 0.0f, 1.0f);
 	}
 
+	// Bit-cast of a floating-point value into a two's complement integer representation.
+	// This makes floating-point values comparable as integers.
+	inline int32_t float_as_twos_complement(float f)

+	{

+		// IEEE-754 floating-point numbers are sorted by magnitude in the same way as integers,

+		// except negative values are like one's complement integers. Convert them to two's complement.

+		int32_t i = bit_cast<int32_t>(f);

+		return (i < 0) ? (0x7FFFFFFF - i) : i;

+	}

+

+	// 'Safe' clamping operation which always returns a value between min and max (inclusive).

+	inline float clamp_s(float x, float min, float max)

+	{

+		// NaN values can't be compared directly

+		if(float_as_twos_complement(x) < float_as_twos_complement(min)) x = min;

+		if(float_as_twos_complement(x) > float_as_twos_complement(max)) x = max;

+

+		return x;

+	}
+
 	inline int ceilPow2(int x)
 	{
 		int i = 1;
diff --git a/src/OpenGL/compiler/Intermediate.cpp b/src/OpenGL/compiler/Intermediate.cpp
index ee77a2f..9f68dc7 100644
--- a/src/OpenGL/compiler/Intermediate.cpp
+++ b/src/OpenGL/compiler/Intermediate.cpp
@@ -1974,7 +1974,7 @@
 				case EOpFloatBitsToInt:
 					switch(basicType) {
 					case EbtFloat:
-						tempConstArray[i].setIConst(sw::bitCast<int>(unionArray[i].getFConst()));
+						tempConstArray[i].setIConst(sw::bit_cast<int>(unionArray[i].getFConst()));
 						type.setBasicType(EbtInt);
 						break;
 					default:
@@ -1986,7 +1986,7 @@
 				case EOpFloatBitsToUint:
 					switch(basicType) {
 					case EbtFloat:
-						tempConstArray[i].setUConst(sw::bitCast<unsigned int>(unionArray[i].getFConst()));
+						tempConstArray[i].setUConst(sw::bit_cast<unsigned int>(unionArray[i].getFConst()));
 						type.setBasicType(EbtUInt);
 						break;
 					default:
@@ -1997,7 +1997,7 @@
 				case EOpIntBitsToFloat:
 					switch(basicType) {
 					case EbtInt:
-						tempConstArray[i].setFConst(sw::bitCast<float>(unionArray[i].getIConst()));
+						tempConstArray[i].setFConst(sw::bit_cast<float>(unionArray[i].getIConst()));
 						type.setBasicType(EbtFloat);
 						break;
 					default:
@@ -2008,7 +2008,7 @@
 				case EOpUintBitsToFloat:
 					switch(basicType) {
 					case EbtUInt:
-						tempConstArray[i].setFConst(sw::bitCast<float>(unionArray[i].getUConst()));
+						tempConstArray[i].setFConst(sw::bit_cast<float>(unionArray[i].getUConst()));
 						type.setBasicType(EbtFloat);
 						break;
 					default:
diff --git a/src/Renderer/PixelProcessor.cpp b/src/Renderer/PixelProcessor.cpp
index 8bc40c2..a1cafde 100644
--- a/src/Renderer/PixelProcessor.cpp
+++ b/src/Renderer/PixelProcessor.cpp
@@ -95,11 +95,11 @@
 
 		if(index < 8)   // ps_1_x constants
 		{
-			// FIXME: Compact into generic function
-			short x = iround(4095 * clamp(value[0], -1.0f, 1.0f));
-			short y = iround(4095 * clamp(value[1], -1.0f, 1.0f));
-			short z = iround(4095 * clamp(value[2], -1.0f, 1.0f));
-			short w = iround(4095 * clamp(value[3], -1.0f, 1.0f));
+			// TODO: Compact into generic function
+			short x = iround(4095 * clamp_s(value[0], -1.0f, 1.0f));
+			short y = iround(4095 * clamp_s(value[1], -1.0f, 1.0f));
+			short z = iround(4095 * clamp_s(value[2], -1.0f, 1.0f));
+			short w = iround(4095 * clamp_s(value[3], -1.0f, 1.0f));
 
 			cW[index][0][0] = x;
 			cW[index][0][1] = x;
diff --git a/src/System/Math.hpp b/src/System/Math.hpp
index a35d2e0..7343cc9 100644
--- a/src/System/Math.hpp
+++ b/src/System/Math.hpp
@@ -75,7 +75,7 @@
 	}
 
 	template <typename destType, typename sourceType>
-	destType bitCast(const sourceType &source)
+	destType bit_cast(const sourceType &source)
 	{
 		union
 		{
@@ -196,6 +196,26 @@
 		return clamp(x, 0.0f, 1.0f);
 	}
 
+	// Bit-cast of a floating-point value into a two's complement integer representation.
+	// This makes floating-point values comparable as integers.
+	inline int32_t float_as_twos_complement(float f)

+	{

+		// IEEE-754 floating-point numbers are sorted by magnitude in the same way as integers,

+		// except negative values are like one's complement integers. Convert them to two's complement.

+		int32_t i = bit_cast<int32_t>(f);

+		return (i < 0) ? (0x7FFFFFFF - i) : i;

+	}

+

+	// 'Safe' clamping operation which always returns a value between min and max (inclusive).

+	inline float clamp_s(float x, float min, float max)

+	{

+		// NaN values can't be compared directly

+		if(float_as_twos_complement(x) < float_as_twos_complement(min)) x = min;

+		if(float_as_twos_complement(x) > float_as_twos_complement(max)) x = max;

+

+		return x;

+	}
+
 	inline int ceilPow2(int x)
 	{
 		int i = 1;