[hlsl] Convert bitcast to a transform.
This CL pulls the code out of the printer which supports bitcast and
moves it into a transform to generate the needed IR.
This adds custom intrinsics into the HLSL back to support the `asuint`,
`asint` and `asfloat` HLSL methods along with `f16tof32` and `f32tof16`.
Bug: 42251045, 348590924
Change-Id: I89465de1fd4171c89cbe4e5029ed9dedb0f803a0
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/195354
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: James Price <jrprice@google.com>
Auto-Submit: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/cmd/test/BUILD.bazel b/src/tint/cmd/test/BUILD.bazel
index cc3866d..1c6c48d 100644
--- a/src/tint/cmd/test/BUILD.bazel
+++ b/src/tint/cmd/test/BUILD.bazel
@@ -51,6 +51,7 @@
"//src/tint/lang/core/ir:test",
"//src/tint/lang/core/type:test",
"//src/tint/lang/core:test",
+ "//src/tint/lang/hlsl/ir:test",
"//src/tint/lang/hlsl/writer/common:test",
"//src/tint/lang/hlsl/writer/raise:test",
"//src/tint/lang/msl/ir:test",
diff --git a/src/tint/cmd/test/BUILD.cmake b/src/tint/cmd/test/BUILD.cmake
index 341bf6e..981ea88 100644
--- a/src/tint/cmd/test/BUILD.cmake
+++ b/src/tint/cmd/test/BUILD.cmake
@@ -52,6 +52,7 @@
tint_lang_core_ir_test
tint_lang_core_type_test
tint_lang_core_test
+ tint_lang_hlsl_ir_test
tint_lang_hlsl_writer_common_test
tint_lang_hlsl_writer_raise_test
tint_lang_msl_ir_test
diff --git a/src/tint/cmd/test/BUILD.gn b/src/tint/cmd/test/BUILD.gn
index ea2de9c..8a954fe 100644
--- a/src/tint/cmd/test/BUILD.gn
+++ b/src/tint/cmd/test/BUILD.gn
@@ -57,6 +57,7 @@
"${tint_src_dir}/lang/core/ir/transform:unittests",
"${tint_src_dir}/lang/core/ir/transform/common:unittests",
"${tint_src_dir}/lang/core/type:unittests",
+ "${tint_src_dir}/lang/hlsl/ir:unittests",
"${tint_src_dir}/lang/hlsl/writer/common:unittests",
"${tint_src_dir}/lang/hlsl/writer/raise:unittests",
"${tint_src_dir}/lang/msl/ir:unittests",
diff --git a/src/tint/lang/hlsl/BUILD.bazel b/src/tint/lang/hlsl/BUILD.bazel
index 1a114c6..5470814 100644
--- a/src/tint/lang/hlsl/BUILD.bazel
+++ b/src/tint/lang/hlsl/BUILD.bazel
@@ -36,4 +36,18 @@
load("//src/tint:flags.bzl", "COPTS")
load("@bazel_skylib//lib:selects.bzl", "selects")
+cc_library(
+ name = "hlsl",
+ srcs = [
+ "builtin_fn.cc",
+ ],
+ hdrs = [
+ "builtin_fn.h",
+ ],
+ deps = [
+ "//src/tint/utils/traits",
+ ],
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
diff --git a/src/tint/lang/hlsl/BUILD.cmake b/src/tint/lang/hlsl/BUILD.cmake
index 0257514..43d49fd 100644
--- a/src/tint/lang/hlsl/BUILD.cmake
+++ b/src/tint/lang/hlsl/BUILD.cmake
@@ -34,5 +34,20 @@
# Do not modify this file directly
################################################################################
+include(lang/hlsl/intrinsic/BUILD.cmake)
+include(lang/hlsl/ir/BUILD.cmake)
include(lang/hlsl/validate/BUILD.cmake)
include(lang/hlsl/writer/BUILD.cmake)
+
+################################################################################
+# Target: tint_lang_hlsl
+# Kind: lib
+################################################################################
+tint_add_target(tint_lang_hlsl lib
+ lang/hlsl/builtin_fn.cc
+ lang/hlsl/builtin_fn.h
+)
+
+tint_target_add_dependencies(tint_lang_hlsl lib
+ tint_utils_traits
+)
diff --git a/src/tint/lang/hlsl/BUILD.gn b/src/tint/lang/hlsl/BUILD.gn
index 6caa255..a5dc8b3 100644
--- a/src/tint/lang/hlsl/BUILD.gn
+++ b/src/tint/lang/hlsl/BUILD.gn
@@ -37,3 +37,11 @@
import("../../../../scripts/tint_overrides_with_defaults.gni")
import("${tint_src_dir}/tint.gni")
+
+libtint_source_set("hlsl") {
+ sources = [
+ "builtin_fn.cc",
+ "builtin_fn.h",
+ ]
+ deps = [ "${tint_src_dir}/utils/traits" ]
+}
diff --git a/src/tint/lang/hlsl/builtin_fn.cc b/src/tint/lang/hlsl/builtin_fn.cc
new file mode 100644
index 0000000..6a721ea
--- /dev/null
+++ b/src/tint/lang/hlsl/builtin_fn.cc
@@ -0,0 +1,59 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by 'tools/src/cmd/gen' using the template:
+// src/tint/lang/hlsl/builtin_fn.cc.tmpl
+//
+// To regenerate run: './tools/run gen'
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/lang/hlsl/builtin_fn.h"
+
+namespace tint::hlsl {
+
+const char* str(BuiltinFn i) {
+ switch (i) {
+ case BuiltinFn::kNone:
+ return "<none>";
+ case BuiltinFn::kAsint:
+ return "asint";
+ case BuiltinFn::kAsuint:
+ return "asuint";
+ case BuiltinFn::kAsfloat:
+ return "asfloat";
+ case BuiltinFn::kF32Tof16:
+ return "f32tof16";
+ case BuiltinFn::kF16Tof32:
+ return "f16tof32";
+ }
+ return "<unknown>";
+}
+
+} // namespace tint::hlsl
diff --git a/src/tint/lang/hlsl/builtin_fn.cc.tmpl b/src/tint/lang/hlsl/builtin_fn.cc.tmpl
new file mode 100644
index 0000000..0a81199
--- /dev/null
+++ b/src/tint/lang/hlsl/builtin_fn.cc.tmpl
@@ -0,0 +1,31 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate builtin_fn.cc
+
+To update the generated file, run:
+ ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- $I := LoadIntrinsics "src/tint/lang/hlsl/hlsl.def" -}}
+#include "src/tint/lang/hlsl/builtin_fn.h"
+
+namespace tint::hlsl {
+
+const char* str(BuiltinFn i) {
+ switch (i) {
+ case BuiltinFn::kNone:
+ return "<none>";
+{{- range $I.Sem.Builtins }}
+ case BuiltinFn::k{{PascalCase .Name}}:
+ return "{{.Name}}";
+{{- end }}
+ }
+ return "<unknown>";
+}
+
+} // namespace tint::hlsl
diff --git a/src/tint/lang/hlsl/builtin_fn.h b/src/tint/lang/hlsl/builtin_fn.h
new file mode 100644
index 0000000..1071021
--- /dev/null
+++ b/src/tint/lang/hlsl/builtin_fn.h
@@ -0,0 +1,70 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by 'tools/src/cmd/gen' using the template:
+// src/tint/lang/hlsl/builtin_fn.h.tmpl
+//
+// To regenerate run: './tools/run gen'
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_TINT_LANG_HLSL_BUILTIN_FN_H_
+#define SRC_TINT_LANG_HLSL_BUILTIN_FN_H_
+
+#include <cstdint>
+#include <string>
+
+#include "src/tint/utils/traits/traits.h"
+
+// \cond DO_NOT_DOCUMENT
+namespace tint::hlsl {
+
+/// Enumerator of all builtin functions
+enum class BuiltinFn : uint8_t {
+ kAsint,
+ kAsuint,
+ kAsfloat,
+ kF32Tof16,
+ kF16Tof32,
+ kNone,
+};
+
+/// @returns the name of the builtin function type.
+const char* str(BuiltinFn i);
+
+/// Emits the name of the builtin function type.
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& o, BuiltinFn i) {
+ return o << str(i);
+}
+
+} // namespace tint::hlsl
+// \endcond
+
+#endif // SRC_TINT_LANG_HLSL_BUILTIN_FN_H_
diff --git a/src/tint/lang/hlsl/builtin_fn.h.tmpl b/src/tint/lang/hlsl/builtin_fn.h.tmpl
new file mode 100644
index 0000000..566bd9b
--- /dev/null
+++ b/src/tint/lang/hlsl/builtin_fn.h.tmpl
@@ -0,0 +1,47 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate builtin_fn.h
+
+To update the generated file, run:
+ ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- $I := LoadIntrinsics "src/tint/lang/hlsl/hlsl.def" -}}
+
+#ifndef SRC_TINT_LANG_HLSL_BUILTIN_FN_H_
+#define SRC_TINT_LANG_HLSL_BUILTIN_FN_H_
+
+#include <cstdint>
+#include <string>
+
+#include "src/tint/utils/traits/traits.h"
+
+// \cond DO_NOT_DOCUMENT
+namespace tint::hlsl {
+
+/// Enumerator of all builtin functions
+enum class BuiltinFn : uint8_t {
+{{- range $I.Sem.Builtins }}
+ k{{PascalCase .Name}},
+{{- end }}
+ kNone,
+};
+
+/// @returns the name of the builtin function type.
+const char* str(BuiltinFn i);
+
+/// Emits the name of the builtin function type.
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& o, BuiltinFn i) {
+ return o << str(i);
+}
+
+} // namespace tint::hlsl
+// \endcond
+
+#endif // SRC_TINT_LANG_HLSL_BUILTIN_FN_H_
diff --git a/src/tint/lang/hlsl/hlsl.def b/src/tint/lang/hlsl/hlsl.def
new file mode 100644
index 0000000..6eab53a
--- /dev/null
+++ b/src/tint/lang/hlsl/hlsl.def
@@ -0,0 +1,73 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+////////////////////////////////////////////////////////////////////////////////
+// HLSL builtin definition file //
+// //
+// After modifying this file, run: //
+// tools/run gen //
+// from the Dawn source directory. //
+// //
+// See docs/tint/intrinsic_definition_files.md for syntax //
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Types //
+////////////////////////////////////////////////////////////////////////////////
+
+type i32
+type u32
+type f32
+type f16
+type vec2<T>
+@display("vec{N}<{T}>") type vec<N: num, T>
+
+////////////////////////////////////////////////////////////////////////////////
+// Type matchers //
+////////////////////////////////////////////////////////////////////////////////
+
+match iu32: i32 | u32
+match f32_u32: f32 | u32
+match f32_i32: f32 | i32
+
+////////////////////////////////////////////////////////////////////////////////
+// Builtin Functions //
+////////////////////////////////////////////////////////////////////////////////
+fn asint[T: f32_u32](T) -> i32
+fn asint[T: f32_u32, N: num](vec<N, T>) -> vec<N, i32>
+
+fn asuint[T: f32_i32](T) -> u32
+fn asuint[T: f32_i32, N: num](vec<N, T>) -> vec<N, u32>
+
+fn asfloat[T: iu32](T) -> f32
+fn asfloat[T: iu32, N: num](vec<N, T>) -> vec<N, f32>
+
+fn f32tof16(f32) -> u32
+fn f32tof16[N: num](vec<N, f32>) -> vec<N, u32>
+
+fn f16tof32(u32) -> f32
+fn f16tof32[N: num](vec<N, u32>) -> vec<N, f32>
diff --git a/src/tint/lang/hlsl/intrinsic/BUILD.bazel b/src/tint/lang/hlsl/intrinsic/BUILD.bazel
new file mode 100644
index 0000000..d26a7e8
--- /dev/null
+++ b/src/tint/lang/hlsl/intrinsic/BUILD.bazel
@@ -0,0 +1,70 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.bazel.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+load("//src/tint:flags.bzl", "COPTS")
+load("@bazel_skylib//lib:selects.bzl", "selects")
+cc_library(
+ name = "intrinsic",
+ srcs = [
+ "data.cc",
+ ],
+ hdrs = [
+ "dialect.h",
+ ],
+ deps = [
+ "//src/tint/lang/core",
+ "//src/tint/lang/core/constant",
+ "//src/tint/lang/core/intrinsic",
+ "//src/tint/lang/core/type",
+ "//src/tint/lang/hlsl",
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/id",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/reflection",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/symbol",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ ],
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+
diff --git a/src/tint/lang/hlsl/intrinsic/BUILD.cmake b/src/tint/lang/hlsl/intrinsic/BUILD.cmake
new file mode 100644
index 0000000..da93e6a
--- /dev/null
+++ b/src/tint/lang/hlsl/intrinsic/BUILD.cmake
@@ -0,0 +1,65 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.cmake.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+################################################################################
+# Target: tint_lang_hlsl_intrinsic
+# Kind: lib
+################################################################################
+tint_add_target(tint_lang_hlsl_intrinsic lib
+ lang/hlsl/intrinsic/data.cc
+ lang/hlsl/intrinsic/dialect.h
+)
+
+tint_target_add_dependencies(tint_lang_hlsl_intrinsic lib
+ tint_lang_core
+ tint_lang_core_constant
+ tint_lang_core_intrinsic
+ tint_lang_core_type
+ tint_lang_hlsl
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_id
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_reflection
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_symbol
+ tint_utils_text
+ tint_utils_traits
+)
diff --git a/src/tint/lang/hlsl/intrinsic/BUILD.gn b/src/tint/lang/hlsl/intrinsic/BUILD.gn
new file mode 100644
index 0000000..6f36df6
--- /dev/null
+++ b/src/tint/lang/hlsl/intrinsic/BUILD.gn
@@ -0,0 +1,66 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.gn.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+import("../../../../../scripts/tint_overrides_with_defaults.gni")
+
+import("${tint_src_dir}/tint.gni")
+
+libtint_source_set("intrinsic") {
+ sources = [
+ "data.cc",
+ "dialect.h",
+ ]
+ deps = [
+ "${tint_src_dir}/lang/core",
+ "${tint_src_dir}/lang/core/constant",
+ "${tint_src_dir}/lang/core/intrinsic",
+ "${tint_src_dir}/lang/core/type",
+ "${tint_src_dir}/lang/hlsl",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/id",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/symbol",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+}
diff --git a/src/tint/lang/hlsl/intrinsic/data.cc b/src/tint/lang/hlsl/intrinsic/data.cc
new file mode 100644
index 0000000..e15f8d5
--- /dev/null
+++ b/src/tint/lang/hlsl/intrinsic/data.cc
@@ -0,0 +1,551 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by 'tools/src/cmd/gen' using the template:
+// src/tint/lang/hlsl/intrinsic/data.cc.tmpl
+//
+// To regenerate run: './tools/run gen'
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include <limits>
+#include <string>
+
+#include "src/tint/lang/core/intrinsic/type_matchers.h"
+#include "src/tint/lang/hlsl/intrinsic/dialect.h"
+#include "src/tint/utils/text/string_stream.h"
+
+namespace tint::hlsl::intrinsic {
+
+using namespace tint::core::intrinsic; // NOLINT(build/namespaces)
+
+namespace {
+
+using ConstEvalFunctionIndex = tint::core::intrinsic::ConstEvalFunctionIndex;
+using IntrinsicInfo = tint::core::intrinsic::IntrinsicInfo;
+using MatcherIndicesIndex = tint::core::intrinsic::MatcherIndicesIndex;
+using MatchState = tint::core::intrinsic::MatchState;
+using Number = tint::core::intrinsic::Number;
+using NumberMatcher = tint::core::intrinsic::NumberMatcher;
+using NumberMatcherIndex = tint::core::intrinsic::NumberMatcherIndex;
+using OverloadFlag = tint::core::intrinsic::OverloadFlag;
+using OverloadFlags = tint::core::intrinsic::OverloadFlags;
+using OverloadIndex = tint::core::intrinsic::OverloadIndex;
+using OverloadInfo = tint::core::intrinsic::OverloadInfo;
+using ParameterIndex = tint::core::intrinsic::ParameterIndex;
+using ParameterInfo = tint::core::intrinsic::ParameterInfo;
+using StringStream = tint::StringStream;
+using TemplateIndex = tint::core::intrinsic::TemplateIndex;
+using Type = tint::core::type::Type;
+using TypeMatcher = tint::core::intrinsic::TypeMatcher;
+using TypeMatcherIndex = tint::core::intrinsic::TypeMatcherIndex;
+
+template <size_t N>
+using TemplateNumberMatcher = tint::core::intrinsic::TemplateNumberMatcher<N>;
+
+template <size_t N>
+using TemplateTypeMatcher = tint::core::intrinsic::TemplateTypeMatcher<N>;
+
+// clang-format off
+
+/// TypeMatcher for 'type i32'
+constexpr TypeMatcher kI32Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+ if (!MatchI32(state, ty)) {
+ return nullptr;
+ }
+ return BuildI32(state, ty);
+ },
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type("i32");
+ }
+};
+
+
+/// TypeMatcher for 'type u32'
+constexpr TypeMatcher kU32Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+ if (!MatchU32(state, ty)) {
+ return nullptr;
+ }
+ return BuildU32(state, ty);
+ },
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type("u32");
+ }
+};
+
+
+/// TypeMatcher for 'type f32'
+constexpr TypeMatcher kF32Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+ if (!MatchF32(state, ty)) {
+ return nullptr;
+ }
+ return BuildF32(state, ty);
+ },
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type("f32");
+ }
+};
+
+
+/// TypeMatcher for 'type f16'
+constexpr TypeMatcher kF16Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+ if (!MatchF16(state, ty)) {
+ return nullptr;
+ }
+ return BuildF16(state, ty);
+ },
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+ out << style::Type("f16");
+ }
+};
+
+
+/// TypeMatcher for 'type vec2'
+constexpr TypeMatcher kVec2Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+ const Type* T = nullptr;
+ if (!MatchVec2(state, ty, T)) {
+ return nullptr;
+ }
+ T = state.Type(T);
+ if (T == nullptr) {
+ return nullptr;
+ }
+ return BuildVec2(state, ty, T);
+ },
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText T;
+ state->PrintType(T);
+ out << style::Type("vec2", "<", T, ">");
+ }
+};
+
+
+/// TypeMatcher for 'type vec'
+constexpr TypeMatcher kVecMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+ Number N = Number::invalid;
+ const Type* T = nullptr;
+ if (!MatchVec(state, ty, N, T)) {
+ return nullptr;
+ }
+ N = state.Num(N);
+ if (!N.IsValid()) {
+ return nullptr;
+ }
+ T = state.Type(T);
+ if (T == nullptr) {
+ return nullptr;
+ }
+ return BuildVec(state, ty, N, T);
+ },
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {StyledText N;
+ state->PrintNum(N);StyledText T;
+ state->PrintType(T);
+ out << style::Type("vec", N, "<", T, ">");
+ }
+};
+
+
+/// TypeMatcher for 'match iu32'
+constexpr TypeMatcher kIu32Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+ if (MatchI32(state, ty)) {
+ return BuildI32(state, ty);
+ }
+ if (MatchU32(state, ty)) {
+ return BuildU32(state, ty);
+ }
+ return nullptr;
+ },
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
+ // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+ kI32Matcher.print(nullptr, out); out << style::Plain(" or "); kU32Matcher.print(nullptr, out);}
+};
+
+/// TypeMatcher for 'match f32_u32'
+constexpr TypeMatcher kF32U32Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+ if (MatchF32(state, ty)) {
+ return BuildF32(state, ty);
+ }
+ if (MatchU32(state, ty)) {
+ return BuildU32(state, ty);
+ }
+ return nullptr;
+ },
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
+ // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+ kF32Matcher.print(nullptr, out); out << style::Plain(" or "); kU32Matcher.print(nullptr, out);}
+};
+
+/// TypeMatcher for 'match f32_i32'
+constexpr TypeMatcher kF32I32Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+ if (MatchF32(state, ty)) {
+ return BuildF32(state, ty);
+ }
+ if (MatchI32(state, ty)) {
+ return BuildI32(state, ty);
+ }
+ return nullptr;
+ },
+/* print */ [](MatchState*, StyledText& out) {
+ // Note: We pass nullptr to the Matcher.print() functions, as matchers do not support
+ // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+ kF32Matcher.print(nullptr, out); out << style::Plain(" or "); kI32Matcher.print(nullptr, out);}
+};
+
+/// Type and number matchers
+
+/// The template types, types, and type matchers
+constexpr TypeMatcher kTypeMatchers[] = {
+ /* [0] */ TemplateTypeMatcher<0>::matcher,
+ /* [1] */ TemplateTypeMatcher<1>::matcher,
+ /* [2] */ kI32Matcher,
+ /* [3] */ kU32Matcher,
+ /* [4] */ kF32Matcher,
+ /* [5] */ kF16Matcher,
+ /* [6] */ kVec2Matcher,
+ /* [7] */ kVecMatcher,
+ /* [8] */ kIu32Matcher,
+ /* [9] */ kF32U32Matcher,
+ /* [10] */ kF32I32Matcher,
+};
+
+/// The template numbers, and number matchers
+constexpr NumberMatcher kNumberMatchers[] = {
+ /* [0] */ TemplateNumberMatcher<0>::matcher,
+ /* [1] */ TemplateNumberMatcher<1>::matcher,
+};
+
+constexpr MatcherIndex kMatcherIndices[] = {
+ /* [0] */ MatcherIndex(7),
+ /* [1] */ MatcherIndex(1),
+ /* [2] */ MatcherIndex(2),
+ /* [3] */ MatcherIndex(7),
+ /* [4] */ MatcherIndex(1),
+ /* [5] */ MatcherIndex(0),
+ /* [6] */ MatcherIndex(7),
+ /* [7] */ MatcherIndex(1),
+ /* [8] */ MatcherIndex(3),
+ /* [9] */ MatcherIndex(7),
+ /* [10] */ MatcherIndex(1),
+ /* [11] */ MatcherIndex(4),
+ /* [12] */ MatcherIndex(7),
+ /* [13] */ MatcherIndex(0),
+ /* [14] */ MatcherIndex(3),
+ /* [15] */ MatcherIndex(7),
+ /* [16] */ MatcherIndex(0),
+ /* [17] */ MatcherIndex(4),
+ /* [18] */ MatcherIndex(9),
+ /* [19] */ MatcherIndex(10),
+ /* [20] */ MatcherIndex(8),
+};
+
+static_assert(MatcherIndicesIndex::CanIndex(kMatcherIndices),
+ "MatcherIndicesIndex is not large enough to index kMatcherIndices");
+
+constexpr ParameterInfo kParameters[] = {
+ {
+ /* [0] */
+ /* usage */ core::ParameterUsage::kNone,
+ /* matcher_indices */ MatcherIndicesIndex(5),
+ },
+ {
+ /* [1] */
+ /* usage */ core::ParameterUsage::kNone,
+ /* matcher_indices */ MatcherIndicesIndex(3),
+ },
+ {
+ /* [2] */
+ /* usage */ core::ParameterUsage::kNone,
+ /* matcher_indices */ MatcherIndicesIndex(11),
+ },
+ {
+ /* [3] */
+ /* usage */ core::ParameterUsage::kNone,
+ /* matcher_indices */ MatcherIndicesIndex(15),
+ },
+ {
+ /* [4] */
+ /* usage */ core::ParameterUsage::kNone,
+ /* matcher_indices */ MatcherIndicesIndex(8),
+ },
+ {
+ /* [5] */
+ /* usage */ core::ParameterUsage::kNone,
+ /* matcher_indices */ MatcherIndicesIndex(12),
+ },
+};
+
+static_assert(ParameterIndex::CanIndex(kParameters),
+ "ParameterIndex is not large enough to index kParameters");
+
+constexpr TemplateInfo kTemplates[] = {
+ {
+ /* [0] */
+ /* name */ "T",
+ /* matcher_indices */ MatcherIndicesIndex(18),
+ /* kind */ TemplateInfo::Kind::kType,
+ },
+ {
+ /* [1] */
+ /* name */ "N",
+ /* matcher_indices */ MatcherIndicesIndex(/* invalid */),
+ /* kind */ TemplateInfo::Kind::kNumber,
+ },
+ {
+ /* [2] */
+ /* name */ "T",
+ /* matcher_indices */ MatcherIndicesIndex(19),
+ /* kind */ TemplateInfo::Kind::kType,
+ },
+ {
+ /* [3] */
+ /* name */ "N",
+ /* matcher_indices */ MatcherIndicesIndex(/* invalid */),
+ /* kind */ TemplateInfo::Kind::kNumber,
+ },
+ {
+ /* [4] */
+ /* name */ "T",
+ /* matcher_indices */ MatcherIndicesIndex(20),
+ /* kind */ TemplateInfo::Kind::kType,
+ },
+ {
+ /* [5] */
+ /* name */ "N",
+ /* matcher_indices */ MatcherIndicesIndex(/* invalid */),
+ /* kind */ TemplateInfo::Kind::kNumber,
+ },
+};
+
+static_assert(TemplateIndex::CanIndex(kTemplates),
+ "TemplateIndex is not large enough to index kTemplates");
+
+constexpr OverloadInfo kOverloads[] = {
+ {
+ /* [0] */
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num_parameters */ 1,
+ /* num_explicit_templates */ 0,
+ /* num_templates */ 1,
+ /* templates */ TemplateIndex(0),
+ /* parameters */ ParameterIndex(0),
+ /* return_matcher_indices */ MatcherIndicesIndex(2),
+ /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+ },
+ {
+ /* [1] */
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num_parameters */ 1,
+ /* num_explicit_templates */ 0,
+ /* num_templates */ 2,
+ /* templates */ TemplateIndex(0),
+ /* parameters */ ParameterIndex(1),
+ /* return_matcher_indices */ MatcherIndicesIndex(0),
+ /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+ },
+ {
+ /* [2] */
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num_parameters */ 1,
+ /* num_explicit_templates */ 0,
+ /* num_templates */ 1,
+ /* templates */ TemplateIndex(2),
+ /* parameters */ ParameterIndex(0),
+ /* return_matcher_indices */ MatcherIndicesIndex(8),
+ /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+ },
+ {
+ /* [3] */
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num_parameters */ 1,
+ /* num_explicit_templates */ 0,
+ /* num_templates */ 2,
+ /* templates */ TemplateIndex(2),
+ /* parameters */ ParameterIndex(1),
+ /* return_matcher_indices */ MatcherIndicesIndex(6),
+ /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+ },
+ {
+ /* [4] */
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num_parameters */ 1,
+ /* num_explicit_templates */ 0,
+ /* num_templates */ 1,
+ /* templates */ TemplateIndex(4),
+ /* parameters */ ParameterIndex(0),
+ /* return_matcher_indices */ MatcherIndicesIndex(11),
+ /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+ },
+ {
+ /* [5] */
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num_parameters */ 1,
+ /* num_explicit_templates */ 0,
+ /* num_templates */ 2,
+ /* templates */ TemplateIndex(4),
+ /* parameters */ ParameterIndex(1),
+ /* return_matcher_indices */ MatcherIndicesIndex(9),
+ /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+ },
+ {
+ /* [6] */
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num_parameters */ 1,
+ /* num_explicit_templates */ 0,
+ /* num_templates */ 0,
+ /* templates */ TemplateIndex(/* invalid */),
+ /* parameters */ ParameterIndex(2),
+ /* return_matcher_indices */ MatcherIndicesIndex(8),
+ /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+ },
+ {
+ /* [7] */
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num_parameters */ 1,
+ /* num_explicit_templates */ 0,
+ /* num_templates */ 1,
+ /* templates */ TemplateIndex(1),
+ /* parameters */ ParameterIndex(3),
+ /* return_matcher_indices */ MatcherIndicesIndex(12),
+ /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+ },
+ {
+ /* [8] */
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num_parameters */ 1,
+ /* num_explicit_templates */ 0,
+ /* num_templates */ 0,
+ /* templates */ TemplateIndex(/* invalid */),
+ /* parameters */ ParameterIndex(4),
+ /* return_matcher_indices */ MatcherIndicesIndex(11),
+ /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+ },
+ {
+ /* [9] */
+ /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+ /* num_parameters */ 1,
+ /* num_explicit_templates */ 0,
+ /* num_templates */ 1,
+ /* templates */ TemplateIndex(1),
+ /* parameters */ ParameterIndex(5),
+ /* return_matcher_indices */ MatcherIndicesIndex(15),
+ /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+ },
+};
+
+static_assert(OverloadIndex::CanIndex(kOverloads),
+ "OverloadIndex is not large enough to index kOverloads");
+
+constexpr IntrinsicInfo kBuiltins[] = {
+ {
+ /* [0] */
+ /* fn asint[T : f32_u32](T) -> i32 */
+ /* fn asint[T : f32_u32, N : num](vec<N, T>) -> vec<N, i32> */
+ /* num overloads */ 2,
+ /* overloads */ OverloadIndex(0),
+ },
+ {
+ /* [1] */
+ /* fn asuint[T : f32_i32](T) -> u32 */
+ /* fn asuint[T : f32_i32, N : num](vec<N, T>) -> vec<N, u32> */
+ /* num overloads */ 2,
+ /* overloads */ OverloadIndex(2),
+ },
+ {
+ /* [2] */
+ /* fn asfloat[T : iu32](T) -> f32 */
+ /* fn asfloat[T : iu32, N : num](vec<N, T>) -> vec<N, f32> */
+ /* num overloads */ 2,
+ /* overloads */ OverloadIndex(4),
+ },
+ {
+ /* [3] */
+ /* fn f32tof16(f32) -> u32 */
+ /* fn f32tof16[N : num](vec<N, f32>) -> vec<N, u32> */
+ /* num overloads */ 2,
+ /* overloads */ OverloadIndex(6),
+ },
+ {
+ /* [4] */
+ /* fn f16tof32(u32) -> f32 */
+ /* fn f16tof32[N : num](vec<N, u32>) -> vec<N, f32> */
+ /* num overloads */ 2,
+ /* overloads */ OverloadIndex(8),
+ },
+};
+
+// clang-format on
+
+} // anonymous namespace
+
+const core::intrinsic::TableData Dialect::kData{
+ /* templates */ kTemplates,
+ /* type_matcher_indices */ kMatcherIndices,
+ /* type_matchers */ kTypeMatchers,
+ /* number_matchers */ kNumberMatchers,
+ /* parameters */ kParameters,
+ /* overloads */ kOverloads,
+ /* const_eval_functions */ Empty,
+ /* ctor_conv */ Empty,
+ /* builtins */ kBuiltins,
+ /* binary '+' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '-' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '*' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '/' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '%' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '^' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '&' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '|' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '&&' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '||' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '==' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '!=' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '<' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '>' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '<=' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '>=' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '<<' */ tint::core::intrinsic::kNoOverloads,
+ /* binary '>>' */ tint::core::intrinsic::kNoOverloads,
+ /* unary '!' */ tint::core::intrinsic::kNoOverloads,
+ /* unary '~' */ tint::core::intrinsic::kNoOverloads,
+ /* unary '-' */ tint::core::intrinsic::kNoOverloads,
+ /* unary '*' */ tint::core::intrinsic::kNoOverloads,
+ /* unary '&' */ tint::core::intrinsic::kNoOverloads,
+};
+
+} // namespace tint::hlsl::intrinsic
diff --git a/src/tint/lang/hlsl/intrinsic/data.cc.tmpl b/src/tint/lang/hlsl/intrinsic/data.cc.tmpl
new file mode 100644
index 0000000..68d95c1
--- /dev/null
+++ b/src/tint/lang/hlsl/intrinsic/data.cc.tmpl
@@ -0,0 +1,34 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate intrinsic_table.inl
+Used by BuiltinTable.cc for builtin overload resolution.
+
+To update the generated file, run:
+ ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/utils/templates/intrinsic_table_data.tmpl.inc" -}}
+
+{{- $I := LoadIntrinsics "src/tint/lang/hlsl/hlsl.def" -}}
+
+#include <limits>
+#include <string>
+
+#include "src/tint/lang/core/intrinsic/type_matchers.h"
+#include "src/tint/lang/hlsl/intrinsic/dialect.h"
+#include "src/tint/utils/text/string_stream.h"
+
+namespace tint::hlsl::intrinsic {
+
+using namespace tint::core::intrinsic; // NOLINT(build/namespaces)
+
+{{ Eval "Data"
+ "Intrinsics" $I
+ "Name" "Dialect::kData" -}}
+
+} // namespace tint::hlsl::intrinsic
diff --git a/src/tint/lang/hlsl/intrinsic/dialect.h b/src/tint/lang/hlsl/intrinsic/dialect.h
new file mode 100644
index 0000000..d647f46
--- /dev/null
+++ b/src/tint/lang/hlsl/intrinsic/dialect.h
@@ -0,0 +1,51 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_HLSL_INTRINSIC_DIALECT_H_
+#define SRC_TINT_LANG_HLSL_INTRINSIC_DIALECT_H_
+
+#include "src/tint/lang/core/intrinsic/table_data.h"
+#include "src/tint/lang/hlsl/builtin_fn.h"
+
+namespace tint::hlsl::intrinsic {
+
+/// Dialect holds the intrinsic table data and types for the HLSL dialect
+struct Dialect {
+ /// The dialect's intrinsic table data
+ static const core::intrinsic::TableData kData;
+
+ /// The dialect's builtin function enumerator
+ using BuiltinFn = hlsl::BuiltinFn;
+
+ /// @returns the name of the builtin function @p fn
+ /// @param fn the builtin function
+ static std::string_view ToString(BuiltinFn fn) { return str(fn); }
+};
+
+} // namespace tint::hlsl::intrinsic
+
+#endif // SRC_TINT_LANG_HLSL_INTRINSIC_DIALECT_H_
diff --git a/src/tint/lang/hlsl/ir/BUILD.bazel b/src/tint/lang/hlsl/ir/BUILD.bazel
new file mode 100644
index 0000000..758aef2
--- /dev/null
+++ b/src/tint/lang/hlsl/ir/BUILD.bazel
@@ -0,0 +1,108 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.bazel.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+load("//src/tint:flags.bzl", "COPTS")
+load("@bazel_skylib//lib:selects.bzl", "selects")
+cc_library(
+ name = "ir",
+ srcs = [
+ "builtin_call.cc",
+ ],
+ hdrs = [
+ "builtin_call.h",
+ ],
+ deps = [
+ "//src/tint/api/common",
+ "//src/tint/lang/core",
+ "//src/tint/lang/core/constant",
+ "//src/tint/lang/core/intrinsic",
+ "//src/tint/lang/core/ir",
+ "//src/tint/lang/core/type",
+ "//src/tint/lang/hlsl",
+ "//src/tint/lang/hlsl/intrinsic",
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/id",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/reflection",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/symbol",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ ],
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+cc_library(
+ name = "test",
+ alwayslink = True,
+ srcs = [
+ "builtin_call_test.cc",
+ ],
+ deps = [
+ "//src/tint/api/common",
+ "//src/tint/lang/core",
+ "//src/tint/lang/core/constant",
+ "//src/tint/lang/core/intrinsic",
+ "//src/tint/lang/core/ir",
+ "//src/tint/lang/core/ir:test",
+ "//src/tint/lang/core/type",
+ "//src/tint/lang/hlsl",
+ "//src/tint/lang/hlsl/intrinsic",
+ "//src/tint/lang/hlsl/ir",
+ "//src/tint/utils/containers",
+ "//src/tint/utils/diagnostic",
+ "//src/tint/utils/ice",
+ "//src/tint/utils/id",
+ "//src/tint/utils/macros",
+ "//src/tint/utils/math",
+ "//src/tint/utils/memory",
+ "//src/tint/utils/reflection",
+ "//src/tint/utils/result",
+ "//src/tint/utils/rtti",
+ "//src/tint/utils/symbol",
+ "//src/tint/utils/text",
+ "//src/tint/utils/traits",
+ "@gtest",
+ ],
+ copts = COPTS,
+ visibility = ["//visibility:public"],
+)
+
diff --git a/src/tint/lang/hlsl/ir/BUILD.cmake b/src/tint/lang/hlsl/ir/BUILD.cmake
new file mode 100644
index 0000000..c94d5f4
--- /dev/null
+++ b/src/tint/lang/hlsl/ir/BUILD.cmake
@@ -0,0 +1,106 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.cmake.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+################################################################################
+# Target: tint_lang_hlsl_ir
+# Kind: lib
+################################################################################
+tint_add_target(tint_lang_hlsl_ir lib
+ lang/hlsl/ir/builtin_call.cc
+ lang/hlsl/ir/builtin_call.h
+)
+
+tint_target_add_dependencies(tint_lang_hlsl_ir lib
+ tint_api_common
+ tint_lang_core
+ tint_lang_core_constant
+ tint_lang_core_intrinsic
+ tint_lang_core_ir
+ tint_lang_core_type
+ tint_lang_hlsl
+ tint_lang_hlsl_intrinsic
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_id
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_reflection
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_symbol
+ tint_utils_text
+ tint_utils_traits
+)
+
+################################################################################
+# Target: tint_lang_hlsl_ir_test
+# Kind: test
+################################################################################
+tint_add_target(tint_lang_hlsl_ir_test test
+ lang/hlsl/ir/builtin_call_test.cc
+)
+
+tint_target_add_dependencies(tint_lang_hlsl_ir_test test
+ tint_api_common
+ tint_lang_core
+ tint_lang_core_constant
+ tint_lang_core_intrinsic
+ tint_lang_core_ir
+ tint_lang_core_ir_test
+ tint_lang_core_type
+ tint_lang_hlsl
+ tint_lang_hlsl_intrinsic
+ tint_lang_hlsl_ir
+ tint_utils_containers
+ tint_utils_diagnostic
+ tint_utils_ice
+ tint_utils_id
+ tint_utils_macros
+ tint_utils_math
+ tint_utils_memory
+ tint_utils_reflection
+ tint_utils_result
+ tint_utils_rtti
+ tint_utils_symbol
+ tint_utils_text
+ tint_utils_traits
+)
+
+tint_target_add_external_dependencies(tint_lang_hlsl_ir_test test
+ "gtest"
+)
diff --git a/src/tint/lang/hlsl/ir/BUILD.gn b/src/tint/lang/hlsl/ir/BUILD.gn
new file mode 100644
index 0000000..2cb3e39
--- /dev/null
+++ b/src/tint/lang/hlsl/ir/BUILD.gn
@@ -0,0 +1,104 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+# tools/src/cmd/gen/build/BUILD.gn.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+# Do not modify this file directly
+################################################################################
+
+import("../../../../../scripts/tint_overrides_with_defaults.gni")
+
+import("${tint_src_dir}/tint.gni")
+
+if (tint_build_unittests || tint_build_benchmarks) {
+ import("//testing/test.gni")
+}
+
+libtint_source_set("ir") {
+ sources = [
+ "builtin_call.cc",
+ "builtin_call.h",
+ ]
+ deps = [
+ "${tint_src_dir}/api/common",
+ "${tint_src_dir}/lang/core",
+ "${tint_src_dir}/lang/core/constant",
+ "${tint_src_dir}/lang/core/intrinsic",
+ "${tint_src_dir}/lang/core/ir",
+ "${tint_src_dir}/lang/core/type",
+ "${tint_src_dir}/lang/hlsl",
+ "${tint_src_dir}/lang/hlsl/intrinsic",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/id",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/symbol",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+}
+if (tint_build_unittests) {
+ tint_unittests_source_set("unittests") {
+ sources = [ "builtin_call_test.cc" ]
+ deps = [
+ "${tint_src_dir}:gmock_and_gtest",
+ "${tint_src_dir}/api/common",
+ "${tint_src_dir}/lang/core",
+ "${tint_src_dir}/lang/core/constant",
+ "${tint_src_dir}/lang/core/intrinsic",
+ "${tint_src_dir}/lang/core/ir",
+ "${tint_src_dir}/lang/core/ir:unittests",
+ "${tint_src_dir}/lang/core/type",
+ "${tint_src_dir}/lang/hlsl",
+ "${tint_src_dir}/lang/hlsl/intrinsic",
+ "${tint_src_dir}/lang/hlsl/ir",
+ "${tint_src_dir}/utils/containers",
+ "${tint_src_dir}/utils/diagnostic",
+ "${tint_src_dir}/utils/ice",
+ "${tint_src_dir}/utils/id",
+ "${tint_src_dir}/utils/macros",
+ "${tint_src_dir}/utils/math",
+ "${tint_src_dir}/utils/memory",
+ "${tint_src_dir}/utils/reflection",
+ "${tint_src_dir}/utils/result",
+ "${tint_src_dir}/utils/rtti",
+ "${tint_src_dir}/utils/symbol",
+ "${tint_src_dir}/utils/text",
+ "${tint_src_dir}/utils/traits",
+ ]
+ }
+}
diff --git a/src/tint/lang/hlsl/ir/builtin_call.cc b/src/tint/lang/hlsl/ir/builtin_call.cc
new file mode 100644
index 0000000..2101f71
--- /dev/null
+++ b/src/tint/lang/hlsl/ir/builtin_call.cc
@@ -0,0 +1,56 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/hlsl/ir/builtin_call.h"
+
+#include <utility>
+
+#include "src/tint/lang/core/ir/clone_context.h"
+#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/utils/ice/ice.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::hlsl::ir::BuiltinCall);
+
+namespace tint::hlsl::ir {
+
+BuiltinCall::BuiltinCall(core::ir::InstructionResult* result,
+ BuiltinFn func,
+ VectorRef<core::ir::Value*> arguments)
+ : Base(result, arguments), func_(func) {
+ flags_.Add(Flag::kSequenced);
+ TINT_ASSERT(func != BuiltinFn::kNone);
+}
+
+BuiltinCall::~BuiltinCall() = default;
+
+BuiltinCall* BuiltinCall::Clone(core::ir::CloneContext& ctx) {
+ auto* new_result = ctx.Clone(Result(0));
+ auto new_args = ctx.Clone<BuiltinCall::kDefaultNumOperands>(Args());
+ return ctx.ir.allocators.instructions.Create<BuiltinCall>(new_result, func_, new_args);
+}
+
+} // namespace tint::hlsl::ir
diff --git a/src/tint/lang/hlsl/ir/builtin_call.h b/src/tint/lang/hlsl/ir/builtin_call.h
new file mode 100644
index 0000000..9416c5b
--- /dev/null
+++ b/src/tint/lang/hlsl/ir/builtin_call.h
@@ -0,0 +1,76 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_HLSL_IR_BUILTIN_CALL_H_
+#define SRC_TINT_LANG_HLSL_IR_BUILTIN_CALL_H_
+
+#include <string>
+
+#include "src/tint/lang/core/intrinsic/table_data.h"
+#include "src/tint/lang/core/ir/builtin_call.h"
+#include "src/tint/lang/hlsl/builtin_fn.h"
+#include "src/tint/lang/hlsl/intrinsic/dialect.h"
+#include "src/tint/utils/rtti/castable.h"
+
+namespace tint::hlsl::ir {
+
+/// A HLSL builtin call instruction in the IR.
+class BuiltinCall final : public Castable<BuiltinCall, core::ir::BuiltinCall> {
+ public:
+ /// Constructor
+ /// @param result the result value
+ /// @param func the builtin function
+ /// @param args the conversion arguments
+ BuiltinCall(core::ir::InstructionResult* result,
+ BuiltinFn func,
+ VectorRef<core::ir::Value*> args = tint::Empty);
+ ~BuiltinCall() override;
+
+ /// @copydoc core::ir::Instruction::Clone()
+ BuiltinCall* Clone(core::ir::CloneContext& ctx) override;
+
+ /// @returns the builtin function
+ BuiltinFn Func() const { return func_; }
+
+ /// @returns the identifier for the function
+ size_t FuncId() const override { return static_cast<size_t>(func_); }
+
+ /// @returns the friendly name for the instruction
+ std::string FriendlyName() const override { return std::string("hlsl.") + str(func_); }
+
+ /// @returns the table data to validate this builtin
+ const core::intrinsic::TableData& TableData() const override {
+ return hlsl::intrinsic::Dialect::kData;
+ }
+
+ private:
+ BuiltinFn func_;
+};
+
+} // namespace tint::hlsl::ir
+
+#endif // SRC_TINT_LANG_HLSL_IR_BUILTIN_CALL_H_
diff --git a/src/tint/lang/hlsl/ir/builtin_call_test.cc b/src/tint/lang/hlsl/ir/builtin_call_test.cc
new file mode 100644
index 0000000..8d6233c
--- /dev/null
+++ b/src/tint/lang/hlsl/ir/builtin_call_test.cc
@@ -0,0 +1,62 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/hlsl/ir/builtin_call.h"
+
+#include "gtest/gtest.h"
+#include "src/tint/lang/core/ir/ir_helper_test.h"
+#include "src/tint/lang/core/ir/validator.h"
+
+using namespace tint::core::fluent_types; // NOLINT
+
+namespace tint::hlsl::ir {
+namespace {
+
+using namespace tint::core::number_suffixes; // NOLINT
+ //
+using IR_HlslBuiltinCallTest = core::ir::IRTestHelper;
+
+TEST_F(IR_HlslBuiltinCallTest, Clone) {
+ auto* builtin = b.Call<BuiltinCall>(mod.Types().u32(), BuiltinFn::kF32Tof16, 0_f);
+
+ auto* new_b = clone_ctx.Clone(builtin);
+
+ EXPECT_NE(builtin, new_b);
+ EXPECT_NE(builtin->Result(0), new_b->Result(0));
+ EXPECT_EQ(mod.Types().u32(), new_b->Result(0)->Type());
+
+ EXPECT_EQ(BuiltinFn::kF32Tof16, new_b->Func());
+
+ auto args = new_b->Args();
+ EXPECT_EQ(1u, args.Length());
+
+ auto* val0 = args[0]->As<core::ir::Constant>()->Value();
+ EXPECT_EQ(0_f, val0->As<core::constant::Scalar<core::f32>>()->ValueAs<core::f32>());
+}
+
+} // namespace
+} // namespace tint::hlsl::ir
diff --git a/src/tint/lang/hlsl/writer/bitcast_test.cc b/src/tint/lang/hlsl/writer/bitcast_test.cc
index 14b4cee..81ad93d 100644
--- a/src/tint/lang/hlsl/writer/bitcast_test.cc
+++ b/src/tint/lang/hlsl/writer/bitcast_test.cc
@@ -140,22 +140,22 @@
});
ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
- EXPECT_EQ(output_.hlsl, R"(int tint_bitcast_from_f16(vector<float16_t, 2> src) {
+ EXPECT_EQ(output_.hlsl, R"(
+uint tint_bitcast_from_f16_2(vector<float16_t, 2> src) {
uint2 r = f32tof16(float2(src));
- return asint(uint((r.x & 0xffff) | ((r.y & 0xffff) << 16)));
+ return ((r.x & 65535u) | ((r.y & 65535u) << 16u));
}
float tint_bitcast_from_f16_1(vector<float16_t, 2> src) {
uint2 r = f32tof16(float2(src));
- return asfloat(uint((r.x & 0xffff) | ((r.y & 0xffff) << 16)));
+ return asfloat(((r.x & 65535u) | ((r.y & 65535u) << 16u)));
}
-uint tint_bitcast_from_f16_2(vector<float16_t, 2> src) {
+int tint_bitcast_from_f16(vector<float16_t, 2> src) {
uint2 r = f32tof16(float2(src));
- return asuint(uint((r.x & 0xffff) | ((r.y & 0xffff) << 16)));
+ return asint(((r.x & 65535u) | ((r.y & 65535u) << 16u)));
}
-
void foo() {
vector<float16_t, 2> a = vector<float16_t, 2>(float16_t(1.0h), float16_t(2.0h));
int b = tint_bitcast_from_f16(a);
@@ -181,28 +181,28 @@
});
ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
- EXPECT_EQ(output_.hlsl, R"(vector<float16_t, 2> tint_bitcast_to_f16(int src) {
- uint v = asuint(src);
- float t_low = f16tof32(v & 0xffff);
- float t_high = f16tof32((v >> 16) & 0xffff);
+ EXPECT_EQ(output_.hlsl, R"(
+vector<float16_t, 2> tint_bitcast_to_f16_2(uint src) {
+ uint v = src;
+ float t_low = f16tof32((v & 65535u));
+ float t_high = f16tof32(((v >> 16u) & 65535u));
return vector<float16_t, 2>(t_low.x, t_high.x);
}
vector<float16_t, 2> tint_bitcast_to_f16_1(float src) {
uint v = asuint(src);
- float t_low = f16tof32(v & 0xffff);
- float t_high = f16tof32((v >> 16) & 0xffff);
+ float t_low = f16tof32((v & 65535u));
+ float t_high = f16tof32(((v >> 16u) & 65535u));
return vector<float16_t, 2>(t_low.x, t_high.x);
}
-vector<float16_t, 2> tint_bitcast_to_f16_2(uint src) {
+vector<float16_t, 2> tint_bitcast_to_f16(int src) {
uint v = asuint(src);
- float t_low = f16tof32(v & 0xffff);
- float t_high = f16tof32((v >> 16) & 0xffff);
+ float t_low = f16tof32((v & 65535u));
+ float t_high = f16tof32(((v >> 16u) & 65535u));
return vector<float16_t, 2>(t_low.x, t_high.x);
}
-
void foo() {
int a = 1;
vector<float16_t, 2> b = tint_bitcast_to_f16(a);
@@ -227,22 +227,22 @@
});
ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
- EXPECT_EQ(output_.hlsl, R"(int2 tint_bitcast_from_f16(vector<float16_t, 4> src) {
+ EXPECT_EQ(output_.hlsl, R"(
+uint2 tint_bitcast_from_f16_2(vector<float16_t, 4> src) {
uint4 r = f32tof16(float4(src));
- return asint(uint2((r.x & 0xffff) | ((r.y & 0xffff) << 16), (r.z & 0xffff) | ((r.w & 0xffff) << 16)));
+ return uint2(((r.x & 65535u) | ((r.y & 65535u) << 16u)), ((r.z & 65535u) | ((r.w & 65535u) << 16u)));
}
float2 tint_bitcast_from_f16_1(vector<float16_t, 4> src) {
uint4 r = f32tof16(float4(src));
- return asfloat(uint2((r.x & 0xffff) | ((r.y & 0xffff) << 16), (r.z & 0xffff) | ((r.w & 0xffff) << 16)));
+ return asfloat(uint2(((r.x & 65535u) | ((r.y & 65535u) << 16u)), ((r.z & 65535u) | ((r.w & 65535u) << 16u))));
}
-uint2 tint_bitcast_from_f16_2(vector<float16_t, 4> src) {
+int2 tint_bitcast_from_f16(vector<float16_t, 4> src) {
uint4 r = f32tof16(float4(src));
- return asuint(uint2((r.x & 0xffff) | ((r.y & 0xffff) << 16), (r.z & 0xffff) | ((r.w & 0xffff) << 16)));
+ return asint(uint2(((r.x & 65535u) | ((r.y & 65535u) << 16u)), ((r.z & 65535u) | ((r.w & 65535u) << 16u))));
}
-
void foo() {
vector<float16_t, 4> a = vector<float16_t, 4>(float16_t(1.0h), float16_t(2.0h), float16_t(3.0h), float16_t(4.0h));
int2 b = tint_bitcast_from_f16(a);
@@ -268,28 +268,34 @@
});
ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
- EXPECT_EQ(output_.hlsl, R"(vector<float16_t, 4> tint_bitcast_to_f16(int2 src) {
- uint2 v = asuint(src);
- float2 t_low = f16tof32(v & 0xffff);
- float2 t_high = f16tof32((v >> 16) & 0xffff);
+ EXPECT_EQ(output_.hlsl, R"(
+vector<float16_t, 4> tint_bitcast_to_f16_2(uint2 src) {
+ uint2 v = src;
+ uint2 mask = (65535u).xx;
+ uint2 shift = (16u).xx;
+ float2 t_low = f16tof32((v & mask));
+ float2 t_high = f16tof32(((v >> shift) & mask));
return vector<float16_t, 4>(t_low.x, t_high.x, t_low.y, t_high.y);
}
vector<float16_t, 4> tint_bitcast_to_f16_1(float2 src) {
uint2 v = asuint(src);
- float2 t_low = f16tof32(v & 0xffff);
- float2 t_high = f16tof32((v >> 16) & 0xffff);
+ uint2 mask = (65535u).xx;
+ uint2 shift = (16u).xx;
+ float2 t_low = f16tof32((v & mask));
+ float2 t_high = f16tof32(((v >> shift) & mask));
return vector<float16_t, 4>(t_low.x, t_high.x, t_low.y, t_high.y);
}
-vector<float16_t, 4> tint_bitcast_to_f16_2(uint2 src) {
+vector<float16_t, 4> tint_bitcast_to_f16(int2 src) {
uint2 v = asuint(src);
- float2 t_low = f16tof32(v & 0xffff);
- float2 t_high = f16tof32((v >> 16) & 0xffff);
+ uint2 mask = (65535u).xx;
+ uint2 shift = (16u).xx;
+ float2 t_low = f16tof32((v & mask));
+ float2 t_high = f16tof32(((v >> shift) & mask));
return vector<float16_t, 4>(t_low.x, t_high.x, t_low.y, t_high.y);
}
-
void foo() {
int2 a = int2(1, 2);
vector<float16_t, 4> b = tint_bitcast_to_f16(a);
diff --git a/src/tint/lang/hlsl/writer/printer/BUILD.bazel b/src/tint/lang/hlsl/writer/printer/BUILD.bazel
index abb8a5e..69bea38 100644
--- a/src/tint/lang/hlsl/writer/printer/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/printer/BUILD.bazel
@@ -51,6 +51,9 @@
"//src/tint/lang/core/intrinsic",
"//src/tint/lang/core/ir",
"//src/tint/lang/core/type",
+ "//src/tint/lang/hlsl",
+ "//src/tint/lang/hlsl/intrinsic",
+ "//src/tint/lang/hlsl/ir",
"//src/tint/utils/containers",
"//src/tint/utils/diagnostic",
"//src/tint/utils/generator",
diff --git a/src/tint/lang/hlsl/writer/printer/BUILD.cmake b/src/tint/lang/hlsl/writer/printer/BUILD.cmake
index 8379d9e..4fcaeb4 100644
--- a/src/tint/lang/hlsl/writer/printer/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/printer/BUILD.cmake
@@ -50,6 +50,9 @@
tint_lang_core_intrinsic
tint_lang_core_ir
tint_lang_core_type
+ tint_lang_hlsl
+ tint_lang_hlsl_intrinsic
+ tint_lang_hlsl_ir
tint_utils_containers
tint_utils_diagnostic
tint_utils_generator
diff --git a/src/tint/lang/hlsl/writer/printer/BUILD.gn b/src/tint/lang/hlsl/writer/printer/BUILD.gn
index 426f658..eb14752 100644
--- a/src/tint/lang/hlsl/writer/printer/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/printer/BUILD.gn
@@ -50,6 +50,9 @@
"${tint_src_dir}/lang/core/intrinsic",
"${tint_src_dir}/lang/core/ir",
"${tint_src_dir}/lang/core/type",
+ "${tint_src_dir}/lang/hlsl",
+ "${tint_src_dir}/lang/hlsl/intrinsic",
+ "${tint_src_dir}/lang/hlsl/ir",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
"${tint_src_dir}/utils/generator",
diff --git a/src/tint/lang/hlsl/writer/printer/printer.cc b/src/tint/lang/hlsl/writer/printer/printer.cc
index e4be041..79847cb 100644
--- a/src/tint/lang/hlsl/writer/printer/printer.cc
+++ b/src/tint/lang/hlsl/writer/printer/printer.cc
@@ -102,13 +102,13 @@
#include "src/tint/lang/core/type/u32.h"
#include "src/tint/lang/core/type/vector.h"
#include "src/tint/lang/core/type/void.h"
+#include "src/tint/lang/hlsl/ir/builtin_call.h"
#include "src/tint/utils/containers/hashmap.h"
#include "src/tint/utils/containers/map.h"
#include "src/tint/utils/generator/text_generator.h"
#include "src/tint/utils/ice/ice.h"
#include "src/tint/utils/macros/compiler.h"
#include "src/tint/utils/macros/scoped_assignment.h"
-#include "src/tint/utils/math/hash.h"
#include "src/tint/utils/rtti/switch.h"
#include "src/tint/utils/strconv/float_to_string.h"
#include "src/tint/utils/text/string.h"
@@ -194,13 +194,6 @@
/// Block to emit for a continuing
std::function<void()> emit_continuing_;
- using BinaryType =
- tint::UnorderedKeyWrapper<std::tuple<const core::type::Type*, const core::type::Type*>>;
-
- // Polyfill functions for bitcast expression, BinaryType indicates the source type and the
- // destination type.
- std::unordered_map<BinaryType, std::string> bitcast_funcs_;
-
/// Emit the root block.
/// @param root_block the root block to emit
void EmitRootBlock(core::ir::Block* root_block) {
@@ -617,7 +610,6 @@
Switch(
r->Instruction(), //
[&](const core::ir::Access* a) { EmitAccess(out, a); }, //
- [&](const core::ir::Bitcast* b) { EmitBitcast(out, b); }, //
[&](const core::ir::Construct* c) { EmitConstruct(out, c); }, //
[&](const core::ir::Convert* c) { EmitConvert(out, c); }, //
[&](const core::ir::CoreBinary* b) { EmitBinary(out, b); }, //
@@ -631,164 +623,28 @@
[&](const core::ir::UserCall* c) { EmitUserCall(out, c); }, //
[&](const core::ir::Swizzle* s) { EmitSwizzle(out, s); }, //
[&](const core::ir::Var* var) { out << NameOf(var->Result(0)); }, //
+
+ [&](const hlsl::ir::BuiltinCall* c) { EmitHlslBuiltinCall(out, c); }, //
+
TINT_ICE_ON_NO_MATCH);
},
[&](const core::ir::FunctionParam* p) { out << NameOf(p); }, //
TINT_ICE_ON_NO_MATCH);
}
- /// Emit a bitcast instruction
- void EmitBitcast(StringStream& out, const core::ir::Bitcast* b) {
- auto* src_type = b->Val()->Type();
- auto* dst_type = b->Result(0)->Type();
-
- // Identity transform
- if (src_type == dst_type) {
- EmitValue(out, b->Val());
- return;
+ void EmitHlslBuiltinCall(StringStream& out, const hlsl::ir::BuiltinCall* c) {
+ out << c->Func() << "(";
+ bool needs_comma = false;
+ for (const auto* arg : c->Args()) {
+ if (needs_comma) {
+ out << ", ";
+ }
+ EmitValue(out, arg);
+ needs_comma = true;
}
-
- if (src_type->DeepestElement()->As<core::type::F16>()) {
- out << EmitBitcastFromF16(src_type, dst_type);
- } else if (dst_type->DeepestElement()->As<core::type::F16>()) {
- out << EmitBitcastToF16(src_type, dst_type);
- } else {
- out << "as";
- EmitType(out, dst_type);
- }
- out << "(";
- EmitValue(out, b->Val());
out << ")";
}
- // Bitcast f16 types to others by converting the given f16 value to f32 and call
- // f32tof16 to get the bits. This should be safe, because the conversion is precise
- // for finite and infinite f16 value as they are exactly representable by f32.
- std::string EmitBitcastFromF16(const core::type::Type* src_type,
- const core::type::Type* dst_type) {
- return tint::GetOrAdd(
- bitcast_funcs_, BinaryType{{src_type, dst_type}}, [&]() -> std::string {
- TextBuffer b;
- auto fn_name = UniqueIdentifier(std::string("tint_bitcast_from_f16"));
- {
- auto decl = Line(&b);
- EmitTypeAndName(decl, dst_type, core::AddressSpace::kUndefined,
- core::Access::kUndefined, fn_name);
- {
- const ScopedParen sp(decl);
- EmitTypeAndName(decl, src_type, core::AddressSpace::kUndefined,
- core::Access::kUndefined, "src");
- }
- decl << " {";
- }
- {
- auto* src_vec = src_type->As<core::type::Vector>();
-
- const ScopedIndent si(&b);
- {
- Line(&b) << "uint" << src_vec->Width() << " r = f32tof16(float"
- << src_vec->Width() << "(src));";
-
- {
- auto* dst_el_type = dst_type->DeepestElement();
-
- auto s = Line(&b);
- s << "return as";
- EmitType(s, dst_el_type, core::AddressSpace::kUndefined,
- core::Access::kReadWrite, "");
- s << "(";
- switch (src_vec->Width()) {
- case 2: {
- s << "uint((r.x & 0xffff) | ((r.y & 0xffff) << 16))";
- break;
- }
- case 4: {
- s << "uint2((r.x & 0xffff) | ((r.y & 0xffff) << 16), "
- "(r.z & 0xffff) | ((r.w & 0xffff) << 16))";
- break;
- }
- default: {
- TINT_UNREACHABLE();
- }
- }
- s << ");";
- }
- }
- }
- Line(&b) << "}";
- Line(&b);
-
- preamble_buffer_.Append(b);
- return fn_name;
- });
- }
-
- // Bitcast other types to f16 types by reinterpreting their bits as f16 using
- // f16tof32, and convert the result f32 to f16. This should be safe, because the
- // conversion is precise for finite and infinite f16 result value as they are
- // exactly representable by f32.
- std::string EmitBitcastToF16(const core::type::Type* src_type,
- const core::type::Type* dst_type) {
- return tint::GetOrAdd(
- bitcast_funcs_, BinaryType{{src_type, dst_type}}, [&]() -> std::string {
- TextBuffer b;
- auto fn_name = UniqueIdentifier(std::string("tint_bitcast_to_f16"));
- {
- auto decl = Line(&b);
- EmitTypeAndName(decl, dst_type, core::AddressSpace::kUndefined,
- core::Access::kUndefined, fn_name);
- {
- const ScopedParen sp(decl);
- EmitTypeAndName(decl, src_type, core::AddressSpace::kUndefined,
- core::Access::kUndefined, "src");
- }
- decl << " {";
- }
- {
- const ScopedIndent si(&b);
- {
- auto* dst_vec = dst_type->As<core::type::Vector>();
- auto* src_vec = src_type->As<core::type::Vector>();
- const std::string src_type_suffix = (src_vec ? "2" : "");
-
- // Convert the source to uint for f16tof32.
- Line(&b) << "uint" << src_type_suffix << " v = asuint(src);";
- // Reinterpret the low 16 bits and high 16 bits
- Line(&b) << "float" << src_type_suffix << " t_low = f16tof32(v & 0xffff);";
- Line(&b) << "float" << src_type_suffix
- << " t_high = f16tof32((v >> 16) & 0xffff);";
- // Construct the result f16 vector
- {
- auto s = Line(&b);
- s << "return ";
- EmitType(s, dst_type, core::AddressSpace::kUndefined,
- core::Access::kReadWrite, "");
- s << "(";
- switch (dst_vec->Width()) {
- case 2: {
- s << "t_low.x, t_high.x";
- break;
- }
- case 4: {
- s << "t_low.x, t_high.x, t_low.y, t_high.y";
- break;
- }
- default: {
- TINT_UNREACHABLE();
- }
- }
- s << ");";
- }
- }
- }
- Line(&b) << "}";
- Line(&b);
-
- preamble_buffer_.Append(b);
- return fn_name;
- });
- }
-
/// Emit a convert instruction
void EmitConvert(StringStream& out, const core::ir::Convert* c) {
EmitType(out, c->Result(0)->Type());
diff --git a/src/tint/lang/hlsl/writer/raise/BUILD.bazel b/src/tint/lang/hlsl/writer/raise/BUILD.bazel
index f989717..b716ce7 100644
--- a/src/tint/lang/hlsl/writer/raise/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/raise/BUILD.bazel
@@ -39,10 +39,12 @@
cc_library(
name = "raise",
srcs = [
+ "builtin_polyfill.cc",
"fxc_polyfill.cc",
"raise.cc",
],
hdrs = [
+ "builtin_polyfill.h",
"fxc_polyfill.h",
"raise.h",
],
@@ -54,6 +56,9 @@
"//src/tint/lang/core/ir",
"//src/tint/lang/core/ir/transform",
"//src/tint/lang/core/type",
+ "//src/tint/lang/hlsl",
+ "//src/tint/lang/hlsl/intrinsic",
+ "//src/tint/lang/hlsl/ir",
"//src/tint/lang/hlsl/writer/common",
"//src/tint/utils/containers",
"//src/tint/utils/diagnostic",
@@ -76,6 +81,7 @@
name = "test",
alwayslink = True,
srcs = [
+ "builtin_polyfill_test.cc",
"fxc_polyfill_test.cc",
],
deps = [
diff --git a/src/tint/lang/hlsl/writer/raise/BUILD.cmake b/src/tint/lang/hlsl/writer/raise/BUILD.cmake
index 47e9ce4..fd8ae66 100644
--- a/src/tint/lang/hlsl/writer/raise/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/raise/BUILD.cmake
@@ -39,6 +39,8 @@
# Kind: lib
################################################################################
tint_add_target(tint_lang_hlsl_writer_raise lib
+ lang/hlsl/writer/raise/builtin_polyfill.cc
+ lang/hlsl/writer/raise/builtin_polyfill.h
lang/hlsl/writer/raise/fxc_polyfill.cc
lang/hlsl/writer/raise/fxc_polyfill.h
lang/hlsl/writer/raise/raise.cc
@@ -53,6 +55,9 @@
tint_lang_core_ir
tint_lang_core_ir_transform
tint_lang_core_type
+ tint_lang_hlsl
+ tint_lang_hlsl_intrinsic
+ tint_lang_hlsl_ir
tint_lang_hlsl_writer_common
tint_utils_containers
tint_utils_diagnostic
@@ -74,6 +79,7 @@
# Kind: test
################################################################################
tint_add_target(tint_lang_hlsl_writer_raise_test test
+ lang/hlsl/writer/raise/builtin_polyfill_test.cc
lang/hlsl/writer/raise/fxc_polyfill_test.cc
)
diff --git a/src/tint/lang/hlsl/writer/raise/BUILD.gn b/src/tint/lang/hlsl/writer/raise/BUILD.gn
index 0d755f2..ff211e5 100644
--- a/src/tint/lang/hlsl/writer/raise/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/raise/BUILD.gn
@@ -44,6 +44,8 @@
libtint_source_set("raise") {
sources = [
+ "builtin_polyfill.cc",
+ "builtin_polyfill.h",
"fxc_polyfill.cc",
"fxc_polyfill.h",
"raise.cc",
@@ -57,6 +59,9 @@
"${tint_src_dir}/lang/core/ir",
"${tint_src_dir}/lang/core/ir/transform",
"${tint_src_dir}/lang/core/type",
+ "${tint_src_dir}/lang/hlsl",
+ "${tint_src_dir}/lang/hlsl/intrinsic",
+ "${tint_src_dir}/lang/hlsl/ir",
"${tint_src_dir}/lang/hlsl/writer/common",
"${tint_src_dir}/utils/containers",
"${tint_src_dir}/utils/diagnostic",
@@ -75,7 +80,10 @@
}
if (tint_build_unittests) {
tint_unittests_source_set("unittests") {
- sources = [ "fxc_polyfill_test.cc" ]
+ sources = [
+ "builtin_polyfill_test.cc",
+ "fxc_polyfill_test.cc",
+ ]
deps = [
"${tint_src_dir}:gmock_and_gtest",
"${tint_src_dir}/api/common",
diff --git a/src/tint/lang/hlsl/writer/raise/builtin_polyfill.cc b/src/tint/lang/hlsl/writer/raise/builtin_polyfill.cc
new file mode 100644
index 0000000..eddb32c
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/raise/builtin_polyfill.cc
@@ -0,0 +1,312 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/hlsl/writer/raise/builtin_polyfill.h"
+
+#include <string>
+#include <tuple>
+
+#include "src/tint/lang/core/fluent_types.h" // IWYU pragma: export
+#include "src/tint/lang/core/ir/builder.h"
+#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/lang/core/ir/validator.h"
+#include "src/tint/lang/core/type/manager.h"
+#include "src/tint/lang/hlsl/builtin_fn.h"
+#include "src/tint/lang/hlsl/ir/builtin_call.h"
+#include "src/tint/utils/containers/hashmap.h"
+#include "src/tint/utils/math/hash.h"
+
+namespace tint::hlsl::writer::raise {
+namespace {
+
+using namespace tint::core::fluent_types; // NOLINT
+using namespace tint::core::number_suffixes; // NOLINT
+
+/// PIMPL state for the transform.
+struct State {
+ /// The IR module.
+ core::ir::Module& ir;
+
+ /// The IR builder.
+ core::ir::Builder b{ir};
+
+ /// The type manager.
+ core::type::Manager& ty{ir.Types()};
+
+ using BinaryType =
+ tint::UnorderedKeyWrapper<std::tuple<const core::type::Type*, const core::type::Type*>>;
+
+ // Polyfill functions for bitcast expression, BinaryType indicates the source type and the
+ // destination type.
+ Hashmap<BinaryType, core::ir::Function*, 4> bitcast_funcs_{};
+
+ /// Process the module.
+ void Process() {
+ // Find the bitcasts that need replacing.
+ Vector<core::ir::Bitcast*, 4> bitcast_worklist;
+ for (auto* inst : ir.Instructions()) {
+ if (auto* bitcast = inst->As<core::ir::Bitcast>()) {
+ bitcast_worklist.Push(bitcast);
+ }
+ }
+
+ // Replace the bitcasts that we found.
+ for (auto* bitcast : bitcast_worklist) {
+ auto* src_type = bitcast->Val()->Type();
+ auto* dst_type = bitcast->Result(0)->Type();
+ auto* dst_deepest = dst_type->DeepestElement();
+
+ if (src_type == dst_type) {
+ ReplaceBitcastWithValue(bitcast);
+ } else if (src_type->DeepestElement()->Is<core::type::F16>()) {
+ ReplaceBitcastWithFromF16Polyfill(bitcast);
+ } else if (dst_deepest->Is<core::type::F16>()) {
+ ReplaceBitcastWithToF16Polyfill(bitcast);
+ } else {
+ ReplaceBitcastWithAs(bitcast);
+ }
+ }
+ }
+
+ /// Replaces an identity bitcast result with the value.
+ void ReplaceBitcastWithValue(core::ir::Bitcast* bitcast) {
+ bitcast->Result(0)->ReplaceAllUsesWith(bitcast->Val());
+ bitcast->Destroy();
+ }
+
+ void ReplaceBitcastWithAs(core::ir::Bitcast* bitcast) {
+ auto* dst_type = bitcast->Result(0)->Type();
+ auto* dst_deepest = dst_type->DeepestElement();
+
+ BuiltinFn fn = BuiltinFn::kNone;
+ tint::Switch(
+ dst_deepest, //
+ [&](const core::type::I32*) { fn = BuiltinFn::kAsint; }, //
+ [&](const core::type::U32*) { fn = BuiltinFn::kAsuint; }, //
+ [&](const core::type::F32*) { fn = BuiltinFn::kAsfloat; }, //
+ TINT_ICE_ON_NO_MATCH);
+
+ b.InsertBefore(bitcast, [&] {
+ b.CallWithResult<hlsl::ir::BuiltinCall>(bitcast->DetachResult(), fn, bitcast->Val());
+ });
+ bitcast->Destroy();
+ }
+
+ // Bitcast f16 types to others by converting the given f16 value to f32 and call
+ // f32tof16 to get the bits. This should be safe, because the conversion is precise
+ // for finite and infinite f16 value as they are exactly representable by f32.
+ core::ir::Function* CreateBitcastFromF16(const core::type::Type* src_type,
+ const core::type::Type* dst_type) {
+ return bitcast_funcs_.GetOrAdd(
+ BinaryType{{src_type, dst_type}}, [&]() -> core::ir::Function* {
+ TINT_ASSERT(src_type->Is<core::type::Vector>());
+
+ // Generate a helper function that performs the following (in HLSL):
+ //
+ // uint tint_bitcast_from_f16(vector<float16_t, 2> src) {
+ // uint2 r = f32tof16(float2(src));
+ // return uint((r.x & 65535u) | ((r.y & 65535u) << 16u));
+ // }
+
+ auto fn_name = b.ir.symbols.New(std::string("tint_bitcast_from_f16")).Name();
+
+ auto* f = b.Function(fn_name, dst_type);
+ auto* src = b.FunctionParam("src", src_type);
+ f->SetParams({src});
+
+ b.Append(f->Block(), [&] {
+ auto* src_vec = src_type->As<core::type::Vector>();
+
+ auto* cast = b.Convert(ty.vec(ty.f32(), src_vec->Width()), src);
+ auto* r =
+ b.Let("r", b.Call<hlsl::ir::BuiltinCall>(ty.vec(ty.u32(), src_vec->Width()),
+ hlsl::BuiltinFn::kF32Tof16, cast));
+
+ auto* x = b.And(ty.u32(), b.Swizzle(ty.u32(), r, {0_u}), 0xffff_u);
+ auto* y = b.ShiftLeft(
+ ty.u32(), b.And(ty.u32(), b.Swizzle(ty.u32(), r, {1_u}), 0xffff_u), 16_u);
+
+ auto* s = b.Or(ty.u32(), x, y);
+ core::ir::InstructionResult* result = nullptr;
+
+ switch (src_vec->Width()) {
+ case 2: {
+ result = s->Result(0);
+ break;
+ }
+ case 4: {
+ auto* z = b.And(ty.u32(), b.Swizzle(ty.u32(), r, {2_u}), 0xffff_u);
+ auto* w = b.ShiftLeft(
+ ty.u32(), b.And(ty.u32(), b.Swizzle(ty.u32(), r, {3_u}), 0xffff_u),
+ 16_u);
+
+ auto* t = b.Or(ty.u32(), z, w);
+ auto* cons = b.Construct(ty.vec2<u32>(), s, t);
+ result = cons->Result(0);
+ break;
+ }
+ default:
+ TINT_UNREACHABLE();
+ }
+
+ tint::Switch(
+ dst_type->DeepestElement(), //
+ [&](const core::type::F32*) {
+ b.Return(f, b.Call<hlsl::ir::BuiltinCall>(dst_type, BuiltinFn::kAsfloat,
+ result));
+ },
+ [&](const core::type::I32*) {
+ b.Return(f, b.Call<hlsl::ir::BuiltinCall>(dst_type, BuiltinFn::kAsint,
+ result));
+ },
+ [&](const core::type::U32*) { b.Return(f, result); }, //
+ TINT_ICE_ON_NO_MATCH);
+ });
+ return f;
+ });
+ }
+
+ /// Replaces a bitcast with a call to the FromF16 polyfill for the given types
+ void ReplaceBitcastWithFromF16Polyfill(core::ir::Bitcast* bitcast) {
+ auto* src_type = bitcast->Val()->Type();
+ auto* dst_type = bitcast->Result(0)->Type();
+
+ auto* f = CreateBitcastFromF16(src_type, dst_type);
+ b.InsertBefore(bitcast,
+ [&] { b.CallWithResult(bitcast->DetachResult(), f, bitcast->Args()[0]); });
+ bitcast->Destroy();
+ }
+
+ // Bitcast other types to f16 types by reinterpreting their bits as f16 using
+ // f16tof32, and convert the result f32 to f16. This should be safe, because the
+ // conversion is precise for finite and infinite f16 result value as they are
+ // exactly representable by f32.
+ core::ir::Function* CreateBitcastToF16(const core::type::Type* src_type,
+ const core::type::Type* dst_type) {
+ return bitcast_funcs_.GetOrAdd(
+ BinaryType{{src_type, dst_type}}, [&]() -> core::ir::Function* {
+ TINT_ASSERT(dst_type->Is<core::type::Vector>());
+
+ // Generate a helper function that performs the following (in HLSL):
+ //
+ // vector<float16_t, 2> tint_bitcast_to_f16(float src) {
+ // uint v = asuint(src);
+ // float t_low = f16tof32(v & 65535u);
+ // float t_high = f16tof32((v >> 16u) & 65535u);
+ // return vector<float16_t, 2>(t_low.x, t_high.x);
+ // }
+
+ auto fn_name = b.ir.symbols.New(std::string("tint_bitcast_to_f16")).Name();
+
+ auto* f = b.Function(fn_name, dst_type);
+ auto* src = b.FunctionParam("src", src_type);
+ f->SetParams({src});
+ b.Append(f->Block(), [&] {
+ const core::type::Type* uint_ty = nullptr;
+ const core::type::Type* float_ty = nullptr;
+
+ auto* src_vec = src_type->As<core::type::Vector>();
+ if (src_vec) {
+ uint_ty = ty.vec(ty.u32(), src_vec->Width());
+ float_ty = ty.vec(ty.f32(), src_vec->Width());
+ } else {
+ uint_ty = ty.u32();
+ float_ty = ty.f32();
+ }
+
+ core::ir::Instruction* v = nullptr;
+ tint::Switch(
+ src_type->DeepestElement(), //
+ [&](const core::type::U32*) { v = b.Let("v", src); }, //
+ [&](const core::type::I32*) {
+ v = b.Let("v", b.Call<hlsl::ir::BuiltinCall>(uint_ty,
+ BuiltinFn::kAsuint, src));
+ },
+ [&](const core::type::F32*) {
+ v = b.Let("v", b.Call<hlsl::ir::BuiltinCall>(uint_ty,
+ BuiltinFn::kAsuint, src));
+ },
+ TINT_ICE_ON_NO_MATCH);
+
+ core::ir::Value* mask = nullptr;
+ core::ir::Value* shift = nullptr;
+ if (src_vec) {
+ mask = b.Let("mask", b.Splat(uint_ty, 0xffff_u))->Result(0);
+ shift = b.Let("shift", b.Splat(uint_ty, 16_u))->Result(0);
+ } else {
+ mask = b.Value(b.Constant(0xffff_u));
+ shift = b.Value(b.Constant(16_u));
+ }
+
+ auto* l = b.And(uint_ty, v, mask);
+ auto* t_low = b.Let(
+ "t_low", b.Call<hlsl::ir::BuiltinCall>(float_ty, BuiltinFn::kF16Tof32, l));
+
+ auto* h = b.And(uint_ty, b.ShiftRight(uint_ty, v, shift), mask);
+ auto* t_high = b.Let(
+ "t_high", b.Call<hlsl::ir::BuiltinCall>(float_ty, BuiltinFn::kF16Tof32, h));
+
+ auto* x = b.Swizzle(ty.f16(), t_low, {0_u});
+ auto* y = b.Swizzle(ty.f16(), t_high, {0_u});
+ if (dst_type->As<core::type::Vector>()->Width() == 2) {
+ b.Return(f, b.Construct(dst_type, x, y));
+ } else {
+ auto* z = b.Swizzle(ty.f16(), t_low, {1_u});
+ auto* w = b.Swizzle(ty.f16(), t_high, {1_u});
+ b.Return(f, b.Construct(dst_type, x, y, z, w));
+ }
+ });
+ return f;
+ });
+ }
+
+ /// Replaces a bitcast with a call to the ToF16 polyfill for the given types
+ void ReplaceBitcastWithToF16Polyfill(core::ir::Bitcast* bitcast) {
+ auto* src_type = bitcast->Val()->Type();
+ auto* dst_type = bitcast->Result(0)->Type();
+
+ auto* f = CreateBitcastToF16(src_type, dst_type);
+ b.InsertBefore(bitcast,
+ [&] { b.CallWithResult(bitcast->DetachResult(), f, bitcast->Args()[0]); });
+ bitcast->Destroy();
+ }
+};
+
+} // namespace
+
+Result<SuccessType> BuiltinPolyfill(core::ir::Module& ir) {
+ auto result = ValidateAndDumpIfNeeded(ir, "BuiltinPolyfill transform");
+ if (result != Success) {
+ return result.Failure();
+ }
+
+ State{ir}.Process();
+
+ return Success;
+}
+
+} // namespace tint::hlsl::writer::raise
diff --git a/src/tint/lang/hlsl/writer/raise/builtin_polyfill.h b/src/tint/lang/hlsl/writer/raise/builtin_polyfill.h
new file mode 100644
index 0000000..c161f05
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/raise/builtin_polyfill.h
@@ -0,0 +1,49 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_HLSL_WRITER_RAISE_BUILTIN_POLYFILL_H_
+#define SRC_TINT_LANG_HLSL_WRITER_RAISE_BUILTIN_POLYFILL_H_
+
+#include "src/tint/utils/result/result.h"
+
+// Forward declarations.
+namespace tint::core::ir {
+class Module;
+class Texture;
+} // namespace tint::core::ir
+
+namespace tint::hlsl::writer::raise {
+
+/// BuiltinPolyfill is a transform that replaces calls to builtins with polyfills and calls to
+/// HLSL polyfilled or backend intrinsic functions.
+/// @param module the module to transform
+/// @returns success or failure
+Result<SuccessType> BuiltinPolyfill(core::ir::Module& module);
+
+} // namespace tint::hlsl::writer::raise
+
+#endif // SRC_TINT_LANG_HLSL_WRITER_RAISE_BUILTIN_POLYFILL_H_
diff --git a/src/tint/lang/hlsl/writer/raise/builtin_polyfill_test.cc b/src/tint/lang/hlsl/writer/raise/builtin_polyfill_test.cc
new file mode 100644
index 0000000..f9545d6
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/raise/builtin_polyfill_test.cc
@@ -0,0 +1,395 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/hlsl/writer/raise/builtin_polyfill.h"
+
+#include "gtest/gtest.h"
+#include "src/tint/lang/core/fluent_types.h"
+#include "src/tint/lang/core/ir/transform/helper_test.h"
+#include "src/tint/lang/core/number.h"
+#include "src/tint/lang/core/type/builtin_structs.h"
+#include "src/tint/lang/core/type/storage_texture.h"
+
+using namespace tint::core::fluent_types; // NOLINT
+using namespace tint::core::number_suffixes; // NOLINT
+
+namespace tint::hlsl::writer::raise {
+namespace {
+
+using HlslWriter_BuiltinPolyfillTest = core::ir::transform::TransformTest;
+
+TEST_F(HlslWriter_BuiltinPolyfillTest, BitcastIdentity) {
+ auto* a = b.FunctionParam<i32>("a");
+ auto* func = b.Function("foo", ty.i32());
+ func->SetParams({a});
+ b.Append(func->Block(), [&] { b.Return(func, b.Bitcast<i32>(a)); });
+
+ auto* src = R"(
+%foo = func(%a:i32):i32 {
+ $B1: {
+ %3:i32 = bitcast %a
+ ret %3
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%a:i32):i32 {
+ $B1: {
+ ret %a
+ }
+}
+)";
+
+ Run(BuiltinPolyfill);
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriter_BuiltinPolyfillTest, Asuint) {
+ auto* a = b.FunctionParam<i32>("a");
+ auto* func = b.Function("foo", ty.u32());
+ func->SetParams({a});
+ b.Append(func->Block(), [&] { b.Return(func, b.Bitcast<u32>(a)); });
+
+ auto* src = R"(
+%foo = func(%a:i32):u32 {
+ $B1: {
+ %3:u32 = bitcast %a
+ ret %3
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%a:i32):u32 {
+ $B1: {
+ %3:u32 = hlsl.asuint %a
+ ret %3
+ }
+}
+)";
+
+ Run(BuiltinPolyfill);
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriter_BuiltinPolyfillTest, Asint) {
+ auto* a = b.FunctionParam<u32>("a");
+ auto* func = b.Function("foo", ty.i32());
+ func->SetParams({a});
+ b.Append(func->Block(), [&] { b.Return(func, b.Bitcast<i32>(a)); });
+
+ auto* src = R"(
+%foo = func(%a:u32):i32 {
+ $B1: {
+ %3:i32 = bitcast %a
+ ret %3
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%a:u32):i32 {
+ $B1: {
+ %3:i32 = hlsl.asint %a
+ ret %3
+ }
+}
+)";
+
+ Run(BuiltinPolyfill);
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriter_BuiltinPolyfillTest, Asfloat) {
+ auto* a = b.FunctionParam<i32>("a");
+ auto* func = b.Function("foo", ty.f32());
+ func->SetParams({a});
+ b.Append(func->Block(), [&] { b.Return(func, b.Bitcast<f32>(a)); });
+
+ auto* src = R"(
+%foo = func(%a:i32):f32 {
+ $B1: {
+ %3:f32 = bitcast %a
+ ret %3
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%a:i32):f32 {
+ $B1: {
+ %3:f32 = hlsl.asfloat %a
+ ret %3
+ }
+}
+)";
+
+ Run(BuiltinPolyfill);
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriter_BuiltinPolyfillTest, AsfloatVec) {
+ auto* a = b.FunctionParam<vec3<i32>>("a");
+ auto* func = b.Function("foo", ty.vec<f32, 3>());
+ func->SetParams({a});
+ b.Append(func->Block(), [&] { b.Return(func, b.Bitcast(ty.vec(ty.f32(), 3), a)); });
+
+ auto* src = R"(
+%foo = func(%a:vec3<i32>):vec3<f32> {
+ $B1: {
+ %3:vec3<f32> = bitcast %a
+ ret %3
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%a:vec3<i32>):vec3<f32> {
+ $B1: {
+ %3:vec3<f32> = hlsl.asfloat %a
+ ret %3
+ }
+}
+)";
+
+ Run(BuiltinPolyfill);
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriter_BuiltinPolyfillTest, BitcastFromF16) {
+ auto* a = b.FunctionParam<vec2<f16>>("a");
+ auto* func = b.Function("foo", ty.f32());
+ func->SetParams({a});
+ b.Append(func->Block(), [&] { b.Return(func, b.Bitcast(ty.f32(), a)); });
+
+ auto* src = R"(
+%foo = func(%a:vec2<f16>):f32 {
+ $B1: {
+ %3:f32 = bitcast %a
+ ret %3
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%a:vec2<f16>):f32 {
+ $B1: {
+ %3:f32 = call %tint_bitcast_from_f16, %a
+ ret %3
+ }
+}
+%tint_bitcast_from_f16 = func(%src:vec2<f16>):f32 {
+ $B2: {
+ %6:vec2<f32> = convert %src
+ %7:vec2<u32> = hlsl.f32tof16 %6
+ %r:vec2<u32> = let %7
+ %9:u32 = swizzle %r, x
+ %10:u32 = and %9, 65535u
+ %11:u32 = swizzle %r, y
+ %12:u32 = and %11, 65535u
+ %13:u32 = shl %12, 16u
+ %14:u32 = or %10, %13
+ %15:f32 = hlsl.asfloat %14
+ ret %15
+ }
+}
+)";
+
+ Run(BuiltinPolyfill);
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriter_BuiltinPolyfillTest, BitcastToF16) {
+ auto* a = b.FunctionParam<f32>("a");
+ auto* func = b.Function("foo", ty.vec2<f16>());
+ func->SetParams({a});
+ b.Append(func->Block(), [&] { b.Return(func, b.Bitcast(ty.vec2<f16>(), a)); });
+
+ auto* src = R"(
+%foo = func(%a:f32):vec2<f16> {
+ $B1: {
+ %3:vec2<f16> = bitcast %a
+ ret %3
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = func(%a:f32):vec2<f16> {
+ $B1: {
+ %3:vec2<f16> = call %tint_bitcast_to_f16, %a
+ ret %3
+ }
+}
+%tint_bitcast_to_f16 = func(%src:f32):vec2<f16> {
+ $B2: {
+ %6:u32 = hlsl.asuint %src
+ %v:u32 = let %6
+ %8:u32 = and %v, 65535u
+ %9:f32 = hlsl.f16tof32 %8
+ %t_low:f32 = let %9
+ %11:u32 = shr %v, 16u
+ %12:u32 = and %11, 65535u
+ %13:f32 = hlsl.f16tof32 %12
+ %t_high:f32 = let %13
+ %15:f16 = swizzle %t_low, x
+ %16:f16 = swizzle %t_high, x
+ %17:vec2<f16> = construct %15, %16
+ ret %17
+ }
+}
+)";
+
+ Run(BuiltinPolyfill);
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriter_BuiltinPolyfillTest, BitcastFromVec2F16) {
+ auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+ b.Append(func->Block(), [&] {
+ auto* a = b.Var("a", b.Construct<vec2<f16>>(1_h, 2_h));
+ auto* z = b.Load(a);
+ b.Let("b", b.Bitcast<i32>(z));
+ b.Return(func);
+ });
+
+ auto* src = R"(
+%foo = @fragment func():void {
+ $B1: {
+ %2:vec2<f16> = construct 1.0h, 2.0h
+ %a:ptr<function, vec2<f16>, read_write> = var, %2
+ %4:vec2<f16> = load %a
+ %5:i32 = bitcast %4
+ %b:i32 = let %5
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = @fragment func():void {
+ $B1: {
+ %2:vec2<f16> = construct 1.0h, 2.0h
+ %a:ptr<function, vec2<f16>, read_write> = var, %2
+ %4:vec2<f16> = load %a
+ %5:i32 = call %tint_bitcast_from_f16, %4
+ %b:i32 = let %5
+ ret
+ }
+}
+%tint_bitcast_from_f16 = func(%src:vec2<f16>):i32 {
+ $B2: {
+ %9:vec2<f32> = convert %src
+ %10:vec2<u32> = hlsl.f32tof16 %9
+ %r:vec2<u32> = let %10
+ %12:u32 = swizzle %r, x
+ %13:u32 = and %12, 65535u
+ %14:u32 = swizzle %r, y
+ %15:u32 = and %14, 65535u
+ %16:u32 = shl %15, 16u
+ %17:u32 = or %13, %16
+ %18:i32 = hlsl.asint %17
+ ret %18
+ }
+}
+)";
+
+ Run(BuiltinPolyfill);
+ EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriter_BuiltinPolyfillTest, BitcastToVec4F16) {
+ auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+ b.Append(func->Block(), [&] {
+ auto* a = b.Var("a", b.Construct<vec2<i32>>(1_i, 2_i));
+ b.Let("b", b.Bitcast<vec4<f16>>(b.Load(a)));
+ b.Return(func);
+ });
+
+ auto* src = R"(
+%foo = @fragment func():void {
+ $B1: {
+ %2:vec2<i32> = construct 1i, 2i
+ %a:ptr<function, vec2<i32>, read_write> = var, %2
+ %4:vec2<i32> = load %a
+ %5:vec4<f16> = bitcast %4
+ %b:vec4<f16> = let %5
+ ret
+ }
+}
+)";
+ EXPECT_EQ(src, str());
+
+ auto* expect = R"(
+%foo = @fragment func():void {
+ $B1: {
+ %2:vec2<i32> = construct 1i, 2i
+ %a:ptr<function, vec2<i32>, read_write> = var, %2
+ %4:vec2<i32> = load %a
+ %5:vec4<f16> = call %tint_bitcast_to_f16, %4
+ %b:vec4<f16> = let %5
+ ret
+ }
+}
+%tint_bitcast_to_f16 = func(%src:vec2<i32>):vec4<f16> {
+ $B2: {
+ %9:vec2<u32> = hlsl.asuint %src
+ %v:vec2<u32> = let %9
+ %mask:vec2<u32> = let vec2<u32>(65535u)
+ %shift:vec2<u32> = let vec2<u32>(16u)
+ %13:vec2<u32> = and %v, %mask
+ %14:vec2<f32> = hlsl.f16tof32 %13
+ %t_low:vec2<f32> = let %14
+ %16:vec2<u32> = shr %v, %shift
+ %17:vec2<u32> = and %16, %mask
+ %18:vec2<f32> = hlsl.f16tof32 %17
+ %t_high:vec2<f32> = let %18
+ %20:f16 = swizzle %t_low, x
+ %21:f16 = swizzle %t_high, x
+ %22:f16 = swizzle %t_low, y
+ %23:f16 = swizzle %t_high, y
+ %24:vec4<f16> = construct %20, %21, %22, %23
+ ret %24
+ }
+}
+)";
+
+ Run(BuiltinPolyfill);
+ EXPECT_EQ(expect, str());
+}
+
+} // namespace
+} // namespace tint::hlsl::writer::raise
diff --git a/src/tint/lang/hlsl/writer/raise/raise.cc b/src/tint/lang/hlsl/writer/raise/raise.cc
index da40afa..a9f0b33 100644
--- a/src/tint/lang/hlsl/writer/raise/raise.cc
+++ b/src/tint/lang/hlsl/writer/raise/raise.cc
@@ -30,6 +30,7 @@
#include "src/tint/lang/core/ir/transform/add_empty_entry_point.h"
#include "src/tint/lang/core/ir/transform/remove_terminator_args.h"
#include "src/tint/lang/hlsl/writer/common/options.h"
+#include "src/tint/lang/hlsl/writer/raise/builtin_polyfill.h"
#include "src/tint/lang/hlsl/writer/raise/fxc_polyfill.h"
#include "src/tint/utils/result/result.h"
@@ -50,6 +51,8 @@
RUN_TRANSFORM(raise::FxcPolyfill);
}
+ RUN_TRANSFORM(raise::BuiltinPolyfill);
+
// These transforms need to be run last as various transforms introduce terminator arguments,
// naming conflicts, and expressions that need to be explicitly not inlined.
RUN_TRANSFORM(core::ir::transform::RemoveTerminatorArgs);