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: