SpirvShader: Implement GLSLstd450NMin
Beware: the dEQP tests here are very weak - they do not seem to properly test the NaN handling of this instruction.
Bug: b/126873455
Tests: dEQP-VK.spirv_assembly.instruction.compute.opnmin.all
Change-Id: I5283af4a1e697b080f53193bc21ddd446b232d1e
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/28709
Reviewed-by: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 0f5dc78..8ac76c2 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -69,6 +69,23 @@
auto v = rr::As<sw::SIMD::UInt>(f);
return (sw::SIMD::Int((v >> sw::SIMD::UInt(23)) & sw::SIMD::UInt(0xFF)) - sw::SIMD::Int(126));
}
+
+ // Returns y if y < x; otherwise result is x.
+ // If one operand is a NaN, the other operand is the result.
+ // If both operands are NaN, the result is a NaN.
+ rr::RValue<sw::SIMD::Float> NMin(rr::RValue<sw::SIMD::Float> const &x, rr::RValue<sw::SIMD::Float> const &y)
+ {
+ using namespace rr;
+ auto xIsNan = IsNan(x);
+ auto yIsNan = IsNan(y);
+ return As<sw::SIMD::Float>(
+ // If neither are NaN, return min
+ ((~xIsNan & ~yIsNan) & As<sw::SIMD::Int>(Min(x, y))) |
+ // If one operand is a NaN, the other operand is the result
+ // If both operands are NaN, the result is a NaN.
+ ((~xIsNan & yIsNan) & As<sw::SIMD::Int>(x)) |
+ (( xIsNan ) & As<sw::SIMD::Int>(y)));
+ }
}
namespace sw
@@ -3539,7 +3556,12 @@
}
case GLSLstd450NMin:
{
- UNIMPLEMENTED("GLSLstd450NMin");
+ auto x = GenericValue(this, routine, insn.word(5));
+ auto y = GenericValue(this, routine, insn.word(6));
+ for (auto i = 0u; i < type.sizeInComponents; i++)
+ {
+ dst.move(i, NMin(x.Float(i), y.Float(i)));
+ }
break;
}
case GLSLstd450NMax: