tint: Implement runtime quantizeToF16()

Fixed: tint:991
Fixed: tint:1741
Change-Id: I55dbabce6d28adf5abb710dc1e3e879c5aaa6be5
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/108140
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index d9c3479..248da38 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -1047,6 +1047,9 @@
     if (type == sem::BuiltinType::kRadians) {
         return EmitRadiansCall(out, expr, builtin);
     }
+    if (type == sem::BuiltinType::kQuantizeToF16) {
+        return EmitQuantizeToF16Call(out, expr, builtin);
+    }
     if (builtin->IsDataPacking()) {
         return EmitDataPackingCall(out, expr, builtin);
     }
@@ -1940,6 +1943,22 @@
                              });
 }
 
+bool GeneratorImpl::EmitQuantizeToF16Call(std::ostream& out,
+                                          const ast::CallExpression* expr,
+                                          const sem::Builtin* builtin) {
+    // Emulate by casting to min16float and back again.
+    std::string width;
+    if (auto* vec = builtin->ReturnType()->As<sem::Vector>()) {
+        width = std::to_string(vec->Width());
+    }
+    out << "float" << width << "(min16float" << width << "(";
+    if (!EmitExpression(out, expr->args[0])) {
+        return false;
+    }
+    out << "))";
+    return true;
+}
+
 bool GeneratorImpl::EmitDataPackingCall(std::ostream& out,
                                         const ast::CallExpression* expr,
                                         const sem::Builtin* builtin) {