SpirvShader: Add relational ops for ordered and unordered floats

Bug: b/127282157
Change-Id: Id2c5b29d744f6f7ddcbb853db0a95228425d7f83
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/26108
Tested-by: Ben Clayton <bclayton@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index d3c0061..1b3e297 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -250,6 +250,18 @@
 			case spv::OpFAdd:
 			case spv::OpFSub:
 			case spv::OpFDiv:
+			case spv::OpFOrdEqual:
+			case spv::OpFUnordEqual:
+			case spv::OpFOrdNotEqual:
+			case spv::OpFUnordNotEqual:
+			case spv::OpFOrdLessThan:
+			case spv::OpFUnordLessThan:
+			case spv::OpFOrdGreaterThan:
+			case spv::OpFUnordGreaterThan:
+			case spv::OpFOrdLessThanEqual:
+			case spv::OpFUnordLessThanEqual:
+			case spv::OpFOrdGreaterThanEqual:
+			case spv::OpFUnordGreaterThanEqual:
 			case spv::OpUMod:
 			case spv::OpIEqual:
 			case spv::OpINotEqual:
@@ -953,6 +965,18 @@
 			case spv::OpFAdd:
 			case spv::OpFSub:
 			case spv::OpFDiv:
+			case spv::OpFOrdEqual:
+			case spv::OpFUnordEqual:
+			case spv::OpFOrdNotEqual:
+			case spv::OpFUnordNotEqual:
+			case spv::OpFOrdLessThan:
+			case spv::OpFUnordLessThan:
+			case spv::OpFOrdGreaterThan:
+			case spv::OpFUnordGreaterThan:
+			case spv::OpFOrdLessThanEqual:
+			case spv::OpFUnordLessThanEqual:
+			case spv::OpFOrdGreaterThanEqual:
+			case spv::OpFUnordGreaterThanEqual:
 			case spv::OpUMod:
 			case spv::OpIEqual:
 			case spv::OpINotEqual:
@@ -1354,6 +1378,42 @@
 			case spv::OpFDiv:
 				dst.emplace(i, lhs / rhs);
 				break;
+			case spv::OpFOrdEqual:
+				dst.emplace(i, As<SIMD::Float>(CmpEQ(lhs, rhs)));
+				break;
+			case spv::OpFUnordEqual:
+				dst.emplace(i, As<SIMD::Float>(CmpUEQ(lhs, rhs)));
+				break;
+			case spv::OpFOrdNotEqual:
+				dst.emplace(i, As<SIMD::Float>(CmpNEQ(lhs, rhs)));
+				break;
+			case spv::OpFUnordNotEqual:
+				dst.emplace(i, As<SIMD::Float>(CmpUNEQ(lhs, rhs)));
+				break;
+			case spv::OpFOrdLessThan:
+				dst.emplace(i, As<SIMD::Float>(CmpLT(lhs, rhs)));
+				break;
+			case spv::OpFUnordLessThan:
+				dst.emplace(i, As<SIMD::Float>(CmpULT(lhs, rhs)));
+				break;
+			case spv::OpFOrdGreaterThan:
+				dst.emplace(i, As<SIMD::Float>(CmpGT(lhs, rhs)));
+				break;
+			case spv::OpFUnordGreaterThan:
+				dst.emplace(i, As<SIMD::Float>(CmpUGT(lhs, rhs)));
+				break;
+			case spv::OpFOrdLessThanEqual:
+				dst.emplace(i, As<SIMD::Float>(CmpLE(lhs, rhs)));
+				break;
+			case spv::OpFUnordLessThanEqual:
+				dst.emplace(i, As<SIMD::Float>(CmpULE(lhs, rhs)));
+				break;
+			case spv::OpFOrdGreaterThanEqual:
+				dst.emplace(i, As<SIMD::Float>(CmpGE(lhs, rhs)));
+				break;
+			case spv::OpFUnordGreaterThanEqual:
+				dst.emplace(i, As<SIMD::Float>(CmpUGE(lhs, rhs)));
+				break;
 			case spv::OpShiftRightLogical:
 				dst.emplace(i, As<SIMD::Float>(As<SIMD::UInt>(lhs) >> As<SIMD::UInt>(rhs)));
 				break;
diff --git a/src/Reactor/LLVMReactor.cpp b/src/Reactor/LLVMReactor.cpp
index 6831082..d0b6659 100644
--- a/src/Reactor/LLVMReactor.cpp
+++ b/src/Reactor/LLVMReactor.cpp
@@ -6809,6 +6809,36 @@
 		return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpOGT(x.value, y.value), Int4::getType()));
 	}
 
+	RValue<Int4> CmpUEQ(RValue<Float4> x, RValue<Float4> y)
+	{
+		return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpUEQ(x.value, y.value), Int4::getType()));
+	}
+
+	RValue<Int4> CmpULT(RValue<Float4> x, RValue<Float4> y)
+	{
+		return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpULT(x.value, y.value), Int4::getType()));
+	}
+
+	RValue<Int4> CmpULE(RValue<Float4> x, RValue<Float4> y)
+	{
+		return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpULE(x.value, y.value), Int4::getType()));
+	}
+
+	RValue<Int4> CmpUNEQ(RValue<Float4> x, RValue<Float4> y)
+	{
+		return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpUNE(x.value, y.value), Int4::getType()));
+	}
+
+	RValue<Int4> CmpUNLT(RValue<Float4> x, RValue<Float4> y)
+	{
+		return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpUGE(x.value, y.value), Int4::getType()));
+	}
+
+	RValue<Int4> CmpUNLE(RValue<Float4> x, RValue<Float4> y)
+	{
+		return RValue<Int4>(Nucleus::createSExt(Nucleus::createFCmpUGT(x.value, y.value), Int4::getType()));
+	}
+
 	RValue<Int4> IsInf(RValue<Float4> x)
 	{
 		return CmpEQ(As<Int4>(x) & Int4(0x7FFFFFFF), Int4(0x7F800000));
diff --git a/src/Reactor/Reactor.hpp b/src/Reactor/Reactor.hpp
index cfbd00a..099ced3 100644
--- a/src/Reactor/Reactor.hpp
+++ b/src/Reactor/Reactor.hpp
@@ -2138,12 +2138,27 @@
 	RValue<Float4> UnpackHigh(RValue<Float4> x, RValue<Float4> y);
 	RValue<Float4> Mask(Float4 &lhs, RValue<Float4> rhs, unsigned char select);
 	RValue<Int> SignMask(RValue<Float4> x);
+
+	// Ordered comparison functions
 	RValue<Int4> CmpEQ(RValue<Float4> x, RValue<Float4> y);
 	RValue<Int4> CmpLT(RValue<Float4> x, RValue<Float4> y);
 	RValue<Int4> CmpLE(RValue<Float4> x, RValue<Float4> y);
 	RValue<Int4> CmpNEQ(RValue<Float4> x, RValue<Float4> y);
 	RValue<Int4> CmpNLT(RValue<Float4> x, RValue<Float4> y);
 	RValue<Int4> CmpNLE(RValue<Float4> x, RValue<Float4> y);
+	inline RValue<Int4> CmpGT(RValue<Float4> x, RValue<Float4> y) { return CmpNLE(x, y); }
+	inline RValue<Int4> CmpGE(RValue<Float4> x, RValue<Float4> y) { return CmpNLT(x, y); }
+
+	// Unordered comparison functions
+	RValue<Int4> CmpUEQ(RValue<Float4> x, RValue<Float4> y);
+	RValue<Int4> CmpULT(RValue<Float4> x, RValue<Float4> y);
+	RValue<Int4> CmpULE(RValue<Float4> x, RValue<Float4> y);
+	RValue<Int4> CmpUNEQ(RValue<Float4> x, RValue<Float4> y);
+	RValue<Int4> CmpUNLT(RValue<Float4> x, RValue<Float4> y);
+	RValue<Int4> CmpUNLE(RValue<Float4> x, RValue<Float4> y);
+	inline RValue<Int4> CmpUGT(RValue<Float4> x, RValue<Float4> y) { return CmpUNLE(x, y); }
+	inline RValue<Int4> CmpUGE(RValue<Float4> x, RValue<Float4> y) { return CmpUNLT(x, y); }
+
 	RValue<Int4> IsInf(RValue<Float4> x);
 	RValue<Int4> IsNan(RValue<Float4> x);
 	RValue<Float4> Round(RValue<Float4> x);
diff --git a/src/Reactor/SubzeroReactor.cpp b/src/Reactor/SubzeroReactor.cpp
index 7048640..b4f1971 100644
--- a/src/Reactor/SubzeroReactor.cpp
+++ b/src/Reactor/SubzeroReactor.cpp
@@ -6387,38 +6387,38 @@
 		return T(Ice::IceType_v4i32);
 	}
 
-	Half::Half(RValue<Float> cast)

-	{

-		UInt fp32i = As<UInt>(cast);

-		UInt abs = fp32i & 0x7FFFFFFF;

-		UShort fp16i((fp32i & 0x80000000) >> 16); // sign

-

-		If(abs > 0x47FFEFFF) // Infinity

-		{

-			fp16i |= UShort(0x7FFF);

-		}

-		Else

-		{

-			If(abs < 0x38800000) // Denormal

-			{

-				Int mantissa = (abs & 0x007FFFFF) | 0x00800000;

-				Int e = 113 - (abs >> 23);

-				abs = IfThenElse(e < 24, mantissa >> e, Int(0));

-				fp16i |= UShort((abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13);

-			}

-			Else

-			{

-				fp16i |= UShort((abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13);

-			}

-		}

-

-		storeValue(fp16i.loadValue());

-	}

-

-	Type *Half::getType()

-	{

-		return T(Ice::IceType_i16);

-	}

+	Half::Half(RValue<Float> cast)
+	{
+		UInt fp32i = As<UInt>(cast);
+		UInt abs = fp32i & 0x7FFFFFFF;
+		UShort fp16i((fp32i & 0x80000000) >> 16); // sign
+
+		If(abs > 0x47FFEFFF) // Infinity
+		{
+			fp16i |= UShort(0x7FFF);
+		}
+		Else
+		{
+			If(abs < 0x38800000) // Denormal
+			{
+				Int mantissa = (abs & 0x007FFFFF) | 0x00800000;
+				Int e = 113 - (abs >> 23);
+				abs = IfThenElse(e < 24, mantissa >> e, Int(0));
+				fp16i |= UShort((abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13);
+			}
+			Else
+			{
+				fp16i |= UShort((abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13);
+			}
+		}
+
+		storeValue(fp16i.loadValue());
+	}
+
+	Type *Half::getType()
+	{
+		return T(Ice::IceType_i16);
+	}
 
 	Float::Float(RValue<Int> cast)
 	{
@@ -6435,34 +6435,34 @@
 		storeValue(result.value);
 	}
 
-	Float::Float(RValue<Half> cast)

-	{

-		Int fp16i(As<UShort>(cast));

-

-		Int s = (fp16i >> 15) & 0x00000001;

-		Int e = (fp16i >> 10) & 0x0000001F;

-		Int m = fp16i & 0x000003FF;

-

-		UInt fp32i(s << 31);

-		If(e == 0)

-		{

-			If(m != 0)

-			{

-				While((m & 0x00000400) == 0)

-				{

-					m <<= 1;

-					e -= 1;

-				}

-

-				fp32i |= As<UInt>(((e + (127 - 15) + 1) << 23) | ((m & ~0x00000400) << 13));

-			}

-		}

-		Else

-		{

-			fp32i |= As<UInt>(((e + (127 - 15)) << 23) | (m << 13));

-		}

-

-		storeValue(As<Float>(fp32i).value);

+	Float::Float(RValue<Half> cast)
+	{
+		Int fp16i(As<UShort>(cast));
+
+		Int s = (fp16i >> 15) & 0x00000001;
+		Int e = (fp16i >> 10) & 0x0000001F;
+		Int m = fp16i & 0x000003FF;
+
+		UInt fp32i(s << 31);
+		If(e == 0)
+		{
+			If(m != 0)
+			{
+				While((m & 0x00000400) == 0)
+				{
+					m <<= 1;
+					e -= 1;
+				}
+
+				fp32i |= As<UInt>(((e + (127 - 15) + 1) << 23) | ((m & ~0x00000400) << 13));
+			}
+		}
+		Else
+		{
+			fp32i |= As<UInt>(((e + (127 - 15)) << 23) | (m << 13));
+		}
+
+		storeValue(As<Float>(fp32i).value);
 	}
 
 	Float::Float(float x)
@@ -7049,6 +7049,36 @@
 		return RValue<Int4>(Nucleus::createFCmpOGT(x.value, y.value));
 	}
 
+	RValue<Int4> CmpUEQ(RValue<Float4> x, RValue<Float4> y)
+	{
+		return RValue<Int4>(Nucleus::createFCmpUEQ(x.value, y.value));
+	}
+
+	RValue<Int4> CmpULT(RValue<Float4> x, RValue<Float4> y)
+	{
+		return RValue<Int4>(Nucleus::createFCmpULT(x.value, y.value));
+	}
+
+	RValue<Int4> CmpULE(RValue<Float4> x, RValue<Float4> y)
+	{
+		return RValue<Int4>(Nucleus::createFCmpULE(x.value, y.value));
+	}
+
+	RValue<Int4> CmpUNEQ(RValue<Float4> x, RValue<Float4> y)
+	{
+		return RValue<Int4>(Nucleus::createFCmpUNE(x.value, y.value));
+	}
+
+	RValue<Int4> CmpUNLT(RValue<Float4> x, RValue<Float4> y)
+	{
+		return RValue<Int4>(Nucleus::createFCmpUGE(x.value, y.value));
+	}
+
+	RValue<Int4> CmpUNLE(RValue<Float4> x, RValue<Float4> y)
+	{
+		return RValue<Int4>(Nucleus::createFCmpUGT(x.value, y.value));
+	}
+
 	RValue<Int4> IsInf(RValue<Float4> x)
 	{
 		return CmpEQ(As<Int4>(x) & Int4(0x7FFFFFFF), Int4(0x7F800000));