Fix handling overflow in Exp2()

Previously we allowed the input to be up to and including 129.0, which
when adding 127 and shifting left by 23 becomes 0x80000000, which is the
representation of -0.0f. So we need to clamp to a value just slightly
less.

Bug: b/169754022
Change-Id: Ie81e8acb77514e3a03256d1e60f645d0408e41f4
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/62928
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Pipeline/ShaderCore.cpp b/src/Pipeline/ShaderCore.cpp
index f4695cf..f5ab228 100644
--- a/src/Pipeline/ShaderCore.cpp
+++ b/src/Pipeline/ShaderCore.cpp
@@ -319,8 +319,8 @@
 	// the IEEE-754 floating-point number. Clamp to prevent overflow
 	// past the representation of infinity.
 	Float4 x0 = x;
-	x0 = Min(x0, As<Float4>(Int4(0x43010000)));  // 129.00000e+0f
-	x0 = Max(x0, As<Float4>(Int4(0xC2FDFFFF)));  // -126.99999e+0f
+	x0 = Min(x0, As<Float4>(Int4(0x4300FFFF)));  // 128.999985
+	x0 = Max(x0, As<Float4>(Int4(0xC2FDFFFF)));  // -126.999992
 
 	Int4 i = RoundInt(x0 - Float4(0.5f));
 	Float4 ii = As<Float4>((i + Int4(127)) << 23);  // Add single-precision bias, and shift into exponent.
diff --git a/tests/MathUnitTests/unittests.cpp b/tests/MathUnitTests/unittests.cpp
index 1f5dbf7..858c535 100644
--- a/tests/MathUnitTests/unittests.cpp
+++ b/tests/MathUnitTests/unittests.cpp
@@ -81,6 +81,34 @@
 	return ii * ff;
 }
 
+float Exp2(float x)
+{
+	// This implementation is based on 2^(i + f) = 2^i * 2^f,
+	// where i is the integer part of x and f is the fraction.
+
+	// For 2^i we can put the integer part directly in the exponent of
+	// the IEEE-754 floating-point number. Clamp to prevent overflow
+	// past the representation of infinity.
+	float x0 = x;
+	x0 = min(x0, bit_cast<float>(int(0x4300FFFF)));  // 128.999985
+	x0 = max(x0, bit_cast<float>(int(0xC2FDFFFF)));  // -126.999992
+
+	int i = (int)round(x0 - 0.5f);
+	float ii = bit_cast<float>((i + int(127)) << 23);  // Add single-precision bias, and shift into exponent.
+
+	// For the fractional part use a polynomial
+	// which approximates 2^f in the 0 to 1 range.
+	float f = x0 - float(i);
+	float ff = bit_cast<float>(int(0x3AF61905));     // 1.8775767e-3f
+	ff = ff * f + bit_cast<float>(int(0x3C134806));  // 8.9893397e-3f
+	ff = ff * f + bit_cast<float>(int(0x3D64AA23));  // 5.5826318e-2f
+	ff = ff * f + bit_cast<float>(int(0x3E75EAD4));  // 2.4015361e-1f
+	ff = ff * f + bit_cast<float>(int(0x3F31727B));  // 6.9315308e-1f
+	ff = ff * f + float(1.0f);
+
+	return ii * ff;
+}
+
 TEST(MathTest, Exp2Exhaustive)
 {
 	CPUID::setDenormalsAreZero(true);
@@ -94,7 +122,7 @@
 
 	for(float x = -10; x <= 10; x = inc(x))
 	{
-		float val = Exp2_legacy(x);
+		float val = Exp2(x);
 
 		double ref = exp2((double)x);
 		float ulp = (float)ULP_32(ref, (double)val);