SpirvShader: Implement OpQuantizeToF16

Bug: b/126873455
Test: *opquantize*
Change-Id: I941ce6e2f39b81686eeb91b92694a14fa3b9f5f7
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/29569
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Ben Clayton <bclayton@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index ff6c164..d63c97b 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -745,6 +745,7 @@
 			case spv::OpSNegate:
 			case spv::OpFNegate:
 			case spv::OpLogicalNot:
+			case spv::OpQuantizeToF16:
 			// Binary ops
 			case spv::OpIAdd:
 			case spv::OpISub:
@@ -2271,6 +2272,7 @@
 		case spv::OpDPdxFine:
 		case spv::OpDPdyFine:
 		case spv::OpFwidthFine:
+		case spv::OpQuantizeToF16:
 			return EmitUnaryOp(insn, state);
 
 		case spv::OpIAdd:
@@ -3040,6 +3042,21 @@
 				dst.move(i, Abs(dpdx) + Abs(dpdy));
 				break;
 			}
+			case spv::OpQuantizeToF16:
+			{
+				auto abs = Abs(src.Float(i));
+				auto sign = src.Int(i) & SIMD::Int(0x80000000);
+				auto isZero = CmpLT(abs, SIMD::Float(0.000061035));
+				auto isInf  = CmpGT(abs, SIMD::Float(65504.0f));
+				auto isNaN  = IsNan(abs);
+				auto isInfOrNan = isInf | isNaN;
+				SIMD::Int v = src.Int(i) & SIMD::Int(0xFFFFE000);
+				v &= ~isZero | SIMD::Int(0x80000000);
+				v = sign | (isInfOrNan & SIMD::Int(0x7F800000)) | (~isInfOrNan & v);
+				v |= isNaN & SIMD::Int(0x400000);
+				dst.move(i, v);
+				break;
+			}
 			default:
 				UNIMPLEMENTED("Unhandled unary operator %s", OpcodeName(insn.opcode()).c_str());
 			}