SpirvShader: Precision fixes for GLSLstd450Ldexp
Bug: b/126873455
Tests: dEQP-VK.glsl.builtin.precision.ldexp.*
Tests: dEQP-VK.glsl.builtin.function.common.ldexp.*
Change-Id: If70125d749ba976abfa7295f067be51c5e8c2417
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/31409
Presubmit-Ready: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Reviewed-by: Chris Forbes <chrisforbes@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 9a507bf..1522c91 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -3955,10 +3955,29 @@
for (auto i = 0u; i < type.sizeInComponents; i++)
{
// Assumes IEEE 754
- auto significandExponent = Exponent(significand.Float(i));
+ auto in = significand.Float(i);
+ auto significandExponent = Exponent(in);
auto combinedExponent = exponent.Int(i) + significandExponent;
- SIMD::UInt v = (significand.UInt(i) & SIMD::UInt(0x807FFFFF)) |
- (SIMD::UInt(combinedExponent + SIMD::Int(126)) << SIMD::UInt(23));
+ auto isSignificandZero = SIMD::UInt(CmpEQ(significand.Int(0), SIMD::Int(0)));
+ auto isSignificandInf = SIMD::UInt(IsInf(in));
+ auto isSignificandNaN = SIMD::UInt(IsNan(in));
+ auto isExponentNotTooSmall = SIMD::UInt(CmpGE(combinedExponent, SIMD::Int(-126)));
+ auto isExponentNotTooLarge = SIMD::UInt(CmpLE(combinedExponent, SIMD::Int(128)));
+ auto isExponentInBounds = isExponentNotTooSmall & isExponentNotTooLarge;
+
+ SIMD::UInt v;
+ v = significand.UInt(i) & SIMD::UInt(0x7FFFFF); // Add significand.
+ v |= (SIMD::UInt(combinedExponent + SIMD::Int(126)) << SIMD::UInt(23)); // Add exponent.
+ v &= isExponentInBounds; // Clear v if the exponent is OOB.
+
+ v |= significand.UInt(i) & SIMD::UInt(0x80000000); // Add sign bit.
+ v |= ~isExponentNotTooLarge & SIMD::UInt(0x7F800000); // Mark as inf if the exponent is too great.
+
+ // If the input significand is zero, inf or nan, just return the
+ // input significand.
+ auto passthrough = isSignificandZero | isSignificandInf | isSignificandNaN;
+ v = (v & ~passthrough) | (significand.UInt(0) & passthrough);
+
dst.move(i, As<SIMD::Float>(v));
}
break;