SpirvShader: Implement GLSLstd450NMax
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.opnmax.all
Change-Id: Ibd704c9dc9c3475df10b02c0c0f80b9c3e472ff4
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/28710
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 8ac76c2..412a0af 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -86,6 +86,23 @@
((~xIsNan & yIsNan) & As<sw::SIMD::Int>(x)) |
(( xIsNan ) & As<sw::SIMD::Int>(y)));
}
+
+ // 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> NMax(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 max
+ ((~xIsNan & ~yIsNan) & As<sw::SIMD::Int>(Max(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
@@ -3566,7 +3583,12 @@
}
case GLSLstd450NMax:
{
- UNIMPLEMENTED("GLSLstd450NMax");
+ 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, NMax(x.Float(i), y.Float(i)));
+ }
break;
}
case GLSLstd450NClamp: