Fix float-to-half conversion

The Reactor code in floatToHalfBits() did not match the reference
implementation of the sw::half type, leading to failures in dEQP tests
which are enabled by the shaderStorageImageExtendedFormats feature.

The previous code was based on https://gist.github.com/rygorous/2156668.
It doesn't round to nearest even in case of a tie, but that's not
demanded by Vulkan. It merits a closer look to see whether there was a
bug, or whether dEQP-VK is too strict. Dawn also found the previous
implementation to not handle infinity correctly, so a bug seems likely.

In any case, it's good to use a reference implementation for now, and
look for optimization opportunities later.

Bug: b/147900455
Bug: swiftshader:147
Tests: dEQP-VK.image.format_reinterpret.buffer.*_b10g11r11_ufloat_pack32
Change-Id: Id817a012ff38af814907c2de2914ec24565622f3
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/46148
Presubmit-Ready: Nicolas Capens <nicolascapens@google.com>
Kokoro-Result: kokoro <noreply+kokoro@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/Pipeline/ShaderCore.cpp b/src/Pipeline/ShaderCore.cpp
index 83f8126..735248a 100644
--- a/src/Pipeline/ShaderCore.cpp
+++ b/src/Pipeline/ShaderCore.cpp
@@ -569,29 +569,27 @@
 
 SIMD::UInt floatToHalfBits(SIMD::UInt floatBits, bool storeInUpperBits)
 {
-	static const uint32_t mask_sign = 0x80000000u;
-	static const uint32_t mask_round = ~0xfffu;
-	static const uint32_t c_f32infty = 255 << 23;
-	static const uint32_t c_magic = 15 << 23;
-	static const uint32_t c_nanbit = 0x200;
-	static const uint32_t c_infty_as_fp16 = 0x7c00;
-	static const uint32_t c_clamp = (31 << 23) - 0x1000;
+	SIMD::UInt sign = floatBits & SIMD::UInt(0x80000000);
+	SIMD::UInt abs = floatBits & SIMD::UInt(0x7FFFFFFF);
 
-	SIMD::UInt justsign = SIMD::UInt(mask_sign) & floatBits;
-	SIMD::UInt absf = floatBits ^ justsign;
-	SIMD::UInt b_isnormal = CmpNLE(SIMD::UInt(c_f32infty), absf);
+	SIMD::UInt normal = CmpNLE(abs, SIMD::UInt(0x38800000));
 
-	// Note: this version doesn't round to the nearest even in case of a tie as defined by IEEE 754-2008, it rounds to +inf
-	//       instead of nearest even, since that's fine for GLSL ES 3.0's needs (see section 2.1.1 Floating-Point Computation)
-	SIMD::UInt joined = ((((As<SIMD::UInt>(Min(As<SIMD::Float>(absf & SIMD::UInt(mask_round)) * As<SIMD::Float>(SIMD::UInt(c_magic)),
-	                                           As<SIMD::Float>(SIMD::UInt(c_clamp))))) -
-	                       SIMD::UInt(mask_round)) >>
-	                      13) &
-	                     b_isnormal) |
-	                    ((b_isnormal ^ SIMD::UInt(0xFFFFFFFF)) &
-	                     ((CmpNLE(absf, SIMD::UInt(c_f32infty)) & SIMD::UInt(c_nanbit)) | SIMD::UInt(c_infty_as_fp16)));
+	SIMD::UInt mantissa = (abs & SIMD::UInt(0x007FFFFF)) | SIMD::UInt(0x00800000);
+	SIMD::UInt e = SIMD::UInt(113) - (abs >> 23);
+	SIMD::UInt denormal = CmpLT(e, SIMD::UInt(24)) & (mantissa >> e);
 
-	return storeInUpperBits ? ((joined << 16) | justsign) : joined | (justsign >> 16);
+	SIMD::UInt base = (normal & abs) | (~normal & denormal);  // TODO: IfThenElse()
+
+	// float exponent bias is 127, half bias is 15, so adjust by -112
+	SIMD::UInt bias = normal & SIMD::UInt(0xC8000000);
+
+	SIMD::UInt rounded = base + bias + SIMD::UInt(0x00000FFF) + ((base >> 13) & SIMD::UInt(1));
+	SIMD::UInt fp16u = rounded >> 13;
+
+	// Infinity
+	fp16u |= CmpNLE(abs, SIMD::UInt(0x47FFEFFF)) & SIMD::UInt(0x7FFF);
+
+	return storeInUpperBits ? (sign | (fp16u << 16)) : ((sign >> 16) | fp16u);
 }
 
 Float4 r11g11b10Unpack(UInt r11g11b10bits)
diff --git a/src/System/Half.cpp b/src/System/Half.cpp
index ea66920..fd04a31 100644
--- a/src/System/Half.cpp
+++ b/src/System/Half.cpp
@@ -29,7 +29,7 @@
 	else if(abs < 0x38800000)  // Denormal
 	{
 		unsigned int mantissa = (abs & 0x007FFFFF) | 0x00800000;
-		int e = 113 - (abs >> 23);
+		unsigned int e = 113 - (abs >> 23);
 
 		if(e < 24)
 		{