[hlsl] Add `quantizeToF16` support to HLSL IR backend.

This CL adds the polyfill for the `quantizeToF16` method to the HLSL IR
backend.

Bug: 42251045
Change-Id: Ia2d87511151eee979169f5c94c1bd7256b088416
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/198561
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/hlsl/writer/builtin_test.cc b/src/tint/lang/hlsl/writer/builtin_test.cc
index 64ea3a5..7c345dc 100644
--- a/src/tint/lang/hlsl/writer/builtin_test.cc
+++ b/src/tint/lang/hlsl/writer/builtin_test.cc
@@ -1318,6 +1318,24 @@
 )");
 }
 
+TEST_F(HlslWriterTest, BuiltinQuantizeToF16) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* v = b.Var("x", b.Zero(ty.vec2<f32>()));
+        b.Let("a", b.Call(ty.vec2<f32>(), core::BuiltinFn::kQuantizeToF16, b.Load(v)));
+        b.Return(func);
+    });
+
+    ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
+    EXPECT_EQ(output_.hlsl, R"(
+void foo() {
+  float2 x = (0.0f).xx;
+  float2 a = f16tof32(f32tof16(x));
+}
+
+)");
+}
+
 TEST_F(HlslWriterTest, BuiltinUnpack2x16Float) {
     auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
diff --git a/src/tint/lang/hlsl/writer/raise/builtin_polyfill.cc b/src/tint/lang/hlsl/writer/raise/builtin_polyfill.cc
index ef0d92e..77536a7 100644
--- a/src/tint/lang/hlsl/writer/raise/builtin_polyfill.cc
+++ b/src/tint/lang/hlsl/writer/raise/builtin_polyfill.cc
@@ -87,6 +87,7 @@
             }
             if (auto* call = inst->As<core::ir::CoreBuiltinCall>()) {
                 switch (call->Func()) {
+                    case core::BuiltinFn::kQuantizeToF16:
                     case core::BuiltinFn::kSelect:
                     case core::BuiltinFn::kSign:
                     case core::BuiltinFn::kTextureDimensions:
@@ -132,6 +133,9 @@
         // Replace the builtin calls that we found
         for (auto* call : call_worklist) {
             switch (call->Func()) {
+                case core::BuiltinFn::kQuantizeToF16:
+                    QuantizeToF16(call);
+                    break;
                 case core::BuiltinFn::kSelect:
                     Select(call);
                     break;
@@ -824,6 +828,17 @@
         });
         call->Destroy();
     }
+
+    void QuantizeToF16(core::ir::CoreBuiltinCall* call) {
+        auto* u32_type = ty.match_width(ty.u32(), call->Result(0)->Type());
+        b.InsertBefore(call, [&] {
+            auto* inner = b.Call<hlsl::ir::BuiltinCall>(u32_type, hlsl::BuiltinFn::kF32Tof16,
+                                                        call->Args()[0]);
+            b.CallWithResult<hlsl::ir::BuiltinCall>(call->DetachResult(),
+                                                    hlsl::BuiltinFn::kF16Tof32, inner);
+        });
+        call->Destroy();
+    }
 };
 
 }  // namespace
diff --git a/src/tint/lang/hlsl/writer/raise/builtin_polyfill_test.cc b/src/tint/lang/hlsl/writer/raise/builtin_polyfill_test.cc
index ed52790..c46fba9 100644
--- a/src/tint/lang/hlsl/writer/raise/builtin_polyfill_test.cc
+++ b/src/tint/lang/hlsl/writer/raise/builtin_polyfill_test.cc
@@ -1173,6 +1173,44 @@
     EXPECT_EQ(expect, str());
 }
 
+TEST_F(HlslWriter_BuiltinPolyfillTest, QuantizeToF16) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* v = b.Var("x", b.Zero(ty.vec2<f32>()));
+        b.Let("a", b.Call(ty.vec2<f32>(), core::BuiltinFn::kQuantizeToF16, b.Load(v)));
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %x:ptr<function, vec2<f32>, read_write> = var, vec2<f32>(0.0f)
+    %3:vec2<f32> = load %x
+    %4:vec2<f32> = quantizeToF16 %3
+    %a:vec2<f32> = let %4
+    ret
+  }
+}
+)";
+    ASSERT_EQ(src, str());
+
+    auto* expect = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %x:ptr<function, vec2<f32>, read_write> = var, vec2<f32>(0.0f)
+    %3:vec2<f32> = load %x
+    %4:vec2<u32> = hlsl.f32tof16 %3
+    %5:vec2<f32> = hlsl.f16tof32 %4
+    %a:vec2<f32> = let %5
+    ret
+  }
+}
+)";
+    Run(BuiltinPolyfill);
+
+    EXPECT_EQ(expect, str());
+}
+
 TEST_F(HlslWriter_BuiltinPolyfillTest, Unpack2x16Float) {
     auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {