[glsl][ir] Polyfill `quantizeToF16`

This CL adds a polyfill for the `quantizeToF16` call.

Bug: 42251044
Change-Id: I985173bad7ad7a73a49e898b91cf5be05ea06dd7
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/208115
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/tint/lang/glsl/writer/builtin_test.cc b/src/tint/lang/glsl/writer/builtin_test.cc
index d2d0045..5bfa929 100644
--- a/src/tint/lang/glsl/writer/builtin_test.cc
+++ b/src/tint/lang/glsl/writer/builtin_test.cc
@@ -1696,5 +1696,27 @@
 )");
 }
 
+TEST_F(GlslWriterTest, 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_.glsl;
+    EXPECT_EQ(output_.glsl, GlslHeader() + R"(precision highp float;
+precision highp int;
+
+vec2 tint_quantize_to_f16(vec2 val) {
+  return unpackHalf2x16(packHalf2x16(val));
+}
+void main() {
+  vec2 x = vec2(0.0f);
+  vec2 a = tint_quantize_to_f16(x);
+}
+)");
+}
+
 }  // namespace
 }  // namespace tint::glsl::writer
diff --git a/src/tint/lang/glsl/writer/raise/builtin_polyfill.cc b/src/tint/lang/glsl/writer/raise/builtin_polyfill.cc
index cff2d85..a77ccbb 100644
--- a/src/tint/lang/glsl/writer/raise/builtin_polyfill.cc
+++ b/src/tint/lang/glsl/writer/raise/builtin_polyfill.cc
@@ -64,6 +64,8 @@
 
     /// Dot polyfills for non `f32`.
     Hashmap<const core::type::Type*, core::ir::Function*, 4> dot_funcs_{};
+    /// Quantize polyfills
+    Hashmap<const core::type::Type*, core::ir::Function*, 4> quantize_to_f16_funcs_{};
 
     /// Process the module.
     void Process() {
@@ -85,6 +87,7 @@
                     case core::BuiltinFn::kFrexp:
                     case core::BuiltinFn::kInsertBits:
                     case core::BuiltinFn::kModf:
+                    case core::BuiltinFn::kQuantizeToF16:
                     case core::BuiltinFn::kSelect:
                     case core::BuiltinFn::kStorageBarrier:
                     case core::BuiltinFn::kTextureBarrier:
@@ -147,6 +150,9 @@
                 case core::BuiltinFn::kModf:
                     Modf(call);
                     break;
+                case core::BuiltinFn::kQuantizeToF16:
+                    QuantizeToF16(call);
+                    break;
                 case core::BuiltinFn::kSelect:
                     Select(call);
                     break;
@@ -665,6 +671,73 @@
         }
         call->Destroy();
     }
+
+    core::ir::Function* CreateQuantizeToF16Polyfill(const core::type::Type* type) {
+        return quantize_to_f16_funcs_.GetOrAdd(type, [&]() -> core::ir::Function* {
+            auto* f = b.Function("tint_quantize_to_f16", type);
+            auto* val = b.FunctionParam("val", type);
+            f->SetParams({val});
+
+            b.Append(f->Block(), [&] {
+                core::ir::Value* ret = nullptr;
+
+                auto* inner_ty = type->DeepestElement();
+                auto* v2 = ty.vec2(inner_ty);
+
+                auto pack_unpack = [&](core::ir::Value* item) {
+                    auto* r = b.Call(ty.u32(), core::BuiltinFn::kPack2X16Float, item)->Result(0);
+                    return b.Call(v2, core::BuiltinFn::kUnpack2X16Float, r)->Result(0);
+                };
+
+                if (auto* vec = type->As<core::type::Vector>()) {
+                    switch (vec->Width()) {
+                        case 2: {
+                            ret = pack_unpack(val);
+                            break;
+                        }
+                        case 3: {
+                            core::ir::Value* lhs = b.Swizzle(v2, val, {0, 1})->Result(0);
+                            lhs = pack_unpack(lhs);
+
+                            core::ir::Value* rhs = b.Swizzle(v2, val, {2, 2})->Result(0);
+                            rhs = pack_unpack(rhs);
+                            rhs = b.Swizzle(inner_ty, rhs, {0})->Result(0);
+
+                            ret = b.Construct(type, lhs, rhs)->Result(0);
+                            break;
+                        }
+                        default: {
+                            core::ir::Value* lhs = b.Swizzle(v2, val, {0, 1})->Result(0);
+                            lhs = pack_unpack(lhs);
+
+                            core::ir::Value* rhs = b.Swizzle(v2, val, {2, 3})->Result(0);
+                            rhs = pack_unpack(rhs);
+
+                            ret = b.Construct(type, lhs, rhs)->Result(0);
+                            break;
+                        }
+                    }
+                } else {
+                    ret = b.Construct(v2, val)->Result(0);
+                    ret = pack_unpack(ret);
+                    ret = b.Swizzle(type, ret, {0})->Result(0);
+                }
+                b.Return(f, ret);
+            });
+            return f;
+        });
+    }
+
+    // Emulate by casting to f16 and back again.
+    void QuantizeToF16(core::ir::BuiltinCall* call) {
+        auto args = call->Args();
+
+        b.InsertBefore(call, [&] {
+            auto* func = CreateQuantizeToF16Polyfill(args[0]->Type());
+            b.CallWithResult(call->DetachResult(), func, args[0]);
+        });
+        call->Destroy();
+    }
 };
 
 }  // namespace
diff --git a/src/tint/lang/glsl/writer/raise/builtin_polyfill_test.cc b/src/tint/lang/glsl/writer/raise/builtin_polyfill_test.cc
index 0e233a6..14f8a07 100644
--- a/src/tint/lang/glsl/writer/raise/builtin_polyfill_test.cc
+++ b/src/tint/lang/glsl/writer/raise/builtin_polyfill_test.cc
@@ -1989,5 +1989,48 @@
     EXPECT_EQ(expect, str());
 }
 
+TEST_F(GlslWriter_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<f32> = call %tint_quantize_to_f16, %3
+    %a:vec2<f32> = let %4
+    ret
+  }
+}
+%tint_quantize_to_f16 = func(%val:vec2<f32>):vec2<f32> {
+  $B2: {
+    %8:u32 = pack2x16float %val
+    %9:vec2<f32> = unpack2x16float %8
+    ret %9
+  }
+}
+)";
+    Run(BuiltinPolyfill);
+    EXPECT_EQ(expect, str());
+}
+
 }  // namespace
 }  // namespace tint::glsl::writer::raise
diff --git a/test/tint/builtins/gen/var/quantizeToF16/12e50e.wgsl.expected.ir.glsl b/test/tint/builtins/gen/var/quantizeToF16/12e50e.wgsl.expected.ir.glsl
index 2fe1fc2..ac40e09 100644
--- a/test/tint/builtins/gen/var/quantizeToF16/12e50e.wgsl.expected.ir.glsl
+++ b/test/tint/builtins/gen/var/quantizeToF16/12e50e.wgsl.expected.ir.glsl
@@ -1,11 +1,68 @@
-SKIP: FAILED
+#version 310 es
+precision highp float;
+precision highp int;
 
-<dawn>/src/tint/lang/glsl/writer/printer/printer.cc:1451 internal compiler error: TINT_UNREACHABLE unhandled core builtin: quantizeToF16
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+layout(binding = 0, std430)
+buffer tint_symbol_1_1_ssbo {
+  float tint_symbol;
+} v;
+float tint_quantize_to_f16(float val) {
+  return unpackHalf2x16(packHalf2x16(vec2(val))).x;
+}
+float quantizeToF16_12e50e() {
+  float arg_0 = 1.0f;
+  float res = tint_quantize_to_f16(arg_0);
+  return res;
+}
+void main() {
+  v.tint_symbol = quantizeToF16_12e50e();
+}
+#version 310 es
 
-tint executable returned error: signal: trace/BPT trap
+layout(binding = 0, std430)
+buffer tint_symbol_1_1_ssbo {
+  float tint_symbol;
+} v;
+float tint_quantize_to_f16(float val) {
+  return unpackHalf2x16(packHalf2x16(vec2(val))).x;
+}
+float quantizeToF16_12e50e() {
+  float arg_0 = 1.0f;
+  float res = tint_quantize_to_f16(arg_0);
+  return res;
+}
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  v.tint_symbol = quantizeToF16_12e50e();
+}
+#version 310 es
+
+
+struct VertexOutput {
+  vec4 pos;
+  float prevent_dce;
+};
+
+layout(location = 0) flat out float vertex_main_loc0_Output;
+float tint_quantize_to_f16(float val) {
+  return unpackHalf2x16(packHalf2x16(vec2(val))).x;
+}
+float quantizeToF16_12e50e() {
+  float arg_0 = 1.0f;
+  float res = tint_quantize_to_f16(arg_0);
+  return res;
+}
+VertexOutput vertex_main_inner() {
+  VertexOutput tint_symbol = VertexOutput(vec4(0.0f), 0.0f);
+  tint_symbol.pos = vec4(0.0f);
+  tint_symbol.prevent_dce = quantizeToF16_12e50e();
+  return tint_symbol;
+}
+void main() {
+  VertexOutput v = vertex_main_inner();
+  gl_Position = v.pos;
+  gl_Position[1u] = -(gl_Position.y);
+  gl_Position[2u] = ((2.0f * gl_Position.z) - gl_Position.w);
+  vertex_main_loc0_Output = v.prevent_dce;
+  gl_PointSize = 1.0f;
+}
diff --git a/test/tint/builtins/gen/var/quantizeToF16/2cddf3.wgsl.expected.ir.glsl b/test/tint/builtins/gen/var/quantizeToF16/2cddf3.wgsl.expected.ir.glsl
index 2fe1fc2..eeb2f5f 100644
--- a/test/tint/builtins/gen/var/quantizeToF16/2cddf3.wgsl.expected.ir.glsl
+++ b/test/tint/builtins/gen/var/quantizeToF16/2cddf3.wgsl.expected.ir.glsl
@@ -1,11 +1,68 @@
-SKIP: FAILED
+#version 310 es
+precision highp float;
+precision highp int;
 
-<dawn>/src/tint/lang/glsl/writer/printer/printer.cc:1451 internal compiler error: TINT_UNREACHABLE unhandled core builtin: quantizeToF16
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+layout(binding = 0, std430)
+buffer tint_symbol_1_1_ssbo {
+  vec2 tint_symbol;
+} v;
+vec2 tint_quantize_to_f16(vec2 val) {
+  return unpackHalf2x16(packHalf2x16(val));
+}
+vec2 quantizeToF16_2cddf3() {
+  vec2 arg_0 = vec2(1.0f);
+  vec2 res = tint_quantize_to_f16(arg_0);
+  return res;
+}
+void main() {
+  v.tint_symbol = quantizeToF16_2cddf3();
+}
+#version 310 es
 
-tint executable returned error: signal: trace/BPT trap
+layout(binding = 0, std430)
+buffer tint_symbol_1_1_ssbo {
+  vec2 tint_symbol;
+} v;
+vec2 tint_quantize_to_f16(vec2 val) {
+  return unpackHalf2x16(packHalf2x16(val));
+}
+vec2 quantizeToF16_2cddf3() {
+  vec2 arg_0 = vec2(1.0f);
+  vec2 res = tint_quantize_to_f16(arg_0);
+  return res;
+}
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  v.tint_symbol = quantizeToF16_2cddf3();
+}
+#version 310 es
+
+
+struct VertexOutput {
+  vec4 pos;
+  vec2 prevent_dce;
+};
+
+layout(location = 0) flat out vec2 vertex_main_loc0_Output;
+vec2 tint_quantize_to_f16(vec2 val) {
+  return unpackHalf2x16(packHalf2x16(val));
+}
+vec2 quantizeToF16_2cddf3() {
+  vec2 arg_0 = vec2(1.0f);
+  vec2 res = tint_quantize_to_f16(arg_0);
+  return res;
+}
+VertexOutput vertex_main_inner() {
+  VertexOutput tint_symbol = VertexOutput(vec4(0.0f), vec2(0.0f));
+  tint_symbol.pos = vec4(0.0f);
+  tint_symbol.prevent_dce = quantizeToF16_2cddf3();
+  return tint_symbol;
+}
+void main() {
+  VertexOutput v = vertex_main_inner();
+  gl_Position = v.pos;
+  gl_Position[1u] = -(gl_Position.y);
+  gl_Position[2u] = ((2.0f * gl_Position.z) - gl_Position.w);
+  vertex_main_loc0_Output = v.prevent_dce;
+  gl_PointSize = 1.0f;
+}
diff --git a/test/tint/builtins/gen/var/quantizeToF16/cba294.wgsl.expected.ir.glsl b/test/tint/builtins/gen/var/quantizeToF16/cba294.wgsl.expected.ir.glsl
index 2fe1fc2..0e765c1 100644
--- a/test/tint/builtins/gen/var/quantizeToF16/cba294.wgsl.expected.ir.glsl
+++ b/test/tint/builtins/gen/var/quantizeToF16/cba294.wgsl.expected.ir.glsl
@@ -1,11 +1,71 @@
-SKIP: FAILED
+#version 310 es
+precision highp float;
+precision highp int;
 
-<dawn>/src/tint/lang/glsl/writer/printer/printer.cc:1451 internal compiler error: TINT_UNREACHABLE unhandled core builtin: quantizeToF16
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+layout(binding = 0, std430)
+buffer tint_symbol_1_1_ssbo {
+  vec4 tint_symbol;
+} v;
+vec4 tint_quantize_to_f16(vec4 val) {
+  vec2 v_1 = unpackHalf2x16(packHalf2x16(val.xy));
+  return vec4(v_1, unpackHalf2x16(packHalf2x16(val.zw)));
+}
+vec4 quantizeToF16_cba294() {
+  vec4 arg_0 = vec4(1.0f);
+  vec4 res = tint_quantize_to_f16(arg_0);
+  return res;
+}
+void main() {
+  v.tint_symbol = quantizeToF16_cba294();
+}
+#version 310 es
 
-tint executable returned error: signal: trace/BPT trap
+layout(binding = 0, std430)
+buffer tint_symbol_1_1_ssbo {
+  vec4 tint_symbol;
+} v;
+vec4 tint_quantize_to_f16(vec4 val) {
+  vec2 v_1 = unpackHalf2x16(packHalf2x16(val.xy));
+  return vec4(v_1, unpackHalf2x16(packHalf2x16(val.zw)));
+}
+vec4 quantizeToF16_cba294() {
+  vec4 arg_0 = vec4(1.0f);
+  vec4 res = tint_quantize_to_f16(arg_0);
+  return res;
+}
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  v.tint_symbol = quantizeToF16_cba294();
+}
+#version 310 es
+
+
+struct VertexOutput {
+  vec4 pos;
+  vec4 prevent_dce;
+};
+
+layout(location = 0) flat out vec4 vertex_main_loc0_Output;
+vec4 tint_quantize_to_f16(vec4 val) {
+  vec2 v = unpackHalf2x16(packHalf2x16(val.xy));
+  return vec4(v, unpackHalf2x16(packHalf2x16(val.zw)));
+}
+vec4 quantizeToF16_cba294() {
+  vec4 arg_0 = vec4(1.0f);
+  vec4 res = tint_quantize_to_f16(arg_0);
+  return res;
+}
+VertexOutput vertex_main_inner() {
+  VertexOutput tint_symbol = VertexOutput(vec4(0.0f), vec4(0.0f));
+  tint_symbol.pos = vec4(0.0f);
+  tint_symbol.prevent_dce = quantizeToF16_cba294();
+  return tint_symbol;
+}
+void main() {
+  VertexOutput v_1 = vertex_main_inner();
+  gl_Position = v_1.pos;
+  gl_Position[1u] = -(gl_Position.y);
+  gl_Position[2u] = ((2.0f * gl_Position.z) - gl_Position.w);
+  vertex_main_loc0_Output = v_1.prevent_dce;
+  gl_PointSize = 1.0f;
+}
diff --git a/test/tint/builtins/gen/var/quantizeToF16/e8fd14.wgsl.expected.ir.glsl b/test/tint/builtins/gen/var/quantizeToF16/e8fd14.wgsl.expected.ir.glsl
index 2fe1fc2..616db0d 100644
--- a/test/tint/builtins/gen/var/quantizeToF16/e8fd14.wgsl.expected.ir.glsl
+++ b/test/tint/builtins/gen/var/quantizeToF16/e8fd14.wgsl.expected.ir.glsl
@@ -1,11 +1,71 @@
-SKIP: FAILED
+#version 310 es
+precision highp float;
+precision highp int;
 
-<dawn>/src/tint/lang/glsl/writer/printer/printer.cc:1451 internal compiler error: TINT_UNREACHABLE unhandled core builtin: quantizeToF16
-********************************************************************
-*  The tint shader compiler has encountered an unexpected error.   *
-*                                                                  *
-*  Please help us fix this issue by submitting a bug report at     *
-*  crbug.com/tint with the source program that triggered the bug.  *
-********************************************************************
+layout(binding = 0, std430)
+buffer tint_symbol_1_1_ssbo {
+  vec3 tint_symbol;
+} v;
+vec3 tint_quantize_to_f16(vec3 val) {
+  vec2 v_1 = unpackHalf2x16(packHalf2x16(val.xy));
+  return vec3(v_1, unpackHalf2x16(packHalf2x16(val.zz)).x);
+}
+vec3 quantizeToF16_e8fd14() {
+  vec3 arg_0 = vec3(1.0f);
+  vec3 res = tint_quantize_to_f16(arg_0);
+  return res;
+}
+void main() {
+  v.tint_symbol = quantizeToF16_e8fd14();
+}
+#version 310 es
 
-tint executable returned error: signal: trace/BPT trap
+layout(binding = 0, std430)
+buffer tint_symbol_1_1_ssbo {
+  vec3 tint_symbol;
+} v;
+vec3 tint_quantize_to_f16(vec3 val) {
+  vec2 v_1 = unpackHalf2x16(packHalf2x16(val.xy));
+  return vec3(v_1, unpackHalf2x16(packHalf2x16(val.zz)).x);
+}
+vec3 quantizeToF16_e8fd14() {
+  vec3 arg_0 = vec3(1.0f);
+  vec3 res = tint_quantize_to_f16(arg_0);
+  return res;
+}
+layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
+void main() {
+  v.tint_symbol = quantizeToF16_e8fd14();
+}
+#version 310 es
+
+
+struct VertexOutput {
+  vec4 pos;
+  vec3 prevent_dce;
+};
+
+layout(location = 0) flat out vec3 vertex_main_loc0_Output;
+vec3 tint_quantize_to_f16(vec3 val) {
+  vec2 v = unpackHalf2x16(packHalf2x16(val.xy));
+  return vec3(v, unpackHalf2x16(packHalf2x16(val.zz)).x);
+}
+vec3 quantizeToF16_e8fd14() {
+  vec3 arg_0 = vec3(1.0f);
+  vec3 res = tint_quantize_to_f16(arg_0);
+  return res;
+}
+VertexOutput vertex_main_inner() {
+  VertexOutput tint_symbol = VertexOutput(vec4(0.0f), vec3(0.0f));
+  tint_symbol.pos = vec4(0.0f);
+  tint_symbol.prevent_dce = quantizeToF16_e8fd14();
+  return tint_symbol;
+}
+void main() {
+  VertexOutput v_1 = vertex_main_inner();
+  gl_Position = v_1.pos;
+  gl_Position[1u] = -(gl_Position.y);
+  gl_Position[2u] = ((2.0f * gl_Position.z) - gl_Position.w);
+  vertex_main_loc0_Output = v_1.prevent_dce;
+  gl_PointSize = 1.0f;
+}