Import Tint changes from Dawn

Changes:
  - b133c649c15f4936922804a4ece255559231f5ff [ir] Make root block always exist by dan sinclair <dsinclair@chromium.org>
  - 1d76252ce6b75860749fec957f0772823f752554 Remove `access_controls` from generic remapper options. by dan sinclair <dsinclair@chromium.org>
  - 707a5720ce5449d4ff495e1f56bfa587ee93fae5 [ir] Add ZeroInitWorkgroupMemory transform by James Price <jrprice@google.com>
  - 244cac957b325a8123bc162e1fc36162bca81dc7 Reorder options structures. by dan sinclair <dsinclair@chromium.org>
  - 16ce253b81aad7e36fed7cd1126949eb1501f3f1 OpenGL: fix multiplanar external textures. by Stephen White <senorblanco@chromium.org>
  - d0dfa74b4547dc250015b051d8bc3bfb5f341f00 [tint][ir] Add more validation by Ben Clayton <bclayton@google.com>
  - 5021631259fce929a3417909cc9fd70506f19602 [tint][ir] Make type construction and conversion unsequen... by Ben Clayton <bclayton@google.com>
  - dfc815c4ed2b85cc3a7b33895b823f58af24e8e5 [tint] Fork core builtin functions from core -> WGSL by Ben Clayton <bclayton@google.com>
  - c511ffb3fa4187b68aba998e30e12752639c5d95 dawn: Add install command to CMakeLists files by munoza <aura.munoz@autodesk.com>
  - eb44794b36a6cbb865a333057c770ef16cd166d5 [tint][ir] Remove BuiltinCall::IntrinsicName() by Ben Clayton <bclayton@google.com>
  - 30c31a99f0cfb54e1946e6ac8483c22ba378d2b6 [tint][ir] Pass ir::Module by reference, not pointer by Ben Clayton <bclayton@google.com>
  - 16fb254dc3083711a1da6a2a5118cc4eb3f59b03 [tint] Add a diag::List to tint::Failure by Ben Clayton <bclayton@google.com>
GitOrigin-RevId: b133c649c15f4936922804a4ece255559231f5ff
Change-Id: Ibeb3da4099bda48fab9f14bf44981b988c092b76
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/153501
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 2da7f95..8741ed9 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -347,6 +347,12 @@
 
   if(${KIND} STREQUAL lib)
     add_library(${TARGET} STATIC EXCLUDE_FROM_ALL)
+    if (TINT_ENABLE_INSTALL)
+      install(TARGETS ${TARGET}
+        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      )
+    endif()
     tint_default_compile_options(${TARGET})
 
     if(TINT_BUILD_FUZZERS)
@@ -355,6 +361,12 @@
       set(FUZZ_TARGET "${TARGET}${TINT_FUZZ_SUFFIX}")
       add_library(${FUZZ_TARGET} STATIC EXCLUDE_FROM_ALL)
       target_sources(${FUZZ_TARGET} PRIVATE ${SOURCES})
+      if (TINT_ENABLE_INSTALL)
+        install(TARGETS ${FUZZ_TARGET}
+                LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+                ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+                )
+      endif()
       tint_default_compile_options(${FUZZ_TARGET})
     endif()
   elseif(${KIND} STREQUAL cmd)
@@ -587,3 +599,17 @@
 # Target aliases
 ################################################################################
 add_library(libtint ALIAS tint_api)
+
+if (TINT_ENABLE_INSTALL)
+  # We need to recurse all folders and include all headers because tint.h includes most headers from src/tint
+  file(GLOB TINT_HEADERS "${DAWN_INCLUDE_DIR}/tint/*.h")
+
+  install(FILES ${TINT_HEADERS}  DESTINATION  ${CMAKE_INSTALL_INCLUDEDIR}/tint/)
+
+  file(GLOB_RECURSE TINT_SRC_HEADERS RELATIVE ${CMAKE_SOURCE_DIR}/src/tint/ "*.h")
+
+  foreach(TINT_HEADER_FILE ${TINT_SRC_HEADERS})
+      get_filename_component(TINT_HEADER_DIR ${TINT_HEADER_FILE} DIRECTORY)
+      install(FILES ${CMAKE_SOURCE_DIR}/src/tint/${TINT_HEADER_FILE}  DESTINATION  ${CMAKE_INSTALL_INCLUDEDIR}/src/tint/${TINT_HEADER_DIR})
+  endforeach ()
+endif()
diff --git a/src/tint/api/BUILD.bazel b/src/tint/api/BUILD.bazel
index 00f3628..885b21d 100644
--- a/src/tint/api/BUILD.bazel
+++ b/src/tint/api/BUILD.bazel
@@ -36,6 +36,7 @@
     "//src/tint/api/options",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/hlsl/writer/common",
     "//src/tint/lang/spirv/reader/common",
diff --git a/src/tint/api/BUILD.cmake b/src/tint/api/BUILD.cmake
index 05e09ff..697a9f0 100644
--- a/src/tint/api/BUILD.cmake
+++ b/src/tint/api/BUILD.cmake
@@ -38,6 +38,7 @@
   tint_api_options
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_hlsl_writer_common
   tint_lang_spirv_reader_common
diff --git a/src/tint/api/BUILD.gn b/src/tint/api/BUILD.gn
index e70d3af..b1e798a 100644
--- a/src/tint/api/BUILD.gn
+++ b/src/tint/api/BUILD.gn
@@ -35,6 +35,7 @@
     "${tint_src_dir}/api/options",
     "${tint_src_dir}/lang/core",
     "${tint_src_dir}/lang/core/constant",
+    "${tint_src_dir}/lang/core/ir",
     "${tint_src_dir}/lang/core/type",
     "${tint_src_dir}/lang/hlsl/writer/common",
     "${tint_src_dir}/lang/spirv/reader/common",
diff --git a/src/tint/api/options/binding_remapper.h b/src/tint/api/options/binding_remapper.h
index e1cd178..07ecafa 100644
--- a/src/tint/api/options/binding_remapper.h
+++ b/src/tint/api/options/binding_remapper.h
@@ -27,21 +27,15 @@
     /// BindingPoints is a map of old binding point to new binding point
     using BindingPoints = std::unordered_map<BindingPoint, BindingPoint>;
 
-    /// AccessControls is a map of old binding point to new access control
-    using AccessControls = std::unordered_map<BindingPoint, core::Access>;
-
     /// A map of old binding point to new binding point
     BindingPoints binding_points;
 
-    /// A map of old binding point to new access controls
-    AccessControls access_controls;
-
     /// If true, then validation will be disabled for binding point collisions
     /// generated by this transform
     bool allow_collisions = false;
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(binding_points, access_controls, allow_collisions);
+    TINT_REFLECT(binding_points, allow_collisions);
 };
 
 }  // namespace tint
diff --git a/src/tint/api/tint.cc b/src/tint/api/tint.cc
index 3cb2ebb..4d840f2 100644
--- a/src/tint/api/tint.cc
+++ b/src/tint/api/tint.cc
@@ -58,7 +58,7 @@
     tint::Program::printer = [](const tint::Program& program) {
         auto result = wgsl::writer::Generate(program, {});
         if (!result) {
-            return "error: " + result.Failure();
+            return result.Failure().reason.str();
         }
         return result->wgsl;
     };
diff --git a/src/tint/cmd/bench/BUILD.bazel b/src/tint/cmd/bench/BUILD.bazel
index 7995335..62a4335 100644
--- a/src/tint/cmd/bench/BUILD.bazel
+++ b/src/tint/cmd/bench/BUILD.bazel
@@ -61,9 +61,11 @@
     "main_bench.cc",
   ],
   deps = [
+    "//src/tint/api/common",
     "//src/tint/cmd/bench",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/core:bench",
     "//src/tint/lang/spirv/reader/common",
diff --git a/src/tint/cmd/bench/BUILD.cmake b/src/tint/cmd/bench/BUILD.cmake
index fdde451..a6da553 100644
--- a/src/tint/cmd/bench/BUILD.cmake
+++ b/src/tint/cmd/bench/BUILD.cmake
@@ -61,9 +61,11 @@
 )
 
 tint_target_add_dependencies(tint_cmd_bench_bench_cmd bench_cmd
+  tint_api_common
   tint_cmd_bench
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_core_bench
   tint_lang_spirv_reader_common
diff --git a/src/tint/cmd/bench/main_bench.cc b/src/tint/cmd/bench/main_bench.cc
index 3ee05d3..e04dc38 100644
--- a/src/tint/cmd/bench/main_bench.cc
+++ b/src/tint/cmd/bench/main_bench.cc
@@ -109,7 +109,7 @@
             }
             auto result = tint::wgsl::writer::Generate(program, {});
             if (!result) {
-                return Error{result.Failure()};
+                return Error{result.Failure().reason.str()};
             }
             return tint::Source::File(path, result->wgsl);
         }
diff --git a/src/tint/cmd/common/BUILD.bazel b/src/tint/cmd/common/BUILD.bazel
index 7cf4691..5ff1ba3 100644
--- a/src/tint/cmd/common/BUILD.bazel
+++ b/src/tint/cmd/common/BUILD.bazel
@@ -38,6 +38,7 @@
     "//src/tint/api/options",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/spirv/reader/common",
     "//src/tint/lang/wgsl",
diff --git a/src/tint/cmd/common/BUILD.cmake b/src/tint/cmd/common/BUILD.cmake
index a10c867..7bd7799 100644
--- a/src/tint/cmd/common/BUILD.cmake
+++ b/src/tint/cmd/common/BUILD.cmake
@@ -37,6 +37,7 @@
   tint_api_options
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_spirv_reader_common
   tint_lang_wgsl
diff --git a/src/tint/cmd/common/BUILD.gn b/src/tint/cmd/common/BUILD.gn
index b66d0ba..5bca6c4 100644
--- a/src/tint/cmd/common/BUILD.gn
+++ b/src/tint/cmd/common/BUILD.gn
@@ -41,6 +41,7 @@
     "${tint_src_dir}/api/options",
     "${tint_src_dir}/lang/core",
     "${tint_src_dir}/lang/core/constant",
+    "${tint_src_dir}/lang/core/ir",
     "${tint_src_dir}/lang/core/type",
     "${tint_src_dir}/lang/spirv/reader/common",
     "${tint_src_dir}/lang/wgsl",
diff --git a/src/tint/cmd/test/BUILD.bazel b/src/tint/cmd/test/BUILD.bazel
index d57721c..60aebb2 100644
--- a/src/tint/cmd/test/BUILD.bazel
+++ b/src/tint/cmd/test/BUILD.bazel
@@ -43,12 +43,14 @@
     "//src/tint/lang/wgsl/helpers:test",
     "//src/tint/lang/wgsl/inspector:test",
     "//src/tint/lang/wgsl/program:test",
+    "//src/tint/lang/wgsl/reader/lower:test",
     "//src/tint/lang/wgsl/reader/parser:test",
     "//src/tint/lang/wgsl/reader/program_to_ir:test",
     "//src/tint/lang/wgsl/resolver:test",
     "//src/tint/lang/wgsl/sem:test",
     "//src/tint/lang/wgsl/writer/ast_printer:test",
     "//src/tint/lang/wgsl/writer/ir_to_program:test",
+    "//src/tint/lang/wgsl/writer/raise:test",
     "//src/tint/lang/wgsl:test",
     "//src/tint/utils/cli:test",
     "//src/tint/utils/command:test",
diff --git a/src/tint/cmd/test/BUILD.cmake b/src/tint/cmd/test/BUILD.cmake
index 006baed..108f7af 100644
--- a/src/tint/cmd/test/BUILD.cmake
+++ b/src/tint/cmd/test/BUILD.cmake
@@ -44,12 +44,14 @@
   tint_lang_wgsl_helpers_test
   tint_lang_wgsl_inspector_test
   tint_lang_wgsl_program_test
+  tint_lang_wgsl_reader_lower_test
   tint_lang_wgsl_reader_parser_test
   tint_lang_wgsl_reader_program_to_ir_test
   tint_lang_wgsl_resolver_test
   tint_lang_wgsl_sem_test
   tint_lang_wgsl_writer_ast_printer_test
   tint_lang_wgsl_writer_ir_to_program_test
+  tint_lang_wgsl_writer_raise_test
   tint_lang_wgsl_test
   tint_utils_cli_test
   tint_utils_command_test
diff --git a/src/tint/cmd/test/BUILD.gn b/src/tint/cmd/test/BUILD.gn
index fd1f9bf..5461cfb 100644
--- a/src/tint/cmd/test/BUILD.gn
+++ b/src/tint/cmd/test/BUILD.gn
@@ -49,12 +49,14 @@
       "${tint_src_dir}/lang/wgsl/helpers:unittests",
       "${tint_src_dir}/lang/wgsl/inspector:unittests",
       "${tint_src_dir}/lang/wgsl/program:unittests",
+      "${tint_src_dir}/lang/wgsl/reader/lower:unittests",
       "${tint_src_dir}/lang/wgsl/reader/parser:unittests",
       "${tint_src_dir}/lang/wgsl/reader/program_to_ir:unittests",
       "${tint_src_dir}/lang/wgsl/resolver:unittests",
       "${tint_src_dir}/lang/wgsl/sem:unittests",
       "${tint_src_dir}/lang/wgsl/writer/ast_printer:unittests",
       "${tint_src_dir}/lang/wgsl/writer/ir_to_program:unittests",
+      "${tint_src_dir}/lang/wgsl/writer/raise:unittests",
       "${tint_src_dir}/utils/cli:unittests",
       "${tint_src_dir}/utils/command:unittests",
       "${tint_src_dir}/utils/containers:unittests",
diff --git a/src/tint/cmd/tint/main.cc b/src/tint/cmd/tint/main.cc
index c943041..1a48a8d 100644
--- a/src/tint/cmd/tint/main.cc
+++ b/src/tint/cmd/tint/main.cc
@@ -400,9 +400,9 @@
         options.ShowHelp(std::cout);
     };
 
-    auto result = options.Parse(std::cerr, arguments);
+    auto result = options.Parse(arguments);
     if (!result) {
-        std::cerr << std::endl;
+        std::cerr << result.Failure() << std::endl;
         show_usage();
         return false;
     }
diff --git a/src/tint/fuzzers/generate_spirv_corpus.py b/src/tint/fuzzers/generate_spirv_corpus.py
index c608901..6a865e0 100644
--- a/src/tint/fuzzers/generate_spirv_corpus.py
+++ b/src/tint/fuzzers/generate_spirv_corpus.py
@@ -81,7 +81,7 @@
 
     if num_errors > max_tolerated_errors:
         print("Too many (" + str(num_errors) +
-              ") errors occured while generating the SPIR-V corpus.")
+              ") errors occurred while generating the SPIR-V corpus.")
         print(logged_errors)
         return 1
 
diff --git a/src/tint/lang/core/BUILD.bazel b/src/tint/lang/core/BUILD.bazel
index be870fb..8b4f3e9 100644
--- a/src/tint/lang/core/BUILD.bazel
+++ b/src/tint/lang/core/BUILD.bazel
@@ -59,10 +59,14 @@
     "unary_op.h",
   ],
   deps = [
+    "//src/tint/utils/containers",
+    "//src/tint/utils/diagnostic",
     "//src/tint/utils/ice",
     "//src/tint/utils/macros",
+    "//src/tint/utils/math",
     "//src/tint/utils/memory",
     "//src/tint/utils/result",
+    "//src/tint/utils/rtti",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
   ],
diff --git a/src/tint/lang/core/BUILD.cmake b/src/tint/lang/core/BUILD.cmake
index 8c85ad5..ec43104 100644
--- a/src/tint/lang/core/BUILD.cmake
+++ b/src/tint/lang/core/BUILD.cmake
@@ -63,10 +63,14 @@
 )
 
 tint_target_add_dependencies(tint_lang_core lib
+  tint_utils_containers
+  tint_utils_diagnostic
   tint_utils_ice
   tint_utils_macros
+  tint_utils_math
   tint_utils_memory
   tint_utils_result
+  tint_utils_rtti
   tint_utils_text
   tint_utils_traits
 )
diff --git a/src/tint/lang/core/BUILD.gn b/src/tint/lang/core/BUILD.gn
index 59a0588..78c9e73 100644
--- a/src/tint/lang/core/BUILD.gn
+++ b/src/tint/lang/core/BUILD.gn
@@ -62,10 +62,14 @@
     "unary_op.h",
   ]
   deps = [
+    "${tint_src_dir}/utils/containers",
+    "${tint_src_dir}/utils/diagnostic",
     "${tint_src_dir}/utils/ice",
     "${tint_src_dir}/utils/macros",
+    "${tint_src_dir}/utils/math",
     "${tint_src_dir}/utils/memory",
     "${tint_src_dir}/utils/result",
+    "${tint_src_dir}/utils/rtti",
     "${tint_src_dir}/utils/text",
     "${tint_src_dir}/utils/traits",
   ]
diff --git a/src/tint/lang/core/builtin_fn.cc.tmpl b/src/tint/lang/core/builtin_fn.cc.tmpl
index 5a0d100..0a4ba6d 100644
--- a/src/tint/lang/core/builtin_fn.cc.tmpl
+++ b/src/tint/lang/core/builtin_fn.cc.tmpl
@@ -1,6 +1,6 @@
 {{- /*
 --------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate builtin_function.cc
+Template file for use with tools/src/cmd/gen to generate builtin_fn.cc
 
 To update the generated file, run:
     ./tools/run gen
diff --git a/src/tint/lang/core/builtin_fn.h.tmpl b/src/tint/lang/core/builtin_fn.h.tmpl
index 3a10674..d5198fa 100644
--- a/src/tint/lang/core/builtin_fn.h.tmpl
+++ b/src/tint/lang/core/builtin_fn.h.tmpl
@@ -1,6 +1,6 @@
 {{- /*
 --------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate builtin_function.h
+Template file for use with tools/src/cmd/gen to generate builtin_fn.h
 
 To update the generated file, run:
     ./tools/run gen
diff --git a/src/tint/lang/core/constant/BUILD.bazel b/src/tint/lang/core/constant/BUILD.bazel
index 402a7e3..6b5ca7b 100644
--- a/src/tint/lang/core/constant/BUILD.bazel
+++ b/src/tint/lang/core/constant/BUILD.bazel
@@ -89,6 +89,7 @@
     "//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/core/type:test",
     "//src/tint/lang/wgsl",
diff --git a/src/tint/lang/core/constant/BUILD.cmake b/src/tint/lang/core/constant/BUILD.cmake
index d3829a2..5e1666d 100644
--- a/src/tint/lang/core/constant/BUILD.cmake
+++ b/src/tint/lang/core/constant/BUILD.cmake
@@ -88,6 +88,7 @@
   tint_lang_core
   tint_lang_core_constant
   tint_lang_core_intrinsic
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_core_type_test
   tint_lang_wgsl
diff --git a/src/tint/lang/core/constant/BUILD.gn b/src/tint/lang/core/constant/BUILD.gn
index 39ae73f..4d5ccd8 100644
--- a/src/tint/lang/core/constant/BUILD.gn
+++ b/src/tint/lang/core/constant/BUILD.gn
@@ -91,6 +91,7 @@
       "${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/core/type:unittests",
       "${tint_src_dir}/lang/wgsl",
diff --git a/src/tint/lang/core/constant/eval.cc b/src/tint/lang/core/constant/eval.cc
index 74cc427..111629e 100644
--- a/src/tint/lang/core/constant/eval.cc
+++ b/src/tint/lang/core/constant/eval.cc
@@ -486,7 +486,6 @@
     for (uint32_t i = 0; i < n; i++) {
         if (auto el = TransformElements(mgr, composite_el_ty, f, index + i, cs->Index(i)...)) {
             els.Push(el.Get());
-
         } else {
             return el.Failure();
         }
@@ -515,7 +514,6 @@
     for (uint32_t i = 0; i < n; i++) {
         if (auto el = TransformUnaryElements(mgr, composite_el_ty, f, c0->Index(i))) {
             els.Push(el.Get());
-
         } else {
             return el.Failure();
         }
@@ -548,7 +546,6 @@
         if (auto el =
                 TransformBinaryElements(mgr, composite_el_ty, f, c0->Index(i), c1->Index(i))) {
             els.Push(el.Get());
-
         } else {
             return el.Failure();
         }
@@ -616,7 +613,6 @@
         if (auto el = TransformTernaryElements(mgr, composite_el_ty, f, c0->Index(i), c1->Index(i),
                                                c2->Index(i))) {
             els.Push(el.Get());
-
         } else {
             return el.Failure();
         }
@@ -639,7 +635,7 @@
             if (use_runtime_semantics_) {
                 return mgr.Zero(t);
             } else {
-                return tint::Failure;
+                return error;
             }
         }
     }
@@ -647,7 +643,7 @@
 }
 
 template <typename NumberT>
-tint::Result<NumberT> Eval::Add(const Source& source, NumberT a, NumberT b) {
+tint::Result<NumberT, Eval::Error> Eval::Add(const Source& source, NumberT a, NumberT b) {
     NumberT result;
     if constexpr (IsAbstract<NumberT> || IsFloatingPoint<NumberT>) {
         if (auto r = CheckedAdd(a, b)) {
@@ -657,7 +653,7 @@
             if (use_runtime_semantics_) {
                 return NumberT{0};
             } else {
-                return tint::Failure;
+                return error;
             }
         }
     } else {
@@ -677,7 +673,7 @@
 }
 
 template <typename NumberT>
-tint::Result<NumberT> Eval::Sub(const Source& source, NumberT a, NumberT b) {
+tint::Result<NumberT, Eval::Error> Eval::Sub(const Source& source, NumberT a, NumberT b) {
     NumberT result;
     if constexpr (IsAbstract<NumberT> || IsFloatingPoint<NumberT>) {
         if (auto r = CheckedSub(a, b)) {
@@ -687,7 +683,7 @@
             if (use_runtime_semantics_) {
                 return NumberT{0};
             } else {
-                return tint::Failure;
+                return error;
             }
         }
     } else {
@@ -707,7 +703,7 @@
 }
 
 template <typename NumberT>
-tint::Result<NumberT> Eval::Mul(const Source& source, NumberT a, NumberT b) {
+tint::Result<NumberT, Eval::Error> Eval::Mul(const Source& source, NumberT a, NumberT b) {
     using T = UnwrapNumber<NumberT>;
     NumberT result;
     if constexpr (IsAbstract<NumberT> || IsFloatingPoint<NumberT>) {
@@ -718,7 +714,7 @@
             if (use_runtime_semantics_) {
                 return NumberT{0};
             } else {
-                return tint::Failure;
+                return error;
             }
         }
     } else {
@@ -737,7 +733,7 @@
 }
 
 template <typename NumberT>
-tint::Result<NumberT> Eval::Div(const Source& source, NumberT a, NumberT b) {
+tint::Result<NumberT, Eval::Error> Eval::Div(const Source& source, NumberT a, NumberT b) {
     NumberT result;
     if constexpr (IsAbstract<NumberT> || IsFloatingPoint<NumberT>) {
         if (auto r = CheckedDiv(a, b)) {
@@ -747,7 +743,7 @@
             if (use_runtime_semantics_) {
                 return a;
             } else {
-                return tint::Failure;
+                return error;
             }
         }
     } else {
@@ -760,7 +756,7 @@
             if (use_runtime_semantics_) {
                 return a;
             } else {
-                return tint::Failure;
+                return error;
             }
         }
         if constexpr (std::is_signed_v<T>) {
@@ -771,7 +767,7 @@
                 if (use_runtime_semantics_) {
                     return a;
                 } else {
-                    return tint::Failure;
+                    return error;
                 }
             }
         }
@@ -781,7 +777,7 @@
 }
 
 template <typename NumberT>
-tint::Result<NumberT> Eval::Mod(const Source& source, NumberT a, NumberT b) {
+tint::Result<NumberT, Eval::Error> Eval::Mod(const Source& source, NumberT a, NumberT b) {
     NumberT result;
     if constexpr (IsAbstract<NumberT> || IsFloatingPoint<NumberT>) {
         if (auto r = CheckedMod(a, b)) {
@@ -791,7 +787,7 @@
             if (use_runtime_semantics_) {
                 return NumberT{0};
             } else {
-                return tint::Failure;
+                return error;
             }
         }
     } else {
@@ -804,7 +800,7 @@
             if (use_runtime_semantics_) {
                 return NumberT{0};
             } else {
-                return tint::Failure;
+                return error;
             }
         }
         if constexpr (std::is_signed_v<T>) {
@@ -815,7 +811,7 @@
                 if (use_runtime_semantics_) {
                     return NumberT{0};
                 } else {
-                    return tint::Failure;
+                    return error;
                 }
             }
         }
@@ -825,100 +821,104 @@
 }
 
 template <typename NumberT>
-tint::Result<NumberT> Eval::Dot2(const Source& source,
-                                 NumberT a1,
-                                 NumberT a2,
-                                 NumberT b1,
-                                 NumberT b2) {
+tint::Result<NumberT, Eval::Error> Eval::Dot2(const Source& source,
+                                              NumberT a1,
+                                              NumberT a2,
+                                              NumberT b1,
+                                              NumberT b2) {
     auto r1 = Mul(source, a1, b1);
     if (!r1) {
-        return tint::Failure;
+        return error;
     }
     auto r2 = Mul(source, a2, b2);
     if (!r2) {
-        return tint::Failure;
+        return error;
     }
     auto r = Add(source, r1.Get(), r2.Get());
     if (!r) {
-        return tint::Failure;
+        return error;
     }
     return r;
 }
 
 template <typename NumberT>
-tint::Result<NumberT> Eval::Dot3(const Source& source,
-                                 NumberT a1,
-                                 NumberT a2,
-                                 NumberT a3,
-                                 NumberT b1,
-                                 NumberT b2,
-                                 NumberT b3) {
+tint::Result<NumberT, Eval::Error> Eval::Dot3(const Source& source,
+                                              NumberT a1,
+                                              NumberT a2,
+                                              NumberT a3,
+                                              NumberT b1,
+                                              NumberT b2,
+                                              NumberT b3) {
     auto r1 = Mul(source, a1, b1);
     if (!r1) {
-        return tint::Failure;
+        return error;
     }
     auto r2 = Mul(source, a2, b2);
     if (!r2) {
-        return tint::Failure;
+        return error;
     }
     auto r3 = Mul(source, a3, b3);
     if (!r3) {
-        return tint::Failure;
+        return error;
     }
     auto r = Add(source, r1.Get(), r2.Get());
     if (!r) {
-        return tint::Failure;
+        return error;
     }
     r = Add(source, r.Get(), r3.Get());
     if (!r) {
-        return tint::Failure;
+        return error;
     }
     return r;
 }
 
 template <typename NumberT>
-tint::Result<NumberT> Eval::Dot4(const Source& source,
-                                 NumberT a1,
-                                 NumberT a2,
-                                 NumberT a3,
-                                 NumberT a4,
-                                 NumberT b1,
-                                 NumberT b2,
-                                 NumberT b3,
-                                 NumberT b4) {
+tint::Result<NumberT, Eval::Error> Eval::Dot4(const Source& source,
+                                              NumberT a1,
+                                              NumberT a2,
+                                              NumberT a3,
+                                              NumberT a4,
+                                              NumberT b1,
+                                              NumberT b2,
+                                              NumberT b3,
+                                              NumberT b4) {
     auto r1 = Mul(source, a1, b1);
     if (!r1) {
-        return tint::Failure;
+        return error;
     }
     auto r2 = Mul(source, a2, b2);
     if (!r2) {
-        return tint::Failure;
+        return error;
     }
     auto r3 = Mul(source, a3, b3);
     if (!r3) {
-        return tint::Failure;
+        return error;
     }
     auto r4 = Mul(source, a4, b4);
     if (!r4) {
-        return tint::Failure;
+        return error;
     }
     auto r = Add(source, r1.Get(), r2.Get());
     if (!r) {
-        return tint::Failure;
+        return error;
     }
     r = Add(source, r.Get(), r3.Get());
     if (!r) {
-        return tint::Failure;
+        return error;
     }
     r = Add(source, r.Get(), r4.Get());
     if (!r) {
-        return tint::Failure;
+        return error;
     }
     return r;
 }
 
 template <typename NumberT>
-tint::Result<NumberT> Eval::Det2(const Source& source, NumberT a, NumberT b, NumberT c, NumberT d) {
+tint::Result<NumberT, Eval::Error> Eval::Det2(const Source& source,
+                                              NumberT a,
+                                              NumberT b,
+                                              NumberT c,
+                                              NumberT d) {
     // | a c |
     // | b d |
     //
@@ -928,30 +928,30 @@
 
     auto r1 = Mul(source, a, d);
     if (!r1) {
-        return tint::Failure;
+        return error;
     }
     auto r2 = Mul(source, c, b);
     if (!r2) {
-        return tint::Failure;
+        return error;
     }
     auto r = Sub(source, r1.Get(), r2.Get());
     if (!r) {
-        return tint::Failure;
+        return error;
     }
     return r;
 }
 
 template <typename NumberT>
-tint::Result<NumberT> Eval::Det3(const Source& source,
-                                 NumberT a,
-                                 NumberT b,
-                                 NumberT c,
-                                 NumberT d,
-                                 NumberT e,
-                                 NumberT f,
-                                 NumberT g,
-                                 NumberT h,
-                                 NumberT i) {
+tint::Result<NumberT, Eval::Error> Eval::Det3(const Source& source,
+                                              NumberT a,
+                                              NumberT b,
+                                              NumberT c,
+                                              NumberT d,
+                                              NumberT e,
+                                              NumberT f,
+                                              NumberT g,
+                                              NumberT h,
+                                              NumberT i) {
     // | a d g |
     // | b e h |
     // | c f i |
@@ -963,53 +963,53 @@
 
     auto det1 = Det2(source, e, f, h, i);
     if (!det1) {
-        return tint::Failure;
+        return error;
     }
     auto a_det1 = Mul(source, a, det1.Get());
     if (!a_det1) {
-        return tint::Failure;
+        return error;
     }
     auto det2 = Det2(source, b, c, h, i);
     if (!det2) {
-        return tint::Failure;
+        return error;
     }
     auto d_det2 = Mul(source, d, det2.Get());
     if (!d_det2) {
-        return tint::Failure;
+        return error;
     }
     auto det3 = Det2(source, b, c, e, f);
     if (!det3) {
-        return tint::Failure;
+        return error;
     }
     auto g_det3 = Mul(source, g, det3.Get());
     if (!g_det3) {
-        return tint::Failure;
+        return error;
     }
     auto r = Sub(source, a_det1.Get(), d_det2.Get());
     if (!r) {
-        return tint::Failure;
+        return error;
     }
     return Add(source, r.Get(), g_det3.Get());
 }
 
 template <typename NumberT>
-tint::Result<NumberT> Eval::Det4(const Source& source,
-                                 NumberT a,
-                                 NumberT b,
-                                 NumberT c,
-                                 NumberT d,
-                                 NumberT e,
-                                 NumberT f,
-                                 NumberT g,
-                                 NumberT h,
-                                 NumberT i,
-                                 NumberT j,
-                                 NumberT k,
-                                 NumberT l,
-                                 NumberT m,
-                                 NumberT n,
-                                 NumberT o,
-                                 NumberT p) {
+tint::Result<NumberT, Eval::Error> Eval::Det4(const Source& source,
+                                              NumberT a,
+                                              NumberT b,
+                                              NumberT c,
+                                              NumberT d,
+                                              NumberT e,
+                                              NumberT f,
+                                              NumberT g,
+                                              NumberT h,
+                                              NumberT i,
+                                              NumberT j,
+                                              NumberT k,
+                                              NumberT l,
+                                              NumberT m,
+                                              NumberT n,
+                                              NumberT o,
+                                              NumberT p) {
     // | a e i m |
     // | b f j n |
     // | c g k o |
@@ -1023,55 +1023,55 @@
 
     auto det1 = Det3(source, f, g, h, j, k, l, n, o, p);
     if (!det1) {
-        return tint::Failure;
+        return error;
     }
     auto a_det1 = Mul(source, a, det1.Get());
     if (!a_det1) {
-        return tint::Failure;
+        return error;
     }
     auto det2 = Det3(source, b, c, d, j, k, l, n, o, p);
     if (!det2) {
-        return tint::Failure;
+        return error;
     }
     auto e_det2 = Mul(source, e, det2.Get());
     if (!e_det2) {
-        return tint::Failure;
+        return error;
     }
     auto det3 = Det3(source, b, c, d, f, g, h, n, o, p);
     if (!det3) {
-        return tint::Failure;
+        return error;
     }
     auto i_det3 = Mul(source, i, det3.Get());
     if (!i_det3) {
-        return tint::Failure;
+        return error;
     }
     auto det4 = Det3(source, b, c, d, f, g, h, j, k, l);
     if (!det4) {
-        return tint::Failure;
+        return error;
     }
     auto m_det4 = Mul(source, m, det4.Get());
     if (!m_det4) {
-        return tint::Failure;
+        return error;
     }
     auto r = Sub(source, a_det1.Get(), e_det2.Get());
     if (!r) {
-        return tint::Failure;
+        return error;
     }
     r = Add(source, r.Get(), i_det3.Get());
     if (!r) {
-        return tint::Failure;
+        return error;
     }
     return Sub(source, r.Get(), m_det4.Get());
 }
 
 template <typename NumberT>
-tint::Result<NumberT> Eval::Sqrt(const Source& source, NumberT v) {
+tint::Result<NumberT, Eval::Error> Eval::Sqrt(const Source& source, NumberT v) {
     if (v < NumberT(0)) {
         AddError("sqrt must be called with a value >= 0", source);
         if (use_runtime_semantics_) {
             return NumberT{0};
         } else {
-            return tint::Failure;
+            return error;
         }
     }
     return NumberT{std::sqrt(v)};
@@ -1082,18 +1082,21 @@
         if (auto r = Sqrt(source, v)) {
             return CreateScalar(source, elem_ty, r.Get());
         }
-        return tint::Failure;
+        return error;
     };
 }
 
 template <typename NumberT>
-tint::Result<NumberT> Eval::Clamp(const Source& source, NumberT e, NumberT low, NumberT high) {
+tint::Result<NumberT, Eval::Error> Eval::Clamp(const Source& source,
+                                               NumberT e,
+                                               NumberT low,
+                                               NumberT high) {
     if (low > high) {
         StringStream ss;
         ss << "clamp called with 'low' (" << low << ") greater than 'high' (" << high << ")";
         AddError(ss.str(), source);
         if (!use_runtime_semantics_) {
-            return tint::Failure;
+            return error;
         }
     }
     return NumberT{std::min(std::max(e, low), high)};
@@ -1104,7 +1107,7 @@
         if (auto r = Clamp(source, e, low, high)) {
             return CreateScalar(source, elem_ty, r.Get());
         }
-        return tint::Failure;
+        return error;
     };
 }
 
@@ -1113,7 +1116,7 @@
         if (auto r = Add(source, a1, a2)) {
             return CreateScalar(source, elem_ty, r.Get());
         }
-        return tint::Failure;
+        return error;
     };
 }
 
@@ -1122,7 +1125,7 @@
         if (auto r = Sub(source, a1, a2)) {
             return CreateScalar(source, elem_ty, r.Get());
         }
-        return tint::Failure;
+        return error;
     };
 }
 
@@ -1131,7 +1134,7 @@
         if (auto r = Mul(source, a1, a2)) {
             return CreateScalar(source, elem_ty, r.Get());
         }
-        return tint::Failure;
+        return error;
     };
 }
 
@@ -1140,7 +1143,7 @@
         if (auto r = Div(source, a1, a2)) {
             return CreateScalar(source, elem_ty, r.Get());
         }
-        return tint::Failure;
+        return error;
     };
 }
 
@@ -1149,7 +1152,7 @@
         if (auto r = Mod(source, a1, a2)) {
             return CreateScalar(source, elem_ty, r.Get());
         }
-        return tint::Failure;
+        return error;
     };
 }
 
@@ -1158,7 +1161,7 @@
         if (auto r = Dot2(source, a1, a2, b1, b2)) {
             return CreateScalar(source, elem_ty, r.Get());
         }
-        return tint::Failure;
+        return error;
     };
 }
 
@@ -1167,7 +1170,7 @@
         if (auto r = Dot3(source, a1, a2, a3, b1, b2, b3)) {
             return CreateScalar(source, elem_ty, r.Get());
         }
-        return tint::Failure;
+        return error;
     };
 }
 
@@ -1177,7 +1180,7 @@
         if (auto r = Dot4(source, a1, a2, a3, a4, b1, b2, b3, b4)) {
             return CreateScalar(source, elem_ty, r.Get());
         }
-        return tint::Failure;
+        return error;
     };
 }
 
@@ -1203,7 +1206,7 @@
                 v2->Index(0), v2->Index(1), v2->Index(2), v2->Index(3));
     }
     TINT_ICE() << "Expected vector";
-    return Failure;
+    return error;
 }
 
 Eval::Result Eval::Length(const Source& source, const core::type::Type* ty, const Value* c0) {
@@ -1220,7 +1223,7 @@
     // Evaluates to sqrt(e[0]^2 + e[1]^2 + ...) if T is a vector type.
     auto d = Dot(source, c0, c0);
     if (!d) {
-        return tint::Failure;
+        return error;
     }
     return Dispatch_fa_f32_f16(SqrtFunc(source, ty), d.Get());
 }
@@ -1250,7 +1253,7 @@
         if (auto r = Det2(source, a, b, c, d)) {
             return CreateScalar(source, elem_ty, r.Get());
         }
-        return tint::Failure;
+        return error;
     };
 }
 
@@ -1260,7 +1263,7 @@
         if (auto r = Det3(source, a, b, c, d, e, f, g, h, i)) {
             return CreateScalar(source, elem_ty, r.Get());
         }
-        return tint::Failure;
+        return error;
     };
 }
 
@@ -1270,7 +1273,7 @@
         if (auto r = Det4(source, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)) {
             return CreateScalar(source, elem_ty, r.Get());
         }
-        return tint::Failure;
+        return error;
     };
 }
 
@@ -1391,7 +1394,7 @@
         if (use_runtime_semantics_) {
             return mgr.Zero(el.type);
         } else {
-            return tint::Failure;
+            return error;
         }
     }
 
@@ -1471,7 +1474,7 @@
     Vector<const Value*, 4> els;
 
     // Reinterprets the buffer bits as destination element and push the result into the vector.
-    // Return false if an error occured, otherwise return true.
+    // Return false if an error occurred, otherwise return true.
     auto push_dst_element = [&](size_t offset) -> bool {
         uint32_t v;
         if (dst_el_ty->Size() == 4) {
@@ -1519,7 +1522,7 @@
     TINT_ASSERT((buffer.Length() == total_bitwidth));
     for (size_t i = 0; i < dst_count; i++) {
         if (!push_dst_element(i * dst_el_ty->Size())) {
-            return tint::Failure;
+            return error;
         }
     }
 
@@ -1642,7 +1645,7 @@
     for (size_t i = 0; i < mat_ty->rows(); ++i) {
         auto r = dot(args[0], i, args[1]);  // matrix row i * vector
         if (!r) {
-            return tint::Failure;
+            return error;
         }
         result.Push(r.Get());
     }
@@ -1692,7 +1695,7 @@
     for (size_t i = 0; i < mat_ty->columns(); ++i) {
         auto r = dot(args[0], args[1], i);  // vector * matrix col i
         if (!r) {
-            return tint::Failure;
+            return error;
         }
         result.Push(r.Get());
     }
@@ -1751,7 +1754,7 @@
         for (size_t r = 0; r < mat1_ty->rows(); ++r) {
             auto v = dot(mat1, r, mat2, c);  // mat1 row r * mat2 col c
             if (!v) {
-                return tint::Failure;
+                return error;
             }
             col_vec.Push(v.Get());  // mat1 row r * mat2 col c
         }
@@ -1955,7 +1958,7 @@
                     if ((e1u & mask) != 0 && (e1u & mask) != mask) {
                         AddError("shift left operation results in sign change", source);
                         if (!use_runtime_semantics_) {
-                            return tint::Failure;
+                            return error;
                         }
                     }
                 } else {
@@ -1963,7 +1966,7 @@
                     if (e1 != 0) {
                         AddError(OverflowErrorMessage(e1, "<<", e2), source);
                         if (!use_runtime_semantics_) {
-                            return tint::Failure;
+                            return error;
                         }
                     }
 
@@ -1983,7 +1986,7 @@
                     if (use_runtime_semantics_) {
                         e2u = e2u % bit_width;
                     } else {
-                        return tint::Failure;
+                        return error;
                     }
                 }
 
@@ -1995,7 +1998,7 @@
                     if ((e1u & mask) != 0 && (e1u & mask) != mask) {
                         AddError("shift left operation results in sign change", source);
                         if (!use_runtime_semantics_) {
-                            return tint::Failure;
+                            return error;
                         }
                     }
                 } else {
@@ -2007,7 +2010,7 @@
                         if ((e1u & mask) != 0) {
                             AddError(OverflowErrorMessage(e1, "<<", e2), source);
                             if (!use_runtime_semantics_) {
-                                return tint::Failure;
+                                return error;
                             }
                         }
                     }
@@ -2023,7 +2026,7 @@
 
     if (TINT_UNLIKELY(!args[1]->Type()->DeepestElement()->Is<core::type::U32>())) {
         TINT_ICE() << "Element type of rhs of ShiftLeft must be a u32";
-        return Failure;
+        return error;
     }
 
     return TransformBinaryElements(mgr, ty, transform, args[0], args[1]);
@@ -2073,7 +2076,7 @@
                     if (use_runtime_semantics_) {
                         e2u = e2u % bit_width;
                     } else {
-                        return tint::Failure;
+                        return error;
                     }
                 }
 
@@ -2090,7 +2093,7 @@
 
     if (TINT_UNLIKELY(!args[1]->Type()->DeepestElement()->Is<core::type::U32>())) {
         TINT_ICE() << "Element type of rhs of ShiftLeft must be a u32";
-        return Failure;
+        return error;
     }
 
     return TransformBinaryElements(mgr, ty, transform, args[0], args[1]);
@@ -2133,7 +2136,7 @@
                 if (use_runtime_semantics_) {
                     return mgr.Zero(c0->Type());
                 } else {
-                    return tint::Failure;
+                    return error;
                 }
             }
             return CreateScalar(source, c0->Type(), NumberT(std::acos(i.value)));
@@ -2154,7 +2157,7 @@
                 if (use_runtime_semantics_) {
                     return mgr.Zero(c0->Type());
                 } else {
-                    return tint::Failure;
+                    return error;
                 }
             }
             return CreateScalar(source, c0->Type(), NumberT(std::acosh(i.value)));
@@ -2189,7 +2192,7 @@
                 if (use_runtime_semantics_) {
                     return mgr.Zero(c0->Type());
                 } else {
-                    return tint::Failure;
+                    return error;
                 }
             }
             return CreateScalar(source, c0->Type(), NumberT(std::asin(i.value)));
@@ -2236,7 +2239,7 @@
                 if (use_runtime_semantics_) {
                     return mgr.Zero(c0->Type());
                 } else {
-                    return tint::Failure;
+                    return error;
                 }
             }
             return CreateScalar(source, c0->Type(), NumberT(std::atanh(i.value)));
@@ -2388,15 +2391,15 @@
 
     auto x = Dispatch_fa_f32_f16(Det2Func(source, elem_ty), u1, u2, v1, v2);
     if (!x) {
-        return tint::Failure;
+        return error;
     }
     auto y = Dispatch_fa_f32_f16(Det2Func(source, elem_ty), v0, v2, u0, u2);
     if (!y) {
-        return tint::Failure;
+        return error;
     }
     auto z = Dispatch_fa_f32_f16(Det2Func(source, elem_ty), u0, u1, v0, v1);
     if (!z) {
-        return tint::Failure;
+        return error;
     }
 
     return mgr.Composite(ty, Vector<const Value*, 3>{x.Get(), y.Get(), z.Get()});
@@ -2414,12 +2417,12 @@
             auto scale = Div(source, NumberT(180), NumberT(pi));
             if (!scale) {
                 AddNote("when calculating degrees", source);
-                return tint::Failure;
+                return error;
             }
             auto result = Mul(source, e, scale.Get());
             if (!result) {
                 AddNote("when calculating degrees", source);
-                return tint::Failure;
+                return error;
             }
             return CreateScalar(source, c0->Type(), result.Get());
         };
@@ -2455,7 +2458,7 @@
                                            me(0, 3), me(1, 3), me(2, 3), me(3, 3));
         }
         TINT_ICE() << "Unexpected number of matrix rows";
-        return Failure;
+        return error;
     };
     auto r = calculate();
     if (!r) {
@@ -2469,7 +2472,7 @@
                             const Source& source) {
     auto err = [&]() -> Eval::Result {
         AddNote("when calculating distance", source);
-        return tint::Failure;
+        return error;
     };
 
     auto minus = Minus(args[0]->Type(), args, source);
@@ -2506,7 +2509,7 @@
                 if (use_runtime_semantics_) {
                     return mgr.Zero(c0->Type());
                 } else {
-                    return tint::Failure;
+                    return error;
                 }
             }
             return CreateScalar(source, c0->Type(), val);
@@ -2528,7 +2531,7 @@
                 if (use_runtime_semantics_) {
                     return mgr.Zero(c0->Type());
                 } else {
-                    return tint::Failure;
+                    return error;
                 }
             }
             return CreateScalar(source, c0->Type(), val);
@@ -2565,7 +2568,7 @@
                     o = std::min(o, w);
                     c = std::min(c, w - o);
                 } else {
-                    return tint::Failure;
+                    return error;
                 }
             }
 
@@ -2608,7 +2611,7 @@
     auto r = Dot(source, e2, e3);
     if (!r) {
         AddNote("when calculating faceForward", source);
-        return tint::Failure;
+        return error;
     }
     auto is_negative = [](auto v) { return v < 0; };
     if (Dispatch_fa_f32_f16(is_negative, r.Get())) {
@@ -2706,7 +2709,7 @@
         auto create = [&](auto e1, auto e2, auto e3) -> Eval::Result {
             auto err_msg = [&] {
                 AddNote("when calculating fma", source);
-                return tint::Failure;
+                return error;
             };
 
             auto mul = Mul(source, e1, e2);
@@ -2775,7 +2778,7 @@
             [&](Default) {
                 TINT_ICE() << "unhandled element type for frexp() const-eval: "
                            << s->Type()->FriendlyName();
-                return FractExp{Failure, Failure};
+                return FractExp{error, error};
             });
     };
 
@@ -2785,7 +2788,7 @@
         for (uint32_t i = 0; i < vec->Width(); i++) {
             auto fe = scalar(arg->Index(i));
             if (!fe.fract || !fe.exp) {
-                return tint::Failure;
+                return error;
             }
             fract_els.Push(fe.fract.Get());
             exp_els.Push(fe.exp.Get());
@@ -2799,7 +2802,7 @@
     } else {
         auto fe = scalar(arg);
         if (!fe.fract || !fe.exp) {
-            return tint::Failure;
+            return error;
         }
         return mgr.Composite(ty, Vector<const Value*, 2>{
                                      fe.fract.Get(),
@@ -2836,7 +2839,7 @@
                     o = std::min(o, w);
                     c = std::min(c, w - o);
                 } else {
-                    return tint::Failure;
+                    return error;
                 }
             }
 
@@ -2877,13 +2880,13 @@
                 if (use_runtime_semantics_) {
                     return mgr.Zero(c0->Type());
                 } else {
-                    return tint::Failure;
+                    return error;
                 }
             }
 
             auto err = [&] {
                 AddNote("when calculating inverseSqrt", source);
-                return tint::Failure;
+                return error;
             };
 
             auto s = Sqrt(source, e);
@@ -2934,7 +2937,7 @@
                 if (use_runtime_semantics_) {
                     return mgr.Zero(c1->Type());
                 } else {
-                    return tint::Failure;
+                    return error;
                 }
             }
 
@@ -2970,7 +2973,7 @@
                 if (use_runtime_semantics_) {
                     return mgr.Zero(c0->Type());
                 } else {
-                    return tint::Failure;
+                    return error;
                 }
             }
             return CreateScalar(source, c0->Type(), NumberT(std::log(v)));
@@ -2991,7 +2994,7 @@
                 if (use_runtime_semantics_) {
                     return mgr.Zero(c0->Type());
                 } else {
-                    return tint::Failure;
+                    return error;
                 }
             }
             return CreateScalar(source, c0->Type(), NumberT(std::log2(v)));
@@ -3043,19 +3046,19 @@
             // float precision loss when e1 and e2 significantly differ in magnitude.
             auto one_sub_e3 = Sub(source, NumberT{1}, e3);
             if (!one_sub_e3) {
-                return tint::Failure;
+                return error;
             }
             auto e1_mul_one_sub_e3 = Mul(source, e1, one_sub_e3.Get());
             if (!e1_mul_one_sub_e3) {
-                return tint::Failure;
+                return error;
             }
             auto e2_mul_e3 = Mul(source, e2, e3);
             if (!e2_mul_e3) {
-                return tint::Failure;
+                return error;
             }
             auto r = Add(source, e1_mul_one_sub_e3.Get(), e2_mul_e3.Get());
             if (!r) {
-                return tint::Failure;
+                return error;
             }
             return CreateScalar(source, c0->Type(), r.Get());
         };
@@ -3089,13 +3092,13 @@
     if (auto fract = TransformUnaryElements(mgr, args[0]->Type(), transform_fract, args[0])) {
         fields.Push(fract.Get());
     } else {
-        return tint::Failure;
+        return error;
     }
 
     if (auto whole = TransformUnaryElements(mgr, args[0]->Type(), transform_whole, args[0])) {
         fields.Push(whole.Get());
     } else {
-        return tint::Failure;
+        return error;
     }
 
     return mgr.Composite(ty, std::move(fields));
@@ -3108,7 +3111,7 @@
     auto len = Length(source, len_ty, args[0]);
     if (!len) {
         AddNote("when calculating normalize", source);
-        return tint::Failure;
+        return error;
     }
     auto* v = len.Get();
     if (v->AllZero()) {
@@ -3116,7 +3119,7 @@
         if (use_runtime_semantics_) {
             return mgr.Zero(ty);
         } else {
-            return tint::Failure;
+            return error;
         }
     }
     return Divide(ty, Vector{args[0], v}, source);
@@ -3125,29 +3128,29 @@
 Eval::Result Eval::pack2x16float(const core::type::Type* ty,
                                  VectorRef<const Value*> args,
                                  const Source& source) {
-    auto convert = [&](f32 val) -> tint::Result<uint32_t> {
+    auto convert = [&](f32 val) -> tint::Result<uint32_t, Error> {
         auto conv = CheckedConvert<f16>(val);
         if (!conv) {
             AddError(OverflowErrorMessage(val, "f16"), source);
             if (use_runtime_semantics_) {
                 return 0;
             } else {
-                return tint::Failure;
+                return error;
             }
         }
         uint16_t v = conv.Get().BitsRepresentation();
-        return tint::Result<uint32_t>{v};
+        return tint::Result<uint32_t, Error>{v};
     };
 
     auto* e = args[0];
     auto e0 = convert(e->Index(0)->ValueAs<f32>());
     if (!e0) {
-        return tint::Failure;
+        return error;
     }
 
     auto e1 = convert(e->Index(1)->ValueAs<f32>());
     if (!e1) {
-        return tint::Failure;
+        return error;
     }
 
     u32 ret = u32((e0.Get() & 0x0000'ffff) | (e1.Get() << 16));
@@ -3237,7 +3240,7 @@
                 if (use_runtime_semantics_) {
                     return mgr.Zero(c0->Type());
                 } else {
-                    return tint::Failure;
+                    return error;
                 }
             }
             return CreateScalar(source, c0->Type(), *r);
@@ -3259,12 +3262,12 @@
             auto scale = Div(source, NumberT(pi), NumberT(180));
             if (!scale) {
                 AddNote("when calculating radians", source);
-                return tint::Failure;
+                return error;
             }
             auto result = Mul(source, e, scale.Get());
             if (!result) {
                 AddNote("when calculating radians", source);
-                return tint::Failure;
+                return error;
             }
             return CreateScalar(source, c0->Type(), result.Get());
         };
@@ -3287,7 +3290,7 @@
         // dot(e2, e1)
         auto dot_e2_e1 = Dot(source, e2, e1);
         if (!dot_e2_e1) {
-            return tint::Failure;
+            return error;
         }
 
         // 2 * dot(e2, e1)
@@ -3297,13 +3300,13 @@
         };
         auto dot_e2_e1_2 = Dispatch_fa_f32_f16(mul2, dot_e2_e1.Get());
         if (!dot_e2_e1_2) {
-            return tint::Failure;
+            return error;
         }
 
         // 2 * dot(e2, e1) * e2
         auto dot_e2_e1_2_e2 = Mul(source, ty, dot_e2_e1_2.Get(), e2);
         if (!dot_e2_e1_2_e2) {
-            return tint::Failure;
+            return error;
         }
 
         // e1 - 2 * dot(e2, e1) * e2
@@ -3327,23 +3330,23 @@
         // let k = 1.0 - e3 * e3 * (1.0 - dot(e2, e1) * dot(e2, e1))
         auto e3_squared = Mul(source, e3, e3);
         if (!e3_squared) {
-            return tint::Failure;
+            return error;
         }
         auto dot_e2_e1_squared = Mul(source, dot_e2_e1, dot_e2_e1);
         if (!dot_e2_e1_squared) {
-            return tint::Failure;
+            return error;
         }
         auto r = Sub(source, NumberT(1), dot_e2_e1_squared.Get());
         if (!r) {
-            return tint::Failure;
+            return error;
         }
         r = Mul(source, e3_squared.Get(), r.Get());
         if (!r) {
-            return tint::Failure;
+            return error;
         }
         r = Sub(source, NumberT(1), r.Get());
         if (!r) {
-            return tint::Failure;
+            return error;
         }
         return CreateScalar(source, el_ty, r.Get());
     };
@@ -3352,15 +3355,15 @@
         // e3 * dot(e2, e1) + sqrt(k)
         auto sqrt_k = Sqrt(source, k);
         if (!sqrt_k) {
-            return tint::Failure;
+            return error;
         }
         auto r = Mul(source, e3, dot_e2_e1);
         if (!r) {
-            return tint::Failure;
+            return error;
         }
         r = Add(source, r.Get(), sqrt_k.Get());
         if (!r) {
-            return tint::Failure;
+            return error;
         }
         return CreateScalar(source, el_ty, r.Get());
     };
@@ -3378,13 +3381,13 @@
         // dot(e2, e1)
         auto dot_e2_e1 = Dot(source, e2, e1);
         if (!dot_e2_e1) {
-            return tint::Failure;
+            return error;
         }
 
         // let k = 1.0 - e3 * e3 * (1.0 - dot(e2, e1) * dot(e2, e1))
         auto k = Dispatch_fa_f32_f16(compute_k, e3, dot_e2_e1.Get());
         if (!k) {
-            return tint::Failure;
+            return error;
         }
 
         // If k < 0.0, returns the refraction vector 0.0
@@ -3395,15 +3398,15 @@
         // Otherwise return the refraction vector e3 * e1 - (e3 * dot(e2, e1) + sqrt(k)) * e2
         auto e1_scaled = Mul(source, ty, e3, e1);
         if (!e1_scaled) {
-            return tint::Failure;
+            return error;
         }
         auto e2_scale = Dispatch_fa_f32_f16(compute_e2_scale, e3, dot_e2_e1.Get(), k.Get());
         if (!e2_scale) {
-            return tint::Failure;
+            return error;
         }
         auto e2_scaled = Mul(source, ty, e2_scale.Get(), e2);
         if (!e2_scaled) {
-            return tint::Failure;
+            return error;
         }
         return Sub(source, ty, e1_scaled.Get(), e2_scaled.Get());
     };
@@ -3577,7 +3580,7 @@
 
             auto err = [&] {
                 AddNote("when calculating smoothstep", source);
-                return tint::Failure;
+                return error;
             };
 
             // t = clamp((x - low) / (high - low), 0.0, 1.0)
@@ -3716,7 +3719,7 @@
             if (use_runtime_semantics_) {
                 val = f32(0.f);
             } else {
-                return tint::Failure;
+                return error;
             }
         }
         auto el = CreateScalar(source, inner_ty, val.Get());
@@ -3817,7 +3820,7 @@
             if (use_runtime_semantics_) {
                 return mgr.Zero(c->Type());
             } else {
-                return tint::Failure;
+                return error;
             }
         }
         return CreateScalar(source, c->Type(), conv.Get());
@@ -3833,7 +3836,7 @@
     }
     ConvertContext ctx{mgr, diags, source, use_runtime_semantics_};
     auto* converted = ConvertInternal(value, target_ty, ctx);
-    return converted ? Result(converted) : tint::Failure;
+    return converted ? Result(converted) : Result(error);
 }
 
 void Eval::AddError(const std::string& msg, const Source& source) const {
diff --git a/src/tint/lang/core/constant/eval.h b/src/tint/lang/core/constant/eval.h
index 17f298e..3896d72 100644
--- a/src/tint/lang/core/constant/eval.h
+++ b/src/tint/lang/core/constant/eval.h
@@ -41,15 +41,23 @@
 /// Eval performs shader creation-time (const-expression) expression evaluation.
 class Eval {
   public:
+    /// The failure type used by the methods of this class.
+    /// TODO(bclayton): Use Failure, and bubble up the error diagnostics instead of writing directly
+    /// to the diagnostic list.
+    struct Error {};
+
+    /// A value of the type Error.
+    static constexpr Error error{};
+
     /// The result type of a method that may raise a diagnostic error, upon which the caller should
     /// handle the error. Can be one of three distinct values:
     /// * A non-null Value pointer. Returned when a expression resolves to a creation
     ///   time value.
     /// * A null Value pointer. Returned when a expression cannot resolve to a creation time value,
     ///   but is otherwise legal.
-    /// * `tint::Failure`. Returned when there was an error. In this situation the method will have
+    /// * Error. Returned when there was an error. In this situation the method will have
     ///   already reported a diagnostic error message, and the caller should abort resolving.
-    using Result = tint::Result<const Value*>;
+    using Result = tint::Result<const Value*, Error>;
 
     /// Typedef for a constant evaluation function
     using Function = Result (Eval::*)(const core::type::Type* result_ty,
@@ -959,7 +967,7 @@
     /// @param b the rhs number
     /// @returns the result number on success, or logs an error and returns Failure
     template <typename NumberT>
-    tint::Result<NumberT> Add(const Source& source, NumberT a, NumberT b);
+    tint::Result<NumberT, Error> Add(const Source& source, NumberT a, NumberT b);
 
     /// Subtracts two Number<T>s
     /// @param source the source location
@@ -967,7 +975,7 @@
     /// @param b the rhs number
     /// @returns the result number on success, or logs an error and returns Failure
     template <typename NumberT>
-    tint::Result<NumberT> Sub(const Source& source, NumberT a, NumberT b);
+    tint::Result<NumberT, Error> Sub(const Source& source, NumberT a, NumberT b);
 
     /// Multiplies two Number<T>s
     /// @param source the source location
@@ -975,7 +983,7 @@
     /// @param b the rhs number
     /// @returns the result number on success, or logs an error and returns Failure
     template <typename NumberT>
-    tint::Result<NumberT> Mul(const Source& source, NumberT a, NumberT b);
+    tint::Result<NumberT, Error> Mul(const Source& source, NumberT a, NumberT b);
 
     /// Divides two Number<T>s
     /// @param source the source location
@@ -983,7 +991,7 @@
     /// @param b the rhs number
     /// @returns the result number on success, or logs an error and returns Failure
     template <typename NumberT>
-    tint::Result<NumberT> Div(const Source& source, NumberT a, NumberT b);
+    tint::Result<NumberT, Error> Div(const Source& source, NumberT a, NumberT b);
 
     /// Returns the (signed) remainder of the division of two Number<T>s
     /// @param source the source location
@@ -991,7 +999,7 @@
     /// @param b the rhs number
     /// @returns the result number on success, or logs an error and returns Failure
     template <typename NumberT>
-    tint::Result<NumberT> Mod(const Source& source, NumberT a, NumberT b);
+    tint::Result<NumberT, Error> Mod(const Source& source, NumberT a, NumberT b);
 
     /// Returns the dot product of (a1,a2) with (b1,b2)
     /// @param source the source location
@@ -1001,11 +1009,11 @@
     /// @param b2 component 2 of rhs vector
     /// @returns the result number on success, or logs an error and returns Failure
     template <typename NumberT>
-    tint::Result<NumberT> Dot2(const Source& source,
-                               NumberT a1,
-                               NumberT a2,
-                               NumberT b1,
-                               NumberT b2);
+    tint::Result<NumberT, Error> Dot2(const Source& source,
+                                      NumberT a1,
+                                      NumberT a2,
+                                      NumberT b1,
+                                      NumberT b2);
 
     /// Returns the dot product of (a1,a2,a3) with (b1,b2,b3)
     /// @param source the source location
@@ -1017,13 +1025,13 @@
     /// @param b3 component 3 of rhs vector
     /// @returns the result number on success, or logs an error and returns Failure
     template <typename NumberT>
-    tint::Result<NumberT> Dot3(const Source& source,
-                               NumberT a1,
-                               NumberT a2,
-                               NumberT a3,
-                               NumberT b1,
-                               NumberT b2,
-                               NumberT b3);
+    tint::Result<NumberT, Error> Dot3(const Source& source,
+                                      NumberT a1,
+                                      NumberT a2,
+                                      NumberT a3,
+                                      NumberT b1,
+                                      NumberT b2,
+                                      NumberT b3);
 
     /// Returns the dot product of (a1,b1,c1,d1) with (a2,b2,c2,d2)
     /// @param source the source location
@@ -1037,15 +1045,15 @@
     /// @param b4 component 4 of rhs vector
     /// @returns the result number on success, or logs an error and returns Failure
     template <typename NumberT>
-    tint::Result<NumberT> Dot4(const Source& source,
-                               NumberT a1,
-                               NumberT a2,
-                               NumberT a3,
-                               NumberT a4,
-                               NumberT b1,
-                               NumberT b2,
-                               NumberT b3,
-                               NumberT b4);
+    tint::Result<NumberT, Error> Dot4(const Source& source,
+                                      NumberT a1,
+                                      NumberT a2,
+                                      NumberT a3,
+                                      NumberT a4,
+                                      NumberT b1,
+                                      NumberT b2,
+                                      NumberT b3,
+                                      NumberT b4);
 
     /// Returns the determinant of the 2x2 matrix:
     /// | a c |
@@ -1056,11 +1064,11 @@
     /// @param c component 1 of the second column vector
     /// @param d component 2 of the second column vector
     template <typename NumberT>
-    tint::Result<NumberT> Det2(const Source& source,  //
-                               NumberT a,
-                               NumberT b,
-                               NumberT c,
-                               NumberT d);
+    tint::Result<NumberT, Error> Det2(const Source& source,  //
+                                      NumberT a,
+                                      NumberT b,
+                                      NumberT c,
+                                      NumberT d);
 
     /// Returns the determinant of the 3x3 matrix:
     /// | a d g |
@@ -1077,16 +1085,16 @@
     /// @param h component 2 of the third column vector
     /// @param i component 3 of the third column vector
     template <typename NumberT>
-    tint::Result<NumberT> Det3(const Source& source,
-                               NumberT a,
-                               NumberT b,
-                               NumberT c,
-                               NumberT d,
-                               NumberT e,
-                               NumberT f,
-                               NumberT g,
-                               NumberT h,
-                               NumberT i);
+    tint::Result<NumberT, Error> Det3(const Source& source,
+                                      NumberT a,
+                                      NumberT b,
+                                      NumberT c,
+                                      NumberT d,
+                                      NumberT e,
+                                      NumberT f,
+                                      NumberT g,
+                                      NumberT h,
+                                      NumberT i);
 
     /// Returns the determinant of the 4x4 matrix:
     /// | a e i m |
@@ -1111,26 +1119,26 @@
     /// @param o component 3 of the fourth column vector
     /// @param p component 4 of the fourth column vector
     template <typename NumberT>
-    tint::Result<NumberT> Det4(const Source& source,
-                               NumberT a,
-                               NumberT b,
-                               NumberT c,
-                               NumberT d,
-                               NumberT e,
-                               NumberT f,
-                               NumberT g,
-                               NumberT h,
-                               NumberT i,
-                               NumberT j,
-                               NumberT k,
-                               NumberT l,
-                               NumberT m,
-                               NumberT n,
-                               NumberT o,
-                               NumberT p);
+    tint::Result<NumberT, Error> Det4(const Source& source,
+                                      NumberT a,
+                                      NumberT b,
+                                      NumberT c,
+                                      NumberT d,
+                                      NumberT e,
+                                      NumberT f,
+                                      NumberT g,
+                                      NumberT h,
+                                      NumberT i,
+                                      NumberT j,
+                                      NumberT k,
+                                      NumberT l,
+                                      NumberT m,
+                                      NumberT n,
+                                      NumberT o,
+                                      NumberT p);
 
     template <typename NumberT>
-    tint::Result<NumberT> Sqrt(const Source& source, NumberT v);
+    tint::Result<NumberT, Error> Sqrt(const Source& source, NumberT v);
 
     /// Clamps e between low and high
     /// @param source the source location
@@ -1139,7 +1147,7 @@
     /// @param high the upper bound
     /// @returns the result number on success, or logs an error and returns Failure
     template <typename NumberT>
-    tint::Result<NumberT> Clamp(const Source& source, NumberT e, NumberT low, NumberT high);
+    tint::Result<NumberT, Error> Clamp(const Source& source, NumberT e, NumberT low, NumberT high);
 
     /// Returns a callable that calls Add, and creates a Constant with its result of type `elem_ty`
     /// if successful, or returns Failure otherwise.
diff --git a/src/tint/lang/core/intrinsic/data/BUILD.bazel b/src/tint/lang/core/intrinsic/data/BUILD.bazel
index 314ffb3..7359e8e 100644
--- a/src/tint/lang/core/intrinsic/data/BUILD.bazel
+++ b/src/tint/lang/core/intrinsic/data/BUILD.bazel
@@ -38,6 +38,7 @@
     "//src/tint/lang/core/intrinsic",
     "//src/tint/lang/core/type",
     "//src/tint/utils/containers",
+    "//src/tint/utils/diagnostic",
     "//src/tint/utils/ice",
     "//src/tint/utils/id",
     "//src/tint/utils/macros",
diff --git a/src/tint/lang/core/intrinsic/data/BUILD.cmake b/src/tint/lang/core/intrinsic/data/BUILD.cmake
index 8134896..dc4cb63 100644
--- a/src/tint/lang/core/intrinsic/data/BUILD.cmake
+++ b/src/tint/lang/core/intrinsic/data/BUILD.cmake
@@ -37,6 +37,7 @@
   tint_lang_core_intrinsic
   tint_lang_core_type
   tint_utils_containers
+  tint_utils_diagnostic
   tint_utils_ice
   tint_utils_id
   tint_utils_macros
diff --git a/src/tint/lang/core/intrinsic/data/BUILD.gn b/src/tint/lang/core/intrinsic/data/BUILD.gn
index 4a096a5..289deb7 100644
--- a/src/tint/lang/core/intrinsic/data/BUILD.gn
+++ b/src/tint/lang/core/intrinsic/data/BUILD.gn
@@ -37,6 +37,7 @@
     "${tint_src_dir}/lang/core/intrinsic",
     "${tint_src_dir}/lang/core/type",
     "${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",
diff --git a/src/tint/lang/core/intrinsic/table.cc b/src/tint/lang/core/intrinsic/table.cc
index ce4c23e..1e057a7 100644
--- a/src/tint/lang/core/intrinsic/table.cc
+++ b/src/tint/lang/core/intrinsic/table.cc
@@ -220,7 +220,7 @@
         // Sort the candidates with the most promising first
         SortCandidates(candidates);
         on_no_match(std::move(candidates));
-        return Failure;
+        return Failure{};
     }
 
     Candidate match;
@@ -232,7 +232,7 @@
                                  std::move(templates));
         if (!match.overload) {
             // Ambiguous overload. ResolveCandidate() will have already raised an error diagnostic.
-            return Failure;
+            return Failure{};
         }
     }
 
@@ -246,7 +246,7 @@
                           .Type(&any);
         if (TINT_UNLIKELY(!return_type)) {
             TINT_ICE() << "MatchState.Match() returned null";
-            return Failure;
+            return Failure{};
         }
     } else {
         return_type = context.types.void_();
@@ -584,15 +584,6 @@
 }  // namespace
 
 Result<Overload> Lookup(Context& context,
-                        core::BuiltinFn builtin_type,
-                        VectorRef<const core::type::Type*> args,
-                        EvaluationStage earliest_eval_stage,
-                        const Source& source) {
-    return Lookup(context, core::str(builtin_type), static_cast<size_t>(builtin_type), args,
-                  earliest_eval_stage, source);
-}
-
-Result<Overload> Lookup(Context& context,
                         const char* intrinsic_name,
                         size_t function_id,
                         VectorRef<const core::type::Type*> args,
@@ -638,7 +629,7 @@
             break;
         default:
             TINT_UNREACHABLE() << "invalid unary op: " << op;
-            return Failure;
+            return Failure{};
     }
 
     Vector args{arg};
diff --git a/src/tint/lang/core/intrinsic/table.h b/src/tint/lang/core/intrinsic/table.h
index 1f38b3d..6b13e4e 100644
--- a/src/tint/lang/core/intrinsic/table.h
+++ b/src/tint/lang/core/intrinsic/table.h
@@ -17,6 +17,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "src/tint/lang/core/binary_op.h"
 #include "src/tint/lang/core/builtin_fn.h"
@@ -25,6 +26,7 @@
 #include "src/tint/lang/core/parameter_usage.h"
 #include "src/tint/lang/core/unary_op.h"
 #include "src/tint/utils/containers/vector.h"
+#include "src/tint/utils/text/string.h"
 
 // Forward declarations
 namespace tint::diag {
@@ -99,25 +101,6 @@
 /// Lookup looks for the builtin overload with the given signature, raising an error diagnostic
 /// if the builtin was not found.
 /// @param context the intrinsic context
-/// @param builtin_type the builtin identifier
-/// @param args the argument types passed to the builtin function
-/// @param earliest_eval_stage the the earliest evaluation stage that a call to
-///        the builtin can be made. This can alter the overloads considered.
-///        For example, if the earliest evaluation stage is `EvaluationStage::kRuntime`, then
-///        only overloads with concrete argument types will be considered, as all
-///        abstract-numerics will have been materialized after shader creation time
-///        (EvaluationStage::kConstant).
-/// @param source the source of the builtin call
-/// @return the resolved builtin function overload
-Result<Overload> Lookup(Context& context,
-                        core::BuiltinFn builtin_type,
-                        VectorRef<const core::type::Type*> args,
-                        EvaluationStage earliest_eval_stage,
-                        const Source& source);
-
-/// Lookup looks for the builtin overload with the given signature, raising an error diagnostic
-/// if the builtin was not found.
-/// @param context the intrinsic context
 /// @param intrinsic_name the name of the intrinsi
 /// @param function_id the function identifier
 /// @param args the argument types passed to the builtin function
@@ -136,6 +119,31 @@
                         EvaluationStage earliest_eval_stage,
                         const Source& source);
 
+/// Lookup looks for the builtin overload with the given signature, raising an error diagnostic
+/// if the builtin was not found.
+/// @param context the intrinsic context
+/// @param builtin_fn the builtin function
+/// @param args the argument types passed to the builtin function
+/// @param earliest_eval_stage the the earliest evaluation stage that a call to
+///        the builtin can be made. This can alter the overloads considered.
+///        For example, if the earliest evaluation stage is `EvaluationStage::kRuntime`, then
+///        only overloads with concrete argument types will be considered, as all
+///        abstract-numerics will have been materialized after shader creation time
+///        (EvaluationStage::kConstant).
+/// @param source the source of the builtin call
+/// @return the resolved builtin function overload
+template <typename BUILTIN_FN>
+Result<Overload> Lookup(Context& context,
+                        BUILTIN_FN builtin_fn,
+                        VectorRef<const core::type::Type*> args,
+                        EvaluationStage earliest_eval_stage,
+                        const Source& source) {
+    static_assert(std::is_enum_v<BUILTIN_FN>);
+    std::string name = tint::ToString(builtin_fn);  // TODO(bclayton): Avoid this heap allocation
+    size_t id = static_cast<size_t>(builtin_fn);
+    return Lookup(context, name.c_str(), id, std::move(args), earliest_eval_stage, source);
+}
+
 /// Lookup looks for the unary op overload with the given signature, raising an error
 /// diagnostic if the operator was not found.
 /// @param context the intrinsic context
diff --git a/src/tint/lang/core/ir/builder.cc b/src/tint/lang/core/ir/builder.cc
index 07ffe5a..15bc2ef 100644
--- a/src/tint/lang/core/ir/builder.cc
+++ b/src/tint/lang/core/ir/builder.cc
@@ -30,13 +30,6 @@
 
 Builder::~Builder() = default;
 
-ir::Block* Builder::RootBlock() {
-    if (!ir.root_block) {
-        ir.root_block = Block();
-    }
-    return ir.root_block;
-}
-
 Block* Builder::Block() {
     return ir.blocks.Create<ir::Block>();
 }
diff --git a/src/tint/lang/core/ir/builder.h b/src/tint/lang/core/ir/builder.h
index a74f3d5..028eee2 100644
--- a/src/tint/lang/core/ir/builder.h
+++ b/src/tint/lang/core/ir/builder.h
@@ -655,6 +655,15 @@
     ir::Discard* Discard();
 
     /// Creates a user function call instruction
+    /// @param func the function to call
+    /// @param args the call arguments
+    /// @returns the instruction
+    template <typename... ARGS>
+    ir::UserCall* Call(ir::Function* func, ARGS&&... args) {
+        return Call(func->ReturnType(), func, std::forward<ARGS>(args)...);
+    }
+
+    /// Creates a user function call instruction
     /// @param type the return type of the call
     /// @param func the function to call
     /// @param args the call arguments
@@ -688,6 +697,15 @@
                                                     Values(std::forward<ARGS>(args)...)));
     }
 
+    /// Creates a value conversion instruction to the template type T
+    /// @param val the value to be converted
+    /// @returns the instruction
+    template <typename T, typename VAL>
+    ir::Convert* Convert(VAL&& val) {
+        auto* type = ir.Types().Get<T>();
+        return Convert(type, std::forward<VAL>(val));
+    }
+
     /// Creates a value conversion instruction
     /// @param to the type converted to
     /// @param val the value to be converted
@@ -698,6 +716,15 @@
                                                           Value(std::forward<VAL>(val))));
     }
 
+    /// Creates a value constructor instruction to the template type T
+    /// @param args the arguments to the constructor
+    /// @returns the instruction
+    template <typename T, typename... ARGS>
+    ir::Construct* Construct(ARGS&&... args) {
+        auto* type = ir.Types().Get<T>();
+        return Construct(type, std::forward<ARGS>(args)...);
+    }
+
     /// Creates a value constructor instruction
     /// @param type the type to constructed
     /// @param args the arguments to the constructor
@@ -768,6 +795,25 @@
     /// @returns the instruction
     ir::Var* Var(std::string_view name, const core::type::Pointer* type);
 
+    /// Creates a new `var` declaration with a name and initializer value
+    /// @param name the var name
+    /// @param init the var initializer
+    /// @returns the instruction
+    template <core::AddressSpace SPACE = core::AddressSpace::kFunction,
+              core::Access ACCESS = core::Access::kReadWrite,
+              typename VALUE = void>
+    ir::Var* Var(std::string_view name, VALUE&& init) {
+        auto* val = Value(std::forward<VALUE>(init));
+        if (TINT_UNLIKELY(!val)) {
+            TINT_ASSERT(val);
+            return nullptr;
+        }
+        auto* var = Var(name, ir.Types().ptr(SPACE, val->Type(), ACCESS));
+        var->SetInitializer(val);
+        ir.SetName(var->Result(), name);
+        return var;
+    }
+
     /// Creates a new `let` declaration
     /// @param name the let name
     /// @param value the let value
@@ -950,10 +996,6 @@
     /// @returns the instruction
     ir::Unreachable* Unreachable();
 
-    /// Retrieves the root block for the module, creating if necessary
-    /// @returns the root block
-    ir::Block* RootBlock();
-
     /// Creates a new runtime value
     /// @param type the return type
     /// @returns the value
diff --git a/src/tint/lang/core/ir/builtin_call.cc b/src/tint/lang/core/ir/builtin_call.cc
index 367ddae..351e940 100644
--- a/src/tint/lang/core/ir/builtin_call.cc
+++ b/src/tint/lang/core/ir/builtin_call.cc
@@ -21,6 +21,7 @@
 namespace tint::core::ir {
 
 BuiltinCall::BuiltinCall(InstructionResult* result, VectorRef<Value*> arguments) {
+    flags_.Add(Flag::kSequenced);
     AddOperands(BuiltinCall::kArgsOperandOffset, std::move(arguments));
     AddResult(result);
 }
diff --git a/src/tint/lang/core/ir/builtin_call.h b/src/tint/lang/core/ir/builtin_call.h
index fe35766..6874f7e 100644
--- a/src/tint/lang/core/ir/builtin_call.h
+++ b/src/tint/lang/core/ir/builtin_call.h
@@ -36,9 +36,6 @@
     /// @returns the identifier for the function
     virtual size_t FuncId() = 0;
 
-    /// @returns the intrinsic name
-    virtual const char* IntrinsicName() = 0;
-
     /// @returns the table data to validate this builtin
     virtual const core::intrinsic::TableData& TableData() = 0;
 };
diff --git a/src/tint/lang/core/ir/call.cc b/src/tint/lang/core/ir/call.cc
index d79ac69..c678bee 100644
--- a/src/tint/lang/core/ir/call.cc
+++ b/src/tint/lang/core/ir/call.cc
@@ -20,9 +20,7 @@
 
 namespace tint::core::ir {
 
-Call::Call() {
-    flags_.Add(Flag::kSequenced);
-}
+Call::Call() = default;
 
 Call::~Call() = default;
 
diff --git a/src/tint/lang/core/ir/core_builtin_call.h b/src/tint/lang/core/ir/core_builtin_call.h
index 24c998d..9228678 100644
--- a/src/tint/lang/core/ir/core_builtin_call.h
+++ b/src/tint/lang/core/ir/core_builtin_call.h
@@ -49,9 +49,6 @@
     /// @returns the friendly name for the instruction
     std::string FriendlyName() override { return core::str(func_); }
 
-    /// @returns the intrinsic name
-    const char* IntrinsicName() override { return core::str(func_); }
-
     /// @returns the table data to validate this builtin
     const core::intrinsic::TableData& TableData() override { return core::intrinsic::data::kData; }
 
diff --git a/src/tint/lang/core/ir/core_builtin_call_test.cc b/src/tint/lang/core/ir/core_builtin_call_test.cc
index 290af5a..ced611d 100644
--- a/src/tint/lang/core/ir/core_builtin_call_test.cc
+++ b/src/tint/lang/core/ir/core_builtin_call_test.cc
@@ -48,7 +48,7 @@
         {
             Module mod;
             Builder b{mod};
-            b.Call(nullptr, core::BuiltinFn::kAbs);
+            b.Call(static_cast<type::Type*>(nullptr), core::BuiltinFn::kAbs);
         },
         "");
 }
diff --git a/src/tint/lang/core/ir/disassembler.cc b/src/tint/lang/core/ir/disassembler.cc
index 191f4d1..6625466 100644
--- a/src/tint/lang/core/ir/disassembler.cc
+++ b/src/tint/lang/core/ir/disassembler.cc
@@ -152,7 +152,7 @@
         }
     }
 
-    if (mod_.root_block) {
+    if (!mod_.root_block->IsEmpty()) {
         EmitBlock(mod_.root_block, "root");
         EmitLine();
     }
@@ -413,6 +413,7 @@
         [&](ir::InstructionResult* rv) { out_ << "%" << IdOf(rv); },
         [&](ir::BlockParam* p) { out_ << "%" << IdOf(p) << ":" << p->Type()->FriendlyName(); },
         [&](ir::FunctionParam* p) { out_ << "%" << IdOf(p); },
+        [&](ir::Function* f) { out_ << "%" << IdOf(f); },
         [&](Default) {
             if (val == nullptr) {
                 out_ << "undef";
@@ -461,7 +462,8 @@
             EmitValueWithType(uc);
             out_ << " = ";
             EmitInstructionName(uc);
-            out_ << " %" << IdOf(uc->Target());
+            out_ << " ";
+            EmitOperand(uc, UserCall::kFunctionOperandOffset);
             if (!uc->Args().IsEmpty()) {
                 out_ << ", ";
             }
diff --git a/src/tint/lang/core/ir/discard.cc b/src/tint/lang/core/ir/discard.cc
index 7112f01..2c3b1c9 100644
--- a/src/tint/lang/core/ir/discard.cc
+++ b/src/tint/lang/core/ir/discard.cc
@@ -21,7 +21,9 @@
 
 namespace tint::core::ir {
 
-Discard::Discard() = default;
+Discard::Discard() {
+    flags_.Add(Flag::kSequenced);
+}
 
 Discard::~Discard() = default;
 
diff --git a/src/tint/lang/core/ir/module.cc b/src/tint/lang/core/ir/module.cc
index dd96309..090a898 100644
--- a/src/tint/lang/core/ir/module.cc
+++ b/src/tint/lang/core/ir/module.cc
@@ -20,7 +20,7 @@
 
 namespace tint::core::ir {
 
-Module::Module() = default;
+Module::Module() : root_block(blocks.Create<ir::Block>()) {}
 
 Module::Module(Module&&) = default;
 
diff --git a/src/tint/lang/core/ir/transform/BUILD.bazel b/src/tint/lang/core/ir/transform/BUILD.bazel
index 7216985..4388198 100644
--- a/src/tint/lang/core/ir/transform/BUILD.bazel
+++ b/src/tint/lang/core/ir/transform/BUILD.bazel
@@ -37,6 +37,7 @@
     "robustness.cc",
     "shader_io.cc",
     "std140.cc",
+    "zero_init_workgroup_memory.cc",
   ],
   hdrs = [
     "add_empty_entry_point.h",
@@ -50,6 +51,7 @@
     "robustness.h",
     "shader_io.h",
     "std140.h",
+    "zero_init_workgroup_memory.h",
   ],
   deps = [
     "//src/tint/api/common",
@@ -92,6 +94,7 @@
     "multiplanar_external_texture_test.cc",
     "robustness_test.cc",
     "std140_test.cc",
+    "zero_init_workgroup_memory_test.cc",
   ],
   deps = [
     "//src/tint/api/common",
diff --git a/src/tint/lang/core/ir/transform/BUILD.cmake b/src/tint/lang/core/ir/transform/BUILD.cmake
index f474b48..5e772df 100644
--- a/src/tint/lang/core/ir/transform/BUILD.cmake
+++ b/src/tint/lang/core/ir/transform/BUILD.cmake
@@ -48,6 +48,8 @@
   lang/core/ir/transform/shader_io.h
   lang/core/ir/transform/std140.cc
   lang/core/ir/transform/std140.h
+  lang/core/ir/transform/zero_init_workgroup_memory.cc
+  lang/core/ir/transform/zero_init_workgroup_memory.h
 )
 
 tint_target_add_dependencies(tint_lang_core_ir_transform lib
@@ -90,6 +92,7 @@
   lang/core/ir/transform/multiplanar_external_texture_test.cc
   lang/core/ir/transform/robustness_test.cc
   lang/core/ir/transform/std140_test.cc
+  lang/core/ir/transform/zero_init_workgroup_memory_test.cc
 )
 
 tint_target_add_dependencies(tint_lang_core_ir_transform_test test
diff --git a/src/tint/lang/core/ir/transform/BUILD.gn b/src/tint/lang/core/ir/transform/BUILD.gn
index 82e462b..cf99aba 100644
--- a/src/tint/lang/core/ir/transform/BUILD.gn
+++ b/src/tint/lang/core/ir/transform/BUILD.gn
@@ -53,6 +53,8 @@
     "shader_io.h",
     "std140.cc",
     "std140.h",
+    "zero_init_workgroup_memory.cc",
+    "zero_init_workgroup_memory.h",
   ]
   deps = [
     "${tint_src_dir}/api/common",
@@ -93,6 +95,7 @@
       "multiplanar_external_texture_test.cc",
       "robustness_test.cc",
       "std140_test.cc",
+      "zero_init_workgroup_memory_test.cc",
     ]
     deps = [
       "${tint_src_dir}:gmock_and_gtest",
diff --git a/src/tint/lang/core/ir/transform/add_empty_entry_point.cc b/src/tint/lang/core/ir/transform/add_empty_entry_point.cc
index aef5ff8..86bcf0e 100644
--- a/src/tint/lang/core/ir/transform/add_empty_entry_point.cc
+++ b/src/tint/lang/core/ir/transform/add_empty_entry_point.cc
@@ -24,25 +24,25 @@
 
 namespace {
 
-void Run(ir::Module* ir) {
-    for (auto* func : ir->functions) {
+void Run(ir::Module& ir) {
+    for (auto* func : ir.functions) {
         if (func->Stage() != Function::PipelineStage::kUndefined) {
             return;
         }
     }
 
-    ir::Builder builder(*ir);
-    auto* ep = builder.Function("unused_entry_point", ir->Types().void_(),
+    ir::Builder builder{ir};
+    auto* ep = builder.Function("unused_entry_point", ir.Types().void_(),
                                 Function::PipelineStage::kCompute, std::array{1u, 1u, 1u});
     ep->Block()->Append(builder.Return(ep));
 }
 
 }  // namespace
 
-Result<SuccessType, std::string> AddEmptyEntryPoint(Module* ir) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "AddEmptyEntryPoint transform");
+Result<SuccessType> AddEmptyEntryPoint(Module& ir) {
+    auto result = ValidateAndDumpIfNeeded(ir, "AddEmptyEntryPoint transform");
     if (!result) {
-        return result;
+        return result.Failure();
     }
 
     Run(ir);
diff --git a/src/tint/lang/core/ir/transform/add_empty_entry_point.h b/src/tint/lang/core/ir/transform/add_empty_entry_point.h
index 2473d93..8b9e0ef 100644
--- a/src/tint/lang/core/ir/transform/add_empty_entry_point.h
+++ b/src/tint/lang/core/ir/transform/add_empty_entry_point.h
@@ -28,8 +28,8 @@
 
 /// Add an empty entry point to the module, if no other entry points exist.
 /// @param module the module to transform
-/// @returns an error string on failure
-Result<SuccessType, std::string> AddEmptyEntryPoint(Module* module);
+/// @returns success or failure
+Result<SuccessType> AddEmptyEntryPoint(Module& module);
 
 }  // namespace tint::core::ir::transform
 
diff --git a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc
index 4acfbfb..82471d1 100644
--- a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc
+++ b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc
@@ -32,20 +32,20 @@
 /// PIMPL state for the transform.
 struct State {
     /// The IR module.
-    Module* ir = nullptr;
+    Module& ir;
 
     /// The IR builder.
-    Builder b{*ir};
+    Builder b{ir};
 
     /// The type manager.
-    core::type::Manager& ty{ir->Types()};
+    core::type::Manager& ty{ir.Types()};
 
     /// Process the module.
     void Process() {
         // Find module-scope variables that need to be replaced.
-        if (ir->root_block) {
+        if (!ir.root_block->IsEmpty()) {
             Vector<Instruction*, 4> to_remove;
-            for (auto inst : *ir->root_block) {
+            for (auto inst : *ir.root_block) {
                 auto* var = inst->As<Var>();
                 if (!var) {
                     continue;
@@ -67,7 +67,7 @@
         }
 
         // Find function parameters that need to be replaced.
-        for (auto* func : ir->functions) {
+        for (auto* func : ir.functions) {
             for (uint32_t index = 0; index < func->Params().Length(); index++) {
                 auto* param = func->Params()[index];
                 auto* storage_texture = param->Type()->As<core::type::StorageTexture>();
@@ -90,8 +90,8 @@
         auto bp = old_var->BindingPoint();
         new_var->SetBindingPoint(bp->group, bp->binding);
         new_var->InsertBefore(old_var);
-        if (auto name = ir->NameOf(old_var)) {
-            ir->SetName(new_var, name.NameView());
+        if (auto name = ir.NameOf(old_var)) {
+            ir.SetName(new_var, name.NameView());
         }
 
         // Replace all uses of the old variable with the new one.
@@ -111,8 +111,8 @@
         auto* rgba8 = ty.Get<core::type::StorageTexture>(
             bgra8->dim(), core::TexelFormat::kRgba8Unorm, bgra8->access(), bgra8->type());
         auto* new_param = b.FunctionParam(rgba8);
-        if (auto name = ir->NameOf(old_param)) {
-            ir->SetName(new_param, name.NameView());
+        if (auto name = ir.NameOf(old_param)) {
+            ir.SetName(new_param, name.NameView());
         }
 
         Vector<FunctionParam*, 4> new_params = func->Params();
@@ -170,8 +170,8 @@
 
 }  // namespace
 
-Result<SuccessType, std::string> Bgra8UnormPolyfill(Module* ir) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "Bgra8UnormPolyfill transform");
+Result<SuccessType> Bgra8UnormPolyfill(Module& ir) {
+    auto result = ValidateAndDumpIfNeeded(ir, "Bgra8UnormPolyfill transform");
     if (!result) {
         return result;
     }
diff --git a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.h b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.h
index 46c788f..1311056 100644
--- a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.h
+++ b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.h
@@ -29,8 +29,8 @@
 /// Bgra8UnormPolyfill is a transform that changes the texel format of storage textures from
 /// bgra8unorm to rgba8unorm, inserting swizzles before and after texture accesses as necessary.
 /// @param module the module to transform
-/// @returns an error string on failure
-Result<SuccessType, std::string> Bgra8UnormPolyfill(Module* module);
+/// @returns success or failure
+Result<SuccessType> Bgra8UnormPolyfill(Module& module);
 
 }  // namespace tint::core::ir::transform
 
diff --git a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc
index aab9aa5..683b85b 100644
--- a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc
+++ b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc
@@ -52,7 +52,7 @@
 
     auto* var = b.Var("texture", ty.ptr(handle, texture_ty));
     var->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.void_());
     auto* coords = b.FunctionParam("coords", ty.vec2<u32>());
@@ -125,7 +125,7 @@
 
     auto* var = b.Var("texture", ty.ptr(handle, texture_ty));
     var->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.void_());
     auto* coords = b.FunctionParam("coords", ty.vec2<u32>());
@@ -219,7 +219,7 @@
 
     auto* var = b.Var("texture", ty.ptr(handle, texture_ty));
     var->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* bar = b.Function("bar", ty.void_());
     {
@@ -303,9 +303,9 @@
     var_a->SetBindingPoint(1, 2);
     var_b->SetBindingPoint(1, 3);
     var_c->SetBindingPoint(1, 4);
-    b.RootBlock()->Append(var_a);
-    b.RootBlock()->Append(var_b);
-    b.RootBlock()->Append(var_c);
+    mod.root_block->Append(var_a);
+    mod.root_block->Append(var_b);
+    mod.root_block->Append(var_c);
 
     auto* bar = b.Function("bar", ty.void_());
     {
@@ -405,7 +405,7 @@
 
     auto* var_a = b.Var("texture", ty.ptr(handle, texture_ty));
     var_a->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var_a);
+    mod.root_block->Append(var_a);
 
     auto* bar = b.Function("bar", ty.void_());
     {
@@ -506,7 +506,7 @@
 
     auto* var = b.Var("texture", ty.ptr(handle, texture_ty));
     var->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.void_());
     auto* coords = b.FunctionParam("coords", ty.vec2<u32>());
@@ -561,7 +561,7 @@
 
     auto* var = b.Var("texture", ty.ptr(handle, texture_ty));
     var->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.vec2<u32>());
     b.Append(func->Block(), [&] {
@@ -612,7 +612,7 @@
 
     auto* var = b.Var("texture", ty.ptr(handle, texture_ty));
     var->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.vec4<f32>());
     auto* coords = b.FunctionParam("coords", ty.vec2<u32>());
@@ -666,7 +666,7 @@
 
     auto* var = b.Var("texture", ty.ptr(handle, texture_ty));
     var->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.void_());
     auto* coords = b.FunctionParam("coords", ty.vec2<u32>());
diff --git a/src/tint/lang/core/ir/transform/binary_polyfill.cc b/src/tint/lang/core/ir/transform/binary_polyfill.cc
index e4bed28..cd8e09c 100644
--- a/src/tint/lang/core/ir/transform/binary_polyfill.cc
+++ b/src/tint/lang/core/ir/transform/binary_polyfill.cc
@@ -33,16 +33,16 @@
     const BinaryPolyfillConfig& config;
 
     /// The IR module.
-    Module* ir = nullptr;
+    Module& ir;
 
     /// The IR builder.
-    Builder b{*ir};
+    Builder b{ir};
 
     /// The type manager.
-    core::type::Manager& ty{ir->Types()};
+    core::type::Manager& ty{ir.Types()};
 
     /// The symbol table.
-    SymbolTable& sym{ir->symbols};
+    SymbolTable& sym{ir.symbols};
 
     /// Map from integer type to its divide helper function.
     Hashmap<const type::Type*, Function*, 4> int_div_helpers{};
@@ -54,7 +54,7 @@
     void Process() {
         // Find the binary instructions that need to be polyfilled.
         Vector<ir::Binary*, 64> worklist;
-        for (auto* inst : ir->instructions.Objects()) {
+        for (auto* inst : ir.instructions.Objects()) {
             if (!inst->Alive()) {
                 continue;
             }
@@ -98,8 +98,8 @@
 
             if (replacement != binary->Result()) {
                 // Replace the old binary instruction result with the new value.
-                if (auto name = ir->NameOf(binary->Result())) {
-                    ir->SetName(replacement, name);
+                if (auto name = ir.NameOf(binary->Result())) {
+                    ir.SetName(replacement, name);
                 }
                 binary->Result()->ReplaceAllUsesWith(replacement);
                 binary->Destroy();
@@ -232,8 +232,8 @@
 
 }  // namespace
 
-Result<SuccessType, std::string> BinaryPolyfill(Module* ir, const BinaryPolyfillConfig& config) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "BinaryPolyfill transform");
+Result<SuccessType> BinaryPolyfill(Module& ir, const BinaryPolyfillConfig& config) {
+    auto result = ValidateAndDumpIfNeeded(ir, "BinaryPolyfill transform");
     if (!result) {
         return result;
     }
diff --git a/src/tint/lang/core/ir/transform/binary_polyfill.h b/src/tint/lang/core/ir/transform/binary_polyfill.h
index a01d6bb..cc2dc1a 100644
--- a/src/tint/lang/core/ir/transform/binary_polyfill.h
+++ b/src/tint/lang/core/ir/transform/binary_polyfill.h
@@ -38,8 +38,8 @@
 /// backend dialects that may have different semantics.
 /// @param module the module to transform
 /// @param config the polyfill configuration
-/// @returns an error string on failure
-Result<SuccessType, std::string> BinaryPolyfill(Module* module, const BinaryPolyfillConfig& config);
+/// @returns success or failure
+Result<SuccessType> BinaryPolyfill(Module& module, const BinaryPolyfillConfig& config);
 
 }  // namespace tint::core::ir::transform
 
diff --git a/src/tint/lang/core/ir/transform/binding_remapper.cc b/src/tint/lang/core/ir/transform/binding_remapper.cc
index cbb023d..47a591f 100644
--- a/src/tint/lang/core/ir/transform/binding_remapper.cc
+++ b/src/tint/lang/core/ir/transform/binding_remapper.cc
@@ -28,19 +28,16 @@
 
 namespace {
 
-Result<SuccessType, std::string> Run(ir::Module* ir, const BindingRemapperOptions& options) {
-    if (!options.access_controls.empty()) {
-        return std::string("remapping access controls is currently unsupported");
-    }
+Result<SuccessType> Run(ir::Module& ir, const BindingRemapperOptions& options) {
     if (options.binding_points.empty()) {
         return Success;
     }
-    if (!ir->root_block) {
+    if (ir.root_block->IsEmpty()) {
         return Success;
     }
 
     // Find binding resources.
-    for (auto inst : *ir->root_block) {
+    for (auto inst : *ir.root_block) {
         auto* var = inst->As<Var>();
         if (!var || !var->Alive()) {
             continue;
@@ -63,9 +60,8 @@
 
 }  // namespace
 
-Result<SuccessType, std::string> BindingRemapper(Module* ir,
-                                                 const BindingRemapperOptions& options) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "BindingRemapper transform");
+Result<SuccessType> BindingRemapper(Module& ir, const BindingRemapperOptions& options) {
+    auto result = ValidateAndDumpIfNeeded(ir, "BindingRemapper transform");
     if (!result) {
         return result;
     }
diff --git a/src/tint/lang/core/ir/transform/binding_remapper.h b/src/tint/lang/core/ir/transform/binding_remapper.h
index 821f1d9..5d7a2a0 100644
--- a/src/tint/lang/core/ir/transform/binding_remapper.h
+++ b/src/tint/lang/core/ir/transform/binding_remapper.h
@@ -30,9 +30,8 @@
 /// BindingRemapper is a transform that remaps binding point indices and access controls.
 /// @param module the module to transform
 /// @param options the remapping options
-/// @returns an error string on failure
-Result<SuccessType, std::string> BindingRemapper(Module* module,
-                                                 const BindingRemapperOptions& options);
+/// @returns success or failure
+Result<SuccessType> BindingRemapper(Module& module, const BindingRemapperOptions& options);
 
 }  // namespace tint::core::ir::transform
 
diff --git a/src/tint/lang/core/ir/transform/binding_remapper_test.cc b/src/tint/lang/core/ir/transform/binding_remapper_test.cc
index 26b2af9..81383c8 100644
--- a/src/tint/lang/core/ir/transform/binding_remapper_test.cc
+++ b/src/tint/lang/core/ir/transform/binding_remapper_test.cc
@@ -29,7 +29,7 @@
 TEST_F(IR_BindingRemapperTest, NoModify_NoRemappings) {
     auto* buffer = b.Var("buffer", ty.ptr<uniform, i32>());
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* src = R"(
 %b1 = block {  # root
@@ -50,7 +50,7 @@
 TEST_F(IR_BindingRemapperTest, NoModify_RemappingDifferentBindingPoint) {
     auto* buffer = b.Var("buffer", ty.ptr<uniform, i32>());
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* src = R"(
 %b1 = block {  # root
@@ -72,7 +72,7 @@
 TEST_F(IR_BindingRemapperTest, RemappingGroup) {
     auto* buffer = b.Var("buffer", ty.ptr<uniform, i32>());
     buffer->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* src = R"(
 %b1 = block {  # root
@@ -99,7 +99,7 @@
 TEST_F(IR_BindingRemapperTest, RemappingBindingIndex) {
     auto* buffer = b.Var("buffer", ty.ptr<uniform, i32>());
     buffer->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* src = R"(
 %b1 = block {  # root
@@ -126,7 +126,7 @@
 TEST_F(IR_BindingRemapperTest, RemappingGroupAndBindingIndex) {
     auto* buffer = b.Var("buffer", ty.ptr<uniform, i32>());
     buffer->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* src = R"(
 %b1 = block {  # root
@@ -153,10 +153,10 @@
 TEST_F(IR_BindingRemapperTest, SwapTwoBindingPoints) {
     auto* buffer_a = b.Var("buffer_a", ty.ptr<uniform, i32>());
     buffer_a->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(buffer_a);
+    mod.root_block->Append(buffer_a);
     auto* buffer_b = b.Var("buffer_b", ty.ptr<uniform, i32>());
     buffer_b->SetBindingPoint(3, 4);
-    b.RootBlock()->Append(buffer_b);
+    mod.root_block->Append(buffer_b);
 
     auto* src = R"(
 %b1 = block {  # root
@@ -186,10 +186,10 @@
 TEST_F(IR_BindingRemapperTest, BindingPointCollisionSameEntryPoint) {
     auto* buffer_a = b.Var("buffer_a", ty.ptr<uniform, i32>());
     buffer_a->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(buffer_a);
+    mod.root_block->Append(buffer_a);
     auto* buffer_b = b.Var("buffer_b", ty.ptr<uniform, i32>());
     buffer_b->SetBindingPoint(3, 4);
-    b.RootBlock()->Append(buffer_b);
+    mod.root_block->Append(buffer_b);
 
     auto* ep = b.Function("main", mod.Types().void_(), Function::PipelineStage::kFragment);
     b.Append(ep->Block(), [&] {
diff --git a/src/tint/lang/core/ir/transform/block_decorated_structs.cc b/src/tint/lang/core/ir/transform/block_decorated_structs.cc
index 3fe380f..55eada7 100644
--- a/src/tint/lang/core/ir/transform/block_decorated_structs.cc
+++ b/src/tint/lang/core/ir/transform/block_decorated_structs.cc
@@ -28,16 +28,16 @@
 
 namespace {
 
-void Run(Module* ir) {
-    Builder builder(*ir);
+void Run(Module& ir) {
+    Builder builder{ir};
 
-    if (!ir->root_block) {
+    if (ir.root_block->IsEmpty()) {
         return;
     }
 
     // Loop over module-scope declarations, looking for storage or uniform buffers.
     Vector<Var*, 8> buffer_variables;
-    for (auto inst : *ir->root_block) {
+    for (auto inst : *ir.root_block) {
         auto* var = inst->As<Var>();
         if (!var) {
             continue;
@@ -67,8 +67,8 @@
         } else {
             // The original struct might be used in other places, so create a new block-decorated
             // struct that wraps the original struct.
-            members.Push(ir->Types().Get<core::type::StructMember>(
-                /* name */ ir->symbols.New(),
+            members.Push(ir.Types().Get<core::type::StructMember>(
+                /* name */ ir.symbols.New(),
                 /* type */ store_ty,
                 /* index */ 0u,
                 /* offset */ 0u,
@@ -79,8 +79,8 @@
         }
 
         // Create the block-decorated struct.
-        auto* block_struct = ir->Types().Get<core::type::Struct>(
-            /* name */ ir->symbols.New(),
+        auto* block_struct = ir.Types().Get<core::type::Struct>(
+            /* name */ ir.symbols.New(),
             /* members */ members,
             /* align */ store_ty->Align(),
             /* size */ tint::RoundUp(store_ty->Align(), store_ty->Size()),
@@ -89,7 +89,7 @@
 
         // Replace the old variable declaration with one that uses the block-decorated struct type.
         auto* new_var =
-            builder.Var(ir->Types().ptr(ptr->AddressSpace(), block_struct, ptr->Access()));
+            builder.Var(ir.Types().ptr(ptr->AddressSpace(), block_struct, ptr->Access()));
         if (var->BindingPoint()) {
             new_var->SetBindingPoint(var->BindingPoint()->group, var->BindingPoint()->binding);
         }
@@ -111,8 +111,8 @@
 
 }  // namespace
 
-Result<SuccessType, std::string> BlockDecoratedStructs(Module* ir) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "BlockDecoratedStructs transform");
+Result<SuccessType> BlockDecoratedStructs(Module& ir) {
+    auto result = ValidateAndDumpIfNeeded(ir, "BlockDecoratedStructs transform");
     if (!result) {
         return result;
     }
diff --git a/src/tint/lang/core/ir/transform/block_decorated_structs.h b/src/tint/lang/core/ir/transform/block_decorated_structs.h
index ae5e065..c8a6f69 100644
--- a/src/tint/lang/core/ir/transform/block_decorated_structs.h
+++ b/src/tint/lang/core/ir/transform/block_decorated_structs.h
@@ -30,8 +30,8 @@
 /// structure that is recognized as needing a block decoration in SPIR-V, potentially wrapping the
 /// existing store type in a new structure if necessary.
 /// @param module the module to transform
-/// @returns an error string on failure
-Result<SuccessType, std::string> BlockDecoratedStructs(Module* module);
+/// @returns success or failure
+Result<SuccessType> BlockDecoratedStructs(Module& module);
 
 }  // namespace tint::core::ir::transform
 
diff --git a/src/tint/lang/core/ir/transform/block_decorated_structs_test.cc b/src/tint/lang/core/ir/transform/block_decorated_structs_test.cc
index 5526360..500bfdd 100644
--- a/src/tint/lang/core/ir/transform/block_decorated_structs_test.cc
+++ b/src/tint/lang/core/ir/transform/block_decorated_structs_test.cc
@@ -49,7 +49,7 @@
 TEST_F(IR_BlockDecoratedStructsTest, Scalar_Uniform) {
     auto* buffer = b.Var(ty.ptr<uniform, i32>());
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", ty.i32());
 
@@ -83,7 +83,7 @@
 TEST_F(IR_BlockDecoratedStructsTest, Scalar_Storage) {
     auto* buffer = b.Var(ty.ptr<storage, i32>());
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", ty.void_());
     func->Block()->Append(b.Store(buffer, 42_i));
@@ -114,7 +114,7 @@
 
 TEST_F(IR_BlockDecoratedStructsTest, Scalar_PushConstant) {
     auto* buffer = b.Var(ty.ptr<push_constant, i32>());
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", ty.i32());
     b.Append(func->Block(), [&] {  //
@@ -147,7 +147,7 @@
 TEST_F(IR_BlockDecoratedStructsTest, RuntimeArray) {
     auto* buffer = b.Var(ty.ptr<storage, array<i32>>());
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", ty.void_());
 
@@ -190,7 +190,7 @@
 
     auto* buffer = b.Var(ty.ptr(storage, structure, core::Access::kReadWrite));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* i32_ptr = ty.ptr<storage, i32>();
 
@@ -243,10 +243,10 @@
 
     auto* buffer = b.Var(ty.ptr(storage, structure, core::Access::kReadWrite));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* private_var = b.Var(ty.ptr<private_, read_write>(structure));
-    b.RootBlock()->Append(private_var);
+    mod.root_block->Append(private_var);
 
     auto* func = b.Function("foo", ty.void_());
     auto* load = func->Block()->Append(b.Load(private_var));
@@ -290,7 +290,7 @@
     buffer_a->SetBindingPoint(0, 0);
     buffer_b->SetBindingPoint(0, 1);
     buffer_c->SetBindingPoint(0, 2);
-    auto* root = b.RootBlock();
+    auto* root = mod.root_block;
     root->Append(buffer_a);
     root->Append(buffer_b);
     root->Append(buffer_c);
diff --git a/src/tint/lang/core/ir/transform/builtin_polyfill.cc b/src/tint/lang/core/ir/transform/builtin_polyfill.cc
index e5d13d8..992cf86 100644
--- a/src/tint/lang/core/ir/transform/builtin_polyfill.cc
+++ b/src/tint/lang/core/ir/transform/builtin_polyfill.cc
@@ -34,22 +34,22 @@
     const BuiltinPolyfillConfig& config;
 
     /// The IR module.
-    Module* ir = nullptr;
+    Module& ir;
 
     /// The IR builder.
-    Builder b{*ir};
+    Builder b{ir};
 
     /// The type manager.
-    core::type::Manager& ty{ir->Types()};
+    core::type::Manager& ty{ir.Types()};
 
     /// The symbol table.
-    SymbolTable& sym{ir->symbols};
+    SymbolTable& sym{ir.symbols};
 
     /// Process the module.
     void Process() {
         // Find the builtin call instructions that may need to be polyfilled.
         Vector<ir::CoreBuiltinCall*, 4> worklist;
-        for (auto* inst : ir->instructions.Objects()) {
+        for (auto* inst : ir.instructions.Objects()) {
             if (!inst->Alive()) {
                 continue;
             }
@@ -124,8 +124,8 @@
             TINT_ASSERT_OR_RETURN(replacement);
 
             // Replace the old builtin call result with the new value.
-            if (auto name = ir->NameOf(builtin->Result())) {
-                ir->SetName(replacement, name);
+            if (auto name = ir.NameOf(builtin->Result())) {
+                ir.SetName(replacement, name);
             }
             builtin->Result()->ReplaceAllUsesWith(replacement);
             builtin->Destroy();
@@ -457,8 +457,8 @@
 
 }  // namespace
 
-Result<SuccessType, std::string> BuiltinPolyfill(Module* ir, const BuiltinPolyfillConfig& config) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "BuiltinPolyfill transform");
+Result<SuccessType> BuiltinPolyfill(Module& ir, const BuiltinPolyfillConfig& config) {
+    auto result = ValidateAndDumpIfNeeded(ir, "BuiltinPolyfill transform");
     if (!result) {
         return result;
     }
diff --git a/src/tint/lang/core/ir/transform/builtin_polyfill.h b/src/tint/lang/core/ir/transform/builtin_polyfill.h
index df537aa..da24f49 100644
--- a/src/tint/lang/core/ir/transform/builtin_polyfill.h
+++ b/src/tint/lang/core/ir/transform/builtin_polyfill.h
@@ -46,9 +46,8 @@
 /// features with equivalent alternatives.
 /// @param module the module to transform
 /// @param config the polyfill configuration
-/// @returns an error string on failure
-Result<SuccessType, std::string> BuiltinPolyfill(Module* module,
-                                                 const BuiltinPolyfillConfig& config);
+/// @returns success or failure
+Result<SuccessType> BuiltinPolyfill(Module& module, const BuiltinPolyfillConfig& config);
 
 }  // namespace tint::core::ir::transform
 
diff --git a/src/tint/lang/core/ir/transform/demote_to_helper.cc b/src/tint/lang/core/ir/transform/demote_to_helper.cc
index 0226e99..8749807 100644
--- a/src/tint/lang/core/ir/transform/demote_to_helper.cc
+++ b/src/tint/lang/core/ir/transform/demote_to_helper.cc
@@ -31,33 +31,29 @@
 /// PIMPL state for the transform.
 struct State {
     /// The IR module.
-    Module* ir = nullptr;
+    Module& ir;
 
     /// The IR builder.
-    Builder b{*ir};
+    Builder b{ir};
 
     /// The type manager.
-    core::type::Manager& ty{ir->Types()};
+    core::type::Manager& ty{ir.Types()};
 
     /// The global "has not discarded" flag.
     Var* continue_execution = nullptr;
 
     /// Map from function to a flag that indicates whether it (transitively) contains a discard.
-    Hashmap<Function*, bool, 4> function_discard_status;
+    Hashmap<Function*, bool, 4> function_discard_status{};
 
     /// Set of functions that have been processed.
-    Hashset<Function*, 4> processed_functions;
-
-    /// Constructor
-    /// @param mod the module
-    explicit State(Module* mod) : ir(mod) {}
+    Hashset<Function*, 4> processed_functions{};
 
     /// Process the module.
     void Process() {
         // Check each fragment shader entry point for discard instruction, potentially inside
         // functions called (transitively) by the entry point.
         Vector<Function*, 4> to_process;
-        for (auto* func : ir->functions) {
+        for (auto* func : ir.functions) {
             // If the function is a fragment shader that contains a discard, we need to process it.
             if (func->Stage() == Function::PipelineStage::kFragment) {
                 if (HasDiscard(func)) {
@@ -72,7 +68,7 @@
         // Create a boolean variable that can be used to check whether the shader has discarded.
         continue_execution = b.Var("continue_execution", ty.ptr<private_, bool>());
         continue_execution->SetInitializer(b.Constant(true));
-        b.RootBlock()->Append(continue_execution);
+        ir.root_block->Append(continue_execution);
 
         // Process each entry point function that contains a discard.
         for (auto* ep : to_process) {
@@ -203,8 +199,8 @@
 
 }  // namespace
 
-Result<SuccessType, std::string> DemoteToHelper(Module* ir) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "DemoteToHelper transform");
+Result<SuccessType> DemoteToHelper(Module& ir) {
+    auto result = ValidateAndDumpIfNeeded(ir, "DemoteToHelper transform");
     if (!result) {
         return result;
     }
diff --git a/src/tint/lang/core/ir/transform/demote_to_helper.h b/src/tint/lang/core/ir/transform/demote_to_helper.h
index b80ce75..4ba5887 100644
--- a/src/tint/lang/core/ir/transform/demote_to_helper.h
+++ b/src/tint/lang/core/ir/transform/demote_to_helper.h
@@ -33,8 +33,8 @@
 /// derivative operations. We do this by setting a global flag and masking all writes to storage
 /// buffers and textures.
 /// @param module the module to transform
-/// @returns an error string on failure
-Result<SuccessType, std::string> DemoteToHelper(Module* module);
+/// @returns success or failure
+Result<SuccessType> DemoteToHelper(Module& module);
 
 }  // namespace tint::core::ir::transform
 
diff --git a/src/tint/lang/core/ir/transform/demote_to_helper_test.cc b/src/tint/lang/core/ir/transform/demote_to_helper_test.cc
index cc10af2..3efe9f4 100644
--- a/src/tint/lang/core/ir/transform/demote_to_helper_test.cc
+++ b/src/tint/lang/core/ir/transform/demote_to_helper_test.cc
@@ -32,7 +32,7 @@
 TEST_F(IR_DemoteToHelperTest, NoModify_NoDiscard) {
     auto* buffer = b.Var("buffer", ty.ptr<storage, i32>());
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* ep = b.Function("ep", ty.f32(), Function::PipelineStage::kFragment);
     ep->SetReturnLocation(0_u, {});
@@ -66,7 +66,7 @@
 TEST_F(IR_DemoteToHelperTest, DiscardInEntryPoint_WriteInEntryPoint) {
     auto* buffer = b.Var("buffer", ty.ptr<storage, i32>());
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* front_facing = b.FunctionParam("front_facing", ty.bool_());
     front_facing->SetBuiltin(FunctionParam::Builtin::kFrontFacing);
@@ -145,7 +145,7 @@
 TEST_F(IR_DemoteToHelperTest, DiscardInEntryPoint_WriteInHelper) {
     auto* buffer = b.Var("buffer", ty.ptr<storage, i32>());
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* helper = b.Function("foo", ty.void_());
     b.Append(helper->Block(), [&] {
@@ -242,7 +242,7 @@
 TEST_F(IR_DemoteToHelperTest, DiscardInHelper_WriteInEntryPoint) {
     auto* buffer = b.Var("buffer", ty.ptr<storage, i32>());
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* cond = b.FunctionParam("cond", ty.bool_());
     auto* helper = b.Function("foo", ty.void_());
@@ -341,7 +341,7 @@
 TEST_F(IR_DemoteToHelperTest, DiscardInHelper_WriteInHelper) {
     auto* buffer = b.Var("buffer", ty.ptr<storage, i32>());
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* cond = b.FunctionParam("cond", ty.bool_());
     auto* helper = b.Function("foo", ty.void_());
@@ -438,7 +438,7 @@
 }
 
 TEST_F(IR_DemoteToHelperTest, WriteToInvocationPrivateAddressSpace) {
-    auto* priv = b.RootBlock()->Append(b.Var("priv", ty.ptr<private_, i32>()));
+    auto* priv = mod.root_block->Append(b.Var("priv", ty.ptr<private_, i32>()));
     auto* front_facing = b.FunctionParam("front_facing", ty.bool_());
     front_facing->SetBuiltin(FunctionParam::Builtin::kFrontFacing);
     auto* ep = b.Function("ep", ty.f32(), Function::PipelineStage::kFragment);
@@ -521,7 +521,7 @@
                                     core::type::TextureDimension::k2d, format, core::Access::kWrite,
                                     core::type::StorageTexture::SubtypeFor(format, ty))));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     auto* front_facing = b.FunctionParam("front_facing", ty.bool_());
     front_facing->SetBuiltin(FunctionParam::Builtin::kFrontFacing);
@@ -604,7 +604,7 @@
 TEST_F(IR_DemoteToHelperTest, AtomicStore) {
     auto* buffer = b.Var("buffer", ty.ptr(storage, ty.atomic<i32>()));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* front_facing = b.FunctionParam("front_facing", ty.bool_());
     front_facing->SetBuiltin(FunctionParam::Builtin::kFrontFacing);
@@ -683,7 +683,7 @@
 TEST_F(IR_DemoteToHelperTest, AtomicAdd) {
     auto* buffer = b.Var("buffer", ty.ptr(storage, ty.atomic<i32>()));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* front_facing = b.FunctionParam("front_facing", ty.bool_());
     front_facing->SetBuiltin(FunctionParam::Builtin::kFrontFacing);
@@ -766,7 +766,7 @@
 TEST_F(IR_DemoteToHelperTest, AtomicCompareExchange) {
     auto* buffer = b.Var("buffer", ty.ptr(storage, ty.atomic<i32>()));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* front_facing = b.FunctionParam("front_facing", ty.bool_());
     front_facing->SetBuiltin(FunctionParam::Builtin::kFrontFacing);
diff --git a/src/tint/lang/core/ir/transform/helper_test.h b/src/tint/lang/core/ir/transform/helper_test.h
index 71b2c22..b188428 100644
--- a/src/tint/lang/core/ir/transform/helper_test.h
+++ b/src/tint/lang/core/ir/transform/helper_test.h
@@ -37,7 +37,7 @@
     template <typename TRANSFORM, typename... ARGS>
     void Run(TRANSFORM&& transform_func, ARGS&&... args) {
         // Run the transform.
-        auto result = transform_func(&mod, args...);
+        auto result = transform_func(mod, args...);
         EXPECT_TRUE(result) << result.Failure();
         if (!result) {
             return;
@@ -45,7 +45,7 @@
 
         // Validate the output IR.
         auto valid = ir::Validate(mod);
-        EXPECT_TRUE(valid) << valid.Failure().str();
+        EXPECT_TRUE(valid) << valid.Failure().reason.str();
     }
 
     /// @returns the transformed module as a disassembled string
diff --git a/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc b/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc
index 2a94be1..db78182 100644
--- a/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc
+++ b/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc
@@ -35,16 +35,16 @@
     const ExternalTextureOptions& options;
 
     /// The IR module.
-    Module* ir = nullptr;
+    Module& ir;
 
     /// The IR builder.
-    Builder b{*ir};
+    Builder b{ir};
 
     /// The type manager.
-    core::type::Manager& ty{ir->Types()};
+    core::type::Manager& ty{ir.Types()};
 
     /// The symbol table.
-    SymbolTable& sym{ir->symbols};
+    SymbolTable& sym{ir.symbols};
 
     /// The gamma transfer parameters structure.
     const core::type::Struct* gamma_transfer_params_struct = nullptr;
@@ -64,9 +64,9 @@
     /// Process the module.
     void Process() {
         // Find module-scope variables that need to be replaced.
-        if (ir->root_block) {
+        if (!ir.root_block->IsEmpty()) {
             Vector<Instruction*, 4> to_remove;
-            for (auto inst : *ir->root_block) {
+            for (auto inst : *ir.root_block) {
                 auto* var = inst->As<Var>();
                 if (!var) {
                     continue;
@@ -83,7 +83,7 @@
         }
 
         // Find function parameters that need to be replaced.
-        for (auto* func : ir->functions) {
+        for (auto* func : ir.functions) {
             for (uint32_t index = 0; index < func->Params().Length(); index++) {
                 auto* param = func->Params()[index];
                 if (param->Type()->Is<core::type::ExternalTexture>()) {
@@ -101,7 +101,7 @@
     /// Replace an external texture variable declaration.
     /// @param old_var the variable declaration to replace
     void ReplaceVar(Var* old_var) {
-        auto name = ir->NameOf(old_var);
+        auto name = ir.NameOf(old_var);
         auto bp = old_var->BindingPoint();
         auto itr = options.bindings_map.find(bp.value());
         TINT_ASSERT_OR_RETURN(itr != options.bindings_map.end());
@@ -112,7 +112,7 @@
         plane_0->SetBindingPoint(bp->group, bp->binding);
         plane_0->InsertBefore(old_var);
         if (name) {
-            ir->SetName(plane_0, name.Name() + "_plane0");
+            ir.SetName(plane_0, name.Name() + "_plane0");
         }
 
         // Create a sampled texture for the second plane.
@@ -121,7 +121,7 @@
                                  new_binding_points.plane_1.binding);
         plane_1->InsertBefore(old_var);
         if (name) {
-            ir->SetName(plane_1, name.Name() + "_plane1");
+            ir.SetName(plane_1, name.Name() + "_plane1");
         }
 
         // Create a uniform buffer for the external texture parameters.
@@ -130,7 +130,7 @@
                                                  new_binding_points.params.binding);
         external_texture_params->InsertBefore(old_var);
         if (name) {
-            ir->SetName(external_texture_params, name.Name() + "_params");
+            ir.SetName(external_texture_params, name.Name() + "_params");
         }
 
         // Replace all uses of the old variable with the new ones.
@@ -143,24 +143,24 @@
     /// @param old_param the function parameter to replace
     /// @param index the index of the function parameter
     void ReplaceParameter(Function* func, FunctionParam* old_param, uint32_t index) {
-        auto name = ir->NameOf(old_param);
+        auto name = ir.NameOf(old_param);
 
         // Create a sampled texture for the first plane.
         auto* plane_0 = b.FunctionParam(SampledTexture());
         if (name) {
-            ir->SetName(plane_0, name.Name() + "_plane0");
+            ir.SetName(plane_0, name.Name() + "_plane0");
         }
 
         // Create a sampled texture for the second plane.
         auto* plane_1 = b.FunctionParam(SampledTexture());
         if (name) {
-            ir->SetName(plane_1, name.Name() + "_plane1");
+            ir.SetName(plane_1, name.Name() + "_plane1");
         }
 
         // Create the external texture parameters struct.
         auto* external_texture_params = b.FunctionParam(ExternalTextureParams());
         if (name) {
-            ir->SetName(external_texture_params, name.Name() + "_params");
+            ir.SetName(external_texture_params, name.Name() + "_params");
         }
 
         Vector<FunctionParam*, 4> new_params;
@@ -568,9 +568,8 @@
 
 }  // namespace
 
-Result<SuccessType, std::string> MultiplanarExternalTexture(Module* ir,
-                                                            const ExternalTextureOptions& options) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "MultiplanarExternalTexture transform");
+Result<SuccessType> MultiplanarExternalTexture(Module& ir, const ExternalTextureOptions& options) {
+    auto result = ValidateAndDumpIfNeeded(ir, "MultiplanarExternalTexture transform");
     if (!result) {
         return result;
     }
diff --git a/src/tint/lang/core/ir/transform/multiplanar_external_texture.h b/src/tint/lang/core/ir/transform/multiplanar_external_texture.h
index 2fc6dd9..6114d5e 100644
--- a/src/tint/lang/core/ir/transform/multiplanar_external_texture.h
+++ b/src/tint/lang/core/ir/transform/multiplanar_external_texture.h
@@ -32,9 +32,9 @@
 /// parameters that describe how the texture should be sampled.
 /// @param module the module to transform
 /// @param options the external texture options
-/// @returns an error string on failure
-Result<SuccessType, std::string> MultiplanarExternalTexture(Module* module,
-                                                            const ExternalTextureOptions& options);
+/// @returns success or failure
+Result<SuccessType> MultiplanarExternalTexture(Module& module,
+                                               const ExternalTextureOptions& options);
 
 }  // namespace tint::core::ir::transform
 
diff --git a/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc b/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc
index d38c80a..77ad1dd 100644
--- a/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc
+++ b/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc
@@ -47,7 +47,7 @@
 TEST_F(IR_MultiplanarExternalTextureTest, DeclWithNoUses) {
     auto* var = b.Var("texture", ty.ptr(handle, ty.Get<core::type::ExternalTexture>()));
     var->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {  //
@@ -111,7 +111,7 @@
 TEST_F(IR_MultiplanarExternalTextureTest, LoadWithNoUses) {
     auto* var = b.Var("texture", ty.ptr(handle, ty.Get<core::type::ExternalTexture>()));
     var->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
@@ -180,7 +180,7 @@
 TEST_F(IR_MultiplanarExternalTextureTest, TextureDimensions) {
     auto* var = b.Var("texture", ty.ptr(handle, ty.Get<core::type::ExternalTexture>()));
     var->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.vec2<u32>());
     b.Append(func->Block(), [&] {
@@ -253,7 +253,7 @@
 TEST_F(IR_MultiplanarExternalTextureTest, TextureLoad) {
     auto* var = b.Var("texture", ty.ptr(handle, ty.Get<core::type::ExternalTexture>()));
     var->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.vec4<f32>());
     auto* coords = b.FunctionParam("coords", ty.vec2<u32>());
@@ -397,7 +397,7 @@
 TEST_F(IR_MultiplanarExternalTextureTest, TextureLoad_SignedCoords) {
     auto* var = b.Var("texture", ty.ptr(handle, ty.Get<core::type::ExternalTexture>()));
     var->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.vec4<f32>());
     auto* coords = b.FunctionParam("coords", ty.vec2<i32>());
@@ -542,7 +542,7 @@
 TEST_F(IR_MultiplanarExternalTextureTest, TextureSampleBaseClampToEdge) {
     auto* var = b.Var("texture", ty.ptr(handle, ty.Get<core::type::ExternalTexture>()));
     var->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.vec4<f32>());
     auto* sampler = b.FunctionParam("sampler", ty.sampler());
@@ -700,7 +700,7 @@
 TEST_F(IR_MultiplanarExternalTextureTest, ViaUserFunctionParameter) {
     auto* var = b.Var("texture", ty.ptr(handle, ty.Get<core::type::ExternalTexture>()));
     var->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* foo = b.Function("foo", ty.vec4<f32>());
     {
@@ -885,7 +885,7 @@
 TEST_F(IR_MultiplanarExternalTextureTest, MultipleUses) {
     auto* var = b.Var("texture", ty.ptr(handle, ty.Get<core::type::ExternalTexture>()));
     var->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* foo = b.Function("foo", ty.vec4<f32>());
     {
@@ -1102,15 +1102,15 @@
 TEST_F(IR_MultiplanarExternalTextureTest, MultipleTextures) {
     auto* var_a = b.Var("texture_a", ty.ptr(handle, ty.Get<core::type::ExternalTexture>()));
     var_a->SetBindingPoint(1, 2);
-    b.RootBlock()->Append(var_a);
+    mod.root_block->Append(var_a);
 
     auto* var_b = b.Var("texture_b", ty.ptr(handle, ty.Get<core::type::ExternalTexture>()));
     var_b->SetBindingPoint(2, 2);
-    b.RootBlock()->Append(var_b);
+    mod.root_block->Append(var_b);
 
     auto* var_c = b.Var("texture_c", ty.ptr(handle, ty.Get<core::type::ExternalTexture>()));
     var_c->SetBindingPoint(3, 2);
-    b.RootBlock()->Append(var_c);
+    mod.root_block->Append(var_c);
 
     auto* foo = b.Function("foo", ty.void_());
     auto* coords = b.FunctionParam("coords", ty.vec2<u32>());
diff --git a/src/tint/lang/core/ir/transform/robustness.cc b/src/tint/lang/core/ir/transform/robustness.cc
index 77216e1..2996d52 100644
--- a/src/tint/lang/core/ir/transform/robustness.cc
+++ b/src/tint/lang/core/ir/transform/robustness.cc
@@ -37,13 +37,13 @@
     const RobustnessConfig& config;
 
     /// The IR module.
-    Module* ir = nullptr;
+    Module& ir;
 
     /// The IR builder.
-    Builder b{*ir};
+    Builder b{ir};
 
     /// The type manager.
-    core::type::Manager& ty{ir->Types()};
+    core::type::Manager& ty{ir.Types()};
 
     /// Process the module.
     void Process() {
@@ -52,7 +52,7 @@
         Vector<ir::LoadVectorElement*, 64> vector_loads;
         Vector<ir::StoreVectorElement*, 64> vector_stores;
         Vector<ir::CoreBuiltinCall*, 64> texture_calls;
-        for (auto* inst : ir->instructions.Objects()) {
+        for (auto* inst : ir.instructions.Objects()) {
             if (inst->Alive()) {
                 tint::Switch(
                     inst,  //
@@ -335,8 +335,8 @@
 
 }  // namespace
 
-Result<SuccessType, std::string> Robustness(Module* ir, const RobustnessConfig& config) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "Robustness transform");
+Result<SuccessType> Robustness(Module& ir, const RobustnessConfig& config) {
+    auto result = ValidateAndDumpIfNeeded(ir, "Robustness transform");
     if (!result) {
         return result;
     }
diff --git a/src/tint/lang/core/ir/transform/robustness.h b/src/tint/lang/core/ir/transform/robustness.h
index 82d0452..71a7c22 100644
--- a/src/tint/lang/core/ir/transform/robustness.h
+++ b/src/tint/lang/core/ir/transform/robustness.h
@@ -59,8 +59,8 @@
 /// Robustness is a transform that prevents out-of-bounds memory accesses.
 /// @param module the module to transform
 /// @param config the robustness configuration
-/// @returns an error string on failure
-Result<SuccessType, std::string> Robustness(Module* module, const RobustnessConfig& config);
+/// @returns success or failure
+Result<SuccessType> Robustness(Module& module, const RobustnessConfig& config);
 
 }  // namespace tint::core::ir::transform
 
diff --git a/src/tint/lang/core/ir/transform/robustness_test.cc b/src/tint/lang/core/ir/transform/robustness_test.cc
index b44f547..14b2977 100644
--- a/src/tint/lang/core/ir/transform/robustness_test.cc
+++ b/src/tint/lang/core/ir/transform/robustness_test.cc
@@ -784,7 +784,7 @@
 
 TEST_P(IR_RobustnessTest, Private_LoadVectorElement) {
     auto* vec = b.Var("vec", ty.ptr(private_, ty.vec4<u32>()));
-    b.RootBlock()->Append(vec);
+    mod.root_block->Append(vec);
 
     auto* func = b.Function("foo", ty.u32());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -831,7 +831,7 @@
 
 TEST_P(IR_RobustnessTest, Private_StoreVectorElement) {
     auto* vec = b.Var("vec", ty.ptr(private_, ty.vec4<u32>()));
-    b.RootBlock()->Append(vec);
+    mod.root_block->Append(vec);
 
     auto* func = b.Function("foo", ty.void_());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -878,7 +878,7 @@
 
 TEST_P(IR_RobustnessTest, Private_Access) {
     auto* arr = b.Var("arr", ty.ptr(private_, ty.array<u32, 4>()));
-    b.RootBlock()->Append(arr);
+    mod.root_block->Append(arr);
 
     auto* func = b.Function("foo", ty.u32());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -928,7 +928,7 @@
 
 TEST_P(IR_RobustnessTest, PushConstant_LoadVectorElement) {
     auto* vec = b.Var("vec", ty.ptr(push_constant, ty.vec4<u32>()));
-    b.RootBlock()->Append(vec);
+    mod.root_block->Append(vec);
 
     auto* func = b.Function("foo", ty.u32());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -975,7 +975,7 @@
 
 TEST_P(IR_RobustnessTest, PushConstant_StoreVectorElement) {
     auto* vec = b.Var("vec", ty.ptr(push_constant, ty.vec4<u32>()));
-    b.RootBlock()->Append(vec);
+    mod.root_block->Append(vec);
 
     auto* func = b.Function("foo", ty.void_());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -1022,7 +1022,7 @@
 
 TEST_P(IR_RobustnessTest, PushConstant_Access) {
     auto* arr = b.Var("arr", ty.ptr(push_constant, ty.array<u32, 4>()));
-    b.RootBlock()->Append(arr);
+    mod.root_block->Append(arr);
 
     auto* func = b.Function("foo", ty.u32());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -1073,7 +1073,7 @@
 TEST_P(IR_RobustnessTest, Storage_LoadVectorElement) {
     auto* vec = b.Var("vec", ty.ptr(storage, ty.vec4<u32>()));
     vec->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(vec);
+    mod.root_block->Append(vec);
 
     auto* func = b.Function("foo", ty.u32());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -1121,7 +1121,7 @@
 TEST_P(IR_RobustnessTest, Storage_StoreVectorElement) {
     auto* vec = b.Var("vec", ty.ptr(storage, ty.vec4<u32>()));
     vec->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(vec);
+    mod.root_block->Append(vec);
 
     auto* func = b.Function("foo", ty.void_());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -1169,7 +1169,7 @@
 TEST_P(IR_RobustnessTest, Storage_Access) {
     auto* arr = b.Var("arr", ty.ptr(storage, ty.array<u32, 4>()));
     arr->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(arr);
+    mod.root_block->Append(arr);
 
     auto* func = b.Function("foo", ty.u32());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -1220,7 +1220,7 @@
 TEST_P(IR_RobustnessTest, Unifom_LoadVectorElement) {
     auto* vec = b.Var("vec", ty.ptr(uniform, ty.vec4<u32>()));
     vec->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(vec);
+    mod.root_block->Append(vec);
 
     auto* func = b.Function("foo", ty.u32());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -1268,7 +1268,7 @@
 TEST_P(IR_RobustnessTest, Unifom_StoreVectorElement) {
     auto* vec = b.Var("vec", ty.ptr(uniform, ty.vec4<u32>()));
     vec->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(vec);
+    mod.root_block->Append(vec);
 
     auto* func = b.Function("foo", ty.void_());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -1316,7 +1316,7 @@
 TEST_P(IR_RobustnessTest, Unifom_Access) {
     auto* arr = b.Var("arr", ty.ptr(uniform, ty.array<u32, 4>()));
     arr->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(arr);
+    mod.root_block->Append(arr);
 
     auto* func = b.Function("foo", ty.u32());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -1366,7 +1366,7 @@
 
 TEST_P(IR_RobustnessTest, Workgroup_LoadVectorElement) {
     auto* vec = b.Var("vec", ty.ptr(workgroup, ty.vec4<u32>()));
-    b.RootBlock()->Append(vec);
+    mod.root_block->Append(vec);
 
     auto* func = b.Function("foo", ty.u32());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -1413,7 +1413,7 @@
 
 TEST_P(IR_RobustnessTest, Workgroup_StoreVectorElement) {
     auto* vec = b.Var("vec", ty.ptr(workgroup, ty.vec4<u32>()));
-    b.RootBlock()->Append(vec);
+    mod.root_block->Append(vec);
 
     auto* func = b.Function("foo", ty.void_());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -1460,7 +1460,7 @@
 
 TEST_P(IR_RobustnessTest, Workgroup_Access) {
     auto* arr = b.Var("arr", ty.ptr(workgroup, ty.array<u32, 4>()));
-    b.RootBlock()->Append(arr);
+    mod.root_block->Append(arr);
 
     auto* func = b.Function("foo", ty.u32());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -1643,7 +1643,7 @@
 TEST_P(IR_RobustnessTest, RuntimeSizedArray_ConstIndex) {
     auto* arr = b.Var("arr", ty.ptr(storage, ty.array<u32>()));
     arr->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(arr);
+    mod.root_block->Append(arr);
 
     auto* func = b.Function("foo", ty.u32());
     b.Append(func->Block(), [&] {
@@ -1694,7 +1694,7 @@
 TEST_P(IR_RobustnessTest, RuntimeSizedArray_DynamicIndex) {
     auto* arr = b.Var("arr", ty.ptr(storage, ty.array<u32>()));
     arr->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(arr);
+    mod.root_block->Append(arr);
 
     auto* func = b.Function("foo", ty.u32());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -1752,7 +1752,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(storage, structure));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", ty.u32());
     b.Append(func->Block(), [&] {
@@ -1817,7 +1817,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(storage, structure));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", ty.u32());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -1879,7 +1879,7 @@
 TEST_P(IR_RobustnessTest, RuntimeSizedArray_DisableClamping) {
     auto* arr = b.Var("arr", ty.ptr(storage, ty.array<u32>()));
     arr->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(arr);
+    mod.root_block->Append(arr);
 
     auto* func = b.Function("foo", ty.u32());
     auto* idx = b.FunctionParam("idx", ty.u32());
@@ -1939,7 +1939,7 @@
         "texture",
         ty.ptr(handle, ty.Get<type::SampledTexture>(type::TextureDimension::k2d, ty.f32()), read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     auto* func = b.Function("foo", ty.vec2<u32>());
     b.Append(func->Block(), [&] {
@@ -1977,7 +1977,7 @@
         "texture",
         ty.ptr(handle, ty.Get<type::SampledTexture>(type::TextureDimension::k2d, ty.f32()), read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     auto* func = b.Function("foo", ty.vec2<u32>());
     auto* level = b.FunctionParam("level", ty.u32());
@@ -2032,7 +2032,7 @@
         "texture",
         ty.ptr(handle, ty.Get<type::SampledTexture>(type::TextureDimension::k1d, ty.f32()), read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.vec4<f32>());
@@ -2129,7 +2129,7 @@
         "texture",
         ty.ptr(handle, ty.Get<type::SampledTexture>(type::TextureDimension::k2d, ty.f32()), read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.vec4<f32>());
@@ -2227,7 +2227,7 @@
         ty.ptr(handle, ty.Get<type::SampledTexture>(type::TextureDimension::k2dArray, ty.f32()),
                read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.vec4<f32>());
@@ -2333,7 +2333,7 @@
         "texture",
         ty.ptr(handle, ty.Get<type::SampledTexture>(type::TextureDimension::k3d, ty.f32()), read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.vec4<f32>());
@@ -2431,7 +2431,7 @@
         ty.ptr(handle, ty.Get<type::MultisampledTexture>(type::TextureDimension::k2d, ty.f32()),
                read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.vec4<f32>());
@@ -2520,7 +2520,7 @@
     auto* texture = b.Var(
         "texture", ty.ptr(handle, ty.Get<type::DepthTexture>(type::TextureDimension::k2d), read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.f32());
@@ -2615,7 +2615,7 @@
         b.Var("texture",
               ty.ptr(handle, ty.Get<type::DepthTexture>(type::TextureDimension::k2dArray), read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.f32());
@@ -2721,7 +2721,7 @@
         "texture",
         ty.ptr(handle, ty.Get<type::DepthMultisampledTexture>(type::TextureDimension::k2d), read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.f32());
@@ -2807,7 +2807,7 @@
 TEST_P(IR_RobustnessTest, TextureLoad_External) {
     auto* texture = b.Var("texture", ty.ptr(handle, ty.Get<type::ExternalTexture>(), read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.vec4<f32>());
@@ -2897,7 +2897,7 @@
                                                   type::StorageTexture::SubtypeFor(format, ty)),
                      read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.vec4<f32>());
@@ -2987,7 +2987,7 @@
                                                   type::StorageTexture::SubtypeFor(format, ty)),
                      read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.vec4<f32>());
@@ -3077,7 +3077,7 @@
                                             type::StorageTexture::SubtypeFor(format, ty)),
                read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.vec4<f32>());
@@ -3178,7 +3178,7 @@
                                                   type::StorageTexture::SubtypeFor(format, ty)),
                      read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.vec4<f32>());
@@ -3268,7 +3268,7 @@
                                                   type::StorageTexture::SubtypeFor(format, ty)),
                      read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.void_());
@@ -3360,7 +3360,7 @@
                                                   type::StorageTexture::SubtypeFor(format, ty)),
                      read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.void_());
@@ -3452,7 +3452,7 @@
                                                   type::StorageTexture::SubtypeFor(format, ty)),
                      read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.void_());
@@ -3553,7 +3553,7 @@
                                                   type::StorageTexture::SubtypeFor(format, ty)),
                      read));
     texture->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(texture);
+    mod.root_block->Append(texture);
 
     {
         auto* func = b.Function("load_signed", ty.void_());
diff --git a/src/tint/lang/core/ir/transform/shader_io.cc b/src/tint/lang/core/ir/transform/shader_io.cc
index 3edc00d..df9987c 100644
--- a/src/tint/lang/core/ir/transform/shader_io.cc
+++ b/src/tint/lang/core/ir/transform/shader_io.cc
@@ -75,23 +75,19 @@
 /// PIMPL state for the transform.
 struct State {
     /// The IR module.
-    Module* ir = nullptr;
+    Module& ir;
     /// The IR builder.
-    Builder b{*ir};
+    Builder b{ir};
     /// The type manager.
-    core::type::Manager& ty{ir->Types()};
+    core::type::Manager& ty{ir.Types()};
     /// The set of struct members that need to have their IO attributes stripped.
-    Hashset<const core::type::StructMember*, 8> members_to_strip;
+    Hashset<const core::type::StructMember*, 8> members_to_strip{};
 
     /// The entry point currently being processed.
     Function* func = nullptr;
 
     /// The backend state object for the current entry point.
-    std::unique_ptr<ShaderIOBackendState> backend;
-
-    /// Constructor
-    /// @param mod the module
-    explicit State(Module* mod) : ir(mod) {}
+    std::unique_ptr<ShaderIOBackendState> backend{};
 
     /// Process an entry point.
     /// @param f the original entry point function
@@ -109,7 +105,7 @@
         std::optional<uint32_t> vertex_point_size_index;
         if (func->Stage() == Function::PipelineStage::kVertex && backend->NeedsVertexPointSize()) {
             vertex_point_size_index =
-                backend->AddOutput(ir->symbols.New("vertex_point_size"), ty.f32(),
+                backend->AddOutput(ir.symbols.New("vertex_point_size"), ty.f32(),
                                    {{}, {}, {BuiltinValue::kPointSize}, {}, false});
         }
 
@@ -118,10 +114,10 @@
 
         // Rename the old function and remove its pipeline stage and workgroup size, as we will be
         // wrapping it with a new entry point.
-        auto name = ir->NameOf(func).Name();
+        auto name = ir.NameOf(func).Name();
         auto stage = func->Stage();
         auto wgsize = func->WorkgroupSize();
-        ir->SetName(func, name + "_inner");
+        ir.SetName(func, name + "_inner");
         func->SetStage(Function::PipelineStage::kUndefined);
         func->ClearWorkgroupSize();
 
@@ -156,7 +152,7 @@
                         func->Stage() != Function::PipelineStage::kFragment) {
                         attributes.interpolation = {};
                     }
-                    backend->AddInput(ir->symbols.Register(name), member->Type(), attributes);
+                    backend->AddInput(ir.symbols.Register(name), member->Type(), attributes);
                     members_to_strip.Add(member);
                 }
             } else {
@@ -175,7 +171,7 @@
                 attributes.invariant = param->Invariant();
                 param->SetInvariant(false);
 
-                auto name = ir->NameOf(param);
+                auto name = ir.NameOf(param);
                 backend->AddInput(name, param->Type(), std::move(attributes));
             }
         }
@@ -194,7 +190,7 @@
                 if (attributes.interpolation && func->Stage() != Function::PipelineStage::kVertex) {
                     attributes.interpolation = {};
                 }
-                backend->AddOutput(ir->symbols.Register(name), member->Type(), attributes);
+                backend->AddOutput(ir.symbols.Register(name), member->Type(), attributes);
                 members_to_strip.Add(member);
             }
         } else {
@@ -213,7 +209,7 @@
             attributes.invariant = func->ReturnInvariant();
             func->SetReturnInvariant(false);
 
-            backend->AddOutput(ir->symbols.New(), func->ReturnType(), std::move(attributes));
+            backend->AddOutput(ir.symbols.New(), func->ReturnType(), std::move(attributes));
         }
     }
 
@@ -265,9 +261,9 @@
 
 }  // namespace
 
-void RunShaderIOBase(Module* module, std::function<MakeBackendStateFunc> make_backend_state) {
-    State state(module);
-    for (auto* func : module->functions) {
+void RunShaderIOBase(Module& module, std::function<MakeBackendStateFunc> make_backend_state) {
+    State state{module};
+    for (auto* func : module.functions) {
         // Only process entry points.
         if (func->Stage() == Function::PipelineStage::kUndefined) {
             continue;
diff --git a/src/tint/lang/core/ir/transform/shader_io.h b/src/tint/lang/core/ir/transform/shader_io.h
index 22210c0..108bf87 100644
--- a/src/tint/lang/core/ir/transform/shader_io.h
+++ b/src/tint/lang/core/ir/transform/shader_io.h
@@ -28,7 +28,7 @@
     /// Constructor
     /// @param mod the IR module
     /// @param f the entry point function
-    ShaderIOBackendState(Module* mod, Function* f) : ir(mod), func(f) {}
+    ShaderIOBackendState(Module& mod, Function* f) : ir(mod), func(f) {}
 
     /// Destructor
     virtual ~ShaderIOBackendState();
@@ -82,13 +82,13 @@
 
   protected:
     /// The IR module.
-    Module* ir = nullptr;
+    Module& ir;
 
     /// The IR builder.
-    Builder b{*ir};
+    Builder b{ir};
 
     /// The type manager.
-    core::type::Manager& ty{ir->Types()};
+    core::type::Manager& ty{ir.Types()};
 
     /// The original entry point function.
     Function* func = nullptr;
@@ -101,11 +101,11 @@
 };
 
 /// The signature for a function that creates a backend state object.
-using MakeBackendStateFunc = std::unique_ptr<ShaderIOBackendState>(Module*, Function*);
+using MakeBackendStateFunc = std::unique_ptr<ShaderIOBackendState>(Module&, Function*);
 
 /// @param module the module to transform
 /// @param make_backend_state a function that creates a backend state object
-void RunShaderIOBase(Module* module, std::function<MakeBackendStateFunc> make_backend_state);
+void RunShaderIOBase(Module& module, std::function<MakeBackendStateFunc> make_backend_state);
 
 }  // namespace tint::core::ir::transform
 
diff --git a/src/tint/lang/core/ir/transform/std140.cc b/src/tint/lang/core/ir/transform/std140.cc
index ed73e70..03e9f8c 100644
--- a/src/tint/lang/core/ir/transform/std140.cc
+++ b/src/tint/lang/core/ir/transform/std140.cc
@@ -33,16 +33,16 @@
 /// PIMPL state for the transform.
 struct State {
     /// The IR module.
-    Module* ir = nullptr;
+    Module& ir;
 
     /// The IR builder.
-    Builder b{*ir};
+    Builder b{ir};
 
     /// The type manager.
-    core::type::Manager& ty{ir->Types()};
+    core::type::Manager& ty{ir.Types()};
 
     /// The symbol table.
-    SymbolTable& sym{ir->symbols};
+    SymbolTable& sym{ir.symbols};
 
     /// Map from original type to a new type with decomposed matrices.
     Hashmap<const core::type::Type*, const core::type::Type*, 4> rewritten_types{};
@@ -55,13 +55,13 @@
 
     /// Process the module.
     void Process() {
-        if (!ir->root_block) {
+        if (ir.root_block->IsEmpty()) {
             return;
         }
 
         // Find uniform buffers that contain matrices that need to be decomposed.
         Vector<Var*, 8> buffer_variables;
-        for (auto inst : *ir->root_block) {
+        for (auto inst : *ir.root_block) {
             auto* var = inst->As<Var>();
             if (!var || !var->Alive()) {
                 continue;
@@ -83,8 +83,8 @@
             auto* store_type = var->Result()->Type()->As<core::type::Pointer>()->StoreType();
             auto* new_var = b.Var(ty.ptr(uniform, RewriteType(store_type)));
             new_var->SetBindingPoint(bp->group, bp->binding);
-            if (auto name = ir->NameOf(var)) {
-                ir->SetName(new_var->Result(), name);
+            if (auto name = ir.NameOf(var)) {
+                ir.SetName(new_var->Result(), name);
             }
 
             // Replace every instruction that uses the original variable.
@@ -329,8 +329,8 @@
 
 }  // namespace
 
-Result<SuccessType, std::string> Std140(Module* ir) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "Std140 transform");
+Result<SuccessType> Std140(Module& ir) {
+    auto result = ValidateAndDumpIfNeeded(ir, "Std140 transform");
     if (!result) {
         return result;
     }
diff --git a/src/tint/lang/core/ir/transform/std140.h b/src/tint/lang/core/ir/transform/std140.h
index 42f12c7..db6545c 100644
--- a/src/tint/lang/core/ir/transform/std140.h
+++ b/src/tint/lang/core/ir/transform/std140.h
@@ -29,8 +29,8 @@
 /// Std140 is a transform that rewrites matrix types in the uniform address space to conform to
 /// GLSL's std140 layout rules.
 /// @param module the module to transform
-/// @returns an error string on failure
-Result<SuccessType, std::string> Std140(Module* module);
+/// @returns success or failure
+Result<SuccessType> Std140(Module& module);
 
 }  // namespace tint::core::ir::transform
 
diff --git a/src/tint/lang/core/ir/transform/std140_test.cc b/src/tint/lang/core/ir/transform/std140_test.cc
index 4fca697..6fd4d7f 100644
--- a/src/tint/lang/core/ir/transform/std140_test.cc
+++ b/src/tint/lang/core/ir/transform/std140_test.cc
@@ -56,7 +56,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(uniform, structure));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", mat);
     b.Append(func->Block(), [&] {
@@ -100,7 +100,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(uniform, structure));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", mat);
     b.Append(func->Block(), [&] {
@@ -144,7 +144,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(storage, structure));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", mat);
     b.Append(func->Block(), [&] {
@@ -190,7 +190,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(uniform, structure));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", mat);
     b.Append(func->Block(), [&] {
@@ -233,7 +233,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(uniform, structure));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", mat);
     b.Append(func->Block(), [&] {
@@ -304,7 +304,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(uniform, structure));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", mat->ColumnType());
     b.Append(func->Block(), [&] {
@@ -376,7 +376,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(uniform, structure));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", ty.f32());
     b.Append(func->Block(), [&] {
@@ -449,7 +449,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(uniform, structure));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", structure);
     b.Append(func->Block(), [&] {
@@ -527,7 +527,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(uniform, outer));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", outer);
     b.Append(func->Block(), [&] {
@@ -647,7 +647,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(uniform, outer));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", inner);
     b.Append(func->Block(), [&] {
@@ -738,7 +738,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(uniform, outer));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", outer);
     b.Append(func->Block(), [&] {
@@ -832,7 +832,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(uniform, outer));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
@@ -1002,7 +1002,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(uniform, outer));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
@@ -1177,7 +1177,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(uniform, outer));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", ty.void_());
     auto* arr_idx = b.FunctionParam("arr_idx", ty.i32());
@@ -1351,7 +1351,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(uniform, structure));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
@@ -1452,7 +1452,7 @@
 
     auto* buffer = b.Var("buffer", ty.ptr(uniform, structure));
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
diff --git a/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc
new file mode 100644
index 0000000..4e9c88b
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc
@@ -0,0 +1,403 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/lang/core/ir/transform/zero_init_workgroup_memory.h"
+
+#include <map>
+#include <utility>
+
+#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/utils/containers/reverse.h"
+
+using namespace tint::core::fluent_types;     // NOLINT
+using namespace tint::core::number_suffixes;  // NOLINT
+
+namespace tint::core::ir::transform {
+
+namespace {
+
+/// PIMPL state for the transform.
+struct State {
+    /// The IR module.
+    Module& ir;
+
+    /// The IR builder.
+    Builder b{ir};
+
+    /// The type manager.
+    core::type::Manager& ty{ir.Types()};
+
+    /// VarSet is a hash set of workgroup variables.
+    using VarSet = Hashset<Var*, 8>;
+
+    /// A map from variable to an ID used for sorting.
+    Hashmap<Var*, uint32_t, 8> var_to_id{};
+
+    /// A map from blocks to their directly referenced workgroup variables.
+    Hashmap<Block*, VarSet, 64> block_to_direct_vars{};
+
+    /// A map from functions to their transitively referenced workgroup variables.
+    Hashmap<Function*, VarSet, 8> function_to_transitive_vars{};
+
+    /// ArrayIndex represents a required array index for an access instruction.
+    struct ArrayIndex {
+        /// The size of the array that will be indexed.
+        uint32_t count = 0u;
+    };
+
+    /// Index represents an index for an access instruction, which is either a constant value or
+    /// an array index that will be dynamically calculated from an array size.
+    using Index = std::variant<uint32_t, ArrayIndex>;
+
+    /// Store describes a store to a sub-element of a workgroup variable.
+    struct Store {
+        /// The workgroup variable.
+        Var* var = nullptr;
+        /// The store type of the element.
+        const type::Type* store_type = nullptr;
+        /// The list of index operands to get to the element.
+        Vector<Index, 4> indices;
+    };
+
+    /// StoreList is a list of `Store` descriptors.
+    using StoreList = Vector<Store, 8>;
+
+    /// StoreMap is a map from iteration count to a list of `Store` descriptors.
+    using StoreMap = Hashmap<uint32_t, StoreList, 8>;
+
+    /// Process the module.
+    void Process() {
+        if (ir.root_block->IsEmpty()) {
+            return;
+        }
+
+        // Loop over module-scope variables, looking for workgroup variables.
+        uint32_t next_id = 0;
+        for (auto inst : *ir.root_block) {
+            if (auto* var = inst->As<Var>()) {
+                auto* ptr = var->Result()->Type()->As<core::type::Pointer>();
+                if (ptr && ptr->AddressSpace() == core::AddressSpace::kWorkgroup) {
+                    // Record the usage of the variable for each block that references it.
+                    var->Result()->ForEachUse([&](const Usage& use) {
+                        block_to_direct_vars.GetOrZero(use.instruction->Block())->Add(var);
+                    });
+                    var_to_id.Add(var, next_id++);
+                }
+            }
+        }
+
+        // Process each entry point function.
+        for (auto* func : ir.functions) {
+            if (func->Stage() == Function::PipelineStage::kCompute) {
+                ProcessEntryPoint(func);
+            }
+        }
+    }
+
+    /// Process an entry point function to zero-initialize the workgroup variables that it uses.
+    /// @param func the entry point function
+    void ProcessEntryPoint(Function* func) {
+        // Get list of transitively referenced workgroup variables.
+        auto vars = GetReferencedVars(func);
+        if (vars.IsEmpty()) {
+            return;
+        }
+
+        // Sort the variables to get deterministic output in tests.
+        auto sorted_vars = vars.Vector();
+        sorted_vars.Sort([&](Var* first, Var* second) {
+            return *var_to_id.Get(first) < *var_to_id.Get(second);
+        });
+
+        // Build list of store descriptors for all workgroup variables.
+        StoreMap stores;
+        for (auto* var : sorted_vars) {
+            PrepareStores(var, var->Result()->Type()->UnwrapPtr(), 1, {}, stores);
+        }
+
+        // Sort the iteration counts to get deterministic output in tests.
+        auto sorted_iteration_counts = stores.Keys();
+        sorted_iteration_counts.Sort();
+
+        // Capture the first instruction of the function.
+        // All new instructions will be inserted before this.
+        auto* function_start = func->Block()->Front();
+
+        // Get the local invocation index and the linearized workgroup size.
+        auto* local_index = GetLocalInvocationIndex(func);
+        auto wgsizes = func->WorkgroupSize().value();
+        auto wgsize = wgsizes[0] * wgsizes[1] * wgsizes[2];
+
+        // Insert instructions to zero-initialize every variable.
+        b.InsertBefore(function_start, [&] {
+            for (auto count : sorted_iteration_counts) {
+                auto element_stores = stores.Get(count);
+                if (count == 1u) {
+                    // Make the first invocation in the group perform all of the non-arrayed stores.
+                    auto* ifelse = b.If(b.Equal(ty.bool_(), local_index, 0_u));
+                    b.Append(ifelse->True(), [&] {
+                        for (auto& store : *element_stores) {
+                            GenerateStore(store, count, b.Constant(0_u));
+                        }
+                        b.ExitIf(ifelse);
+                    });
+                } else {
+                    // Use a loop for arrayed stores.
+                    GenerateZeroingLoop(local_index, count, wgsize, *element_stores);
+                }
+            }
+            b.Call(ty.void_(), core::BuiltinFn::kWorkgroupBarrier);
+        });
+    }
+
+    /// Get the set of workgroup variables transitively referenced by @p func.
+    /// @param func the function
+    /// @returns the set of transitively referenced workgroup variables
+    VarSet GetReferencedVars(Function* func) {
+        return function_to_transitive_vars.GetOrCreate(func, [&] {
+            VarSet vars;
+            GetReferencedVars(func->Block(), vars);
+            return vars;
+        });
+    }
+
+    /// Get the set of workgroup variables transitively referenced by @p block.
+    /// @param block the block
+    /// @param vars the set of transitively referenced workgroup variables to populate
+    void GetReferencedVars(Block* block, VarSet& vars) {
+        // Add directly referenced vars.
+        if (auto itr = block_to_direct_vars.Find(block)) {
+            for (auto* var : *itr) {
+                vars.Add(var);
+            }
+        }
+
+        // Loop over instructions in the block.
+        for (auto* inst : *block) {
+            tint::Switch(
+                inst,
+                [&](UserCall* call) {
+                    // Get variables referenced by a function called from this block.
+                    auto callee_vars = GetReferencedVars(call->Target());
+                    for (auto* var : callee_vars) {
+                        vars.Add(var);
+                    }
+                },
+                [&](ControlInstruction* ctrl) {
+                    // Recurse into control instructions and gather their referenced vars.
+                    ctrl->ForeachBlock([&](Block* blk) { GetReferencedVars(blk, vars); });
+                });
+        }
+    }
+
+    /// Recursively generate store descriptors for a workgroup variable.
+    /// Determines the combined array iteration count of each inner element.
+    /// @param var the workgroup variable
+    /// @param type the current element type
+    /// @param iteration_count the iteration count of this inner element of the variable
+    /// @param indices the access indices needed to get to this element
+    /// @param stores the map of stores to populate
+    void PrepareStores(Var* var,
+                       const type::Type* type,
+                       uint32_t iteration_count,
+                       Vector<Index, 4> indices,
+                       StoreMap& stores) {
+        // If this type can be trivially zeroed, store to the whole element.
+        if (CanTriviallyZero(type)) {
+            stores.GetOrZero(iteration_count)->Push(Store{var, type, indices});
+            return;
+        }
+
+        tint::Switch(
+            type,
+            [&](const type::Array* arr) {
+                // Add an array index to the list and recurse into the element type.
+                TINT_ASSERT(arr->ConstantCount());
+                auto count = arr->ConstantCount().value();
+                auto new_indices = indices;
+                if (count > 1) {
+                    new_indices.Push(ArrayIndex{count});
+                } else {
+                    new_indices.Push(0u);
+                }
+                PrepareStores(var, arr->ElemType(), iteration_count * count, new_indices, stores);
+            },
+            [&](const type::Atomic*) {
+                stores.GetOrZero(iteration_count)->Push(Store{var, type, indices});
+            },
+            [&](const type::Struct* str) {
+                for (auto* member : str->Members()) {
+                    // Add the member index to the index list and recurse into its type.
+                    auto new_indices = indices;
+                    new_indices.Push(member->Index());
+                    PrepareStores(var, member->Type(), iteration_count, new_indices, stores);
+                }
+            },
+            [&](Default) { TINT_UNREACHABLE(); });
+    }
+
+    /// Get or inject an entry point builtin for the local invocation index.
+    /// @param func the entry point function
+    /// @returns the local invocation index builtin
+    Value* GetLocalInvocationIndex(Function* func) {
+        // Look for an existing local_invocation_index builtin parameter.
+        for (auto* param : func->Params()) {
+            if (auto* str = param->Type()->As<type::Struct>()) {
+                // Check each member for the local invocation index builtin attribute.
+                for (auto* member : str->Members()) {
+                    if (member->Attributes().builtin && member->Attributes().builtin.value() ==
+                                                            BuiltinValue::kLocalInvocationIndex) {
+                        auto* access = b.Access(ty.u32(), param, u32(member->Index()));
+                        access->InsertBefore(func->Block()->Front());
+                        return access->Result();
+                    }
+                }
+            } else {
+                // Check if the parameter is the local invocation index.
+                if (param->Builtin() &&
+                    param->Builtin().value() == FunctionParam::Builtin::kLocalInvocationIndex) {
+                    return param;
+                }
+            }
+        }
+
+        // No local invocation index was found, so add one to the parameter list and use that.
+        Vector<FunctionParam*, 4> params = func->Params();
+        auto* param = b.FunctionParam("tint_local_index", ty.u32());
+        param->SetBuiltin(FunctionParam::Builtin::kLocalInvocationIndex);
+        params.Push(param);
+        func->SetParams(params);
+        return param;
+    }
+
+    /// Generate the store instruction for a given store descriptor.
+    /// @param store the store descriptor
+    /// @param total_count the total number of elements that will be zeroed
+    /// @param linear_index the linear index of the single element that will be zeroed
+    void GenerateStore(const Store& store, uint32_t total_count, Value* linear_index) {
+        auto* to = store.var->Result();
+        if (!store.indices.IsEmpty()) {
+            // Build the access indices to get to the target element.
+            // We walk backwards along the index list so that adjacent invocation store to
+            // adjacent array elements.
+            uint32_t count = 1;
+            Vector<Value*, 4> indices;
+            for (auto idx : Reverse(store.indices)) {
+                if (std::holds_alternative<ArrayIndex>(idx)) {
+                    // Array indices are computed from the linear index based on the size of the
+                    // array and the size of the sub-arrays that have already been indexed.
+                    auto array_index = std::get<ArrayIndex>(idx);
+                    Value* index = linear_index;
+                    if (count > 1) {
+                        index = b.Divide(ty.u32(), index, u32(count))->Result();
+                    }
+                    if (total_count > count * array_index.count) {
+                        index = b.Modulo(ty.u32(), index, u32(array_index.count))->Result();
+                    }
+                    indices.Push(index);
+                    count *= array_index.count;
+                } else {
+                    // Constant indices are added to the list unmodified.
+                    indices.Push(b.Constant(u32(std::get<uint32_t>(idx))));
+                }
+            }
+            indices.Reverse();
+            to = b.Access(ty.ptr(workgroup, store.store_type), to, indices)->Result();
+        }
+
+        // Generate the store instruction.
+        if (auto* atomic = store.store_type->As<type::Atomic>()) {
+            auto* zero = b.Constant(ir.constant_values.Zero(atomic->Type()));
+            b.Call(ty.void_(), core::BuiltinFn::kAtomicStore, to, zero);
+        } else {
+            auto* zero = b.Constant(ir.constant_values.Zero(store.store_type));
+            b.Store(to, zero);
+        }
+    }
+
+    /// Generate a loop for a list of stores with the same iteration count.
+    /// @param local_index the local invocation index
+    /// @param total_count the number of iterations needed to store to all elements
+    /// @param wgsize the linearized workgroup size
+    /// @param stores the list of store descriptors
+    void GenerateZeroingLoop(Value* local_index,
+                             uint32_t total_count,
+                             uint32_t wgsize,
+                             const StoreList& stores) {
+        // The loop is equivalent to:
+        //   for (var idx = local_index; idx < linear_iteration_count; idx += wgsize) {
+        //     <store to elements at `idx`>
+        //   }
+        auto* loop = b.Loop();
+        auto* index = b.BlockParam(ty.u32());
+        loop->Body()->SetParams({index});
+        b.Append(loop->Initializer(), [&] {  //
+            b.NextIteration(loop, local_index);
+        });
+        b.Append(loop->Body(), [&] {
+            // Exit the loop when the iteration count has been exceeded.
+            auto* gt_max = b.GreaterThan(ty.bool_(), index, u32(total_count - 1u));
+            auto* ifelse = b.If(gt_max);
+            b.Append(ifelse->True(), [&] {  //
+                b.ExitLoop(loop);
+            });
+
+            // Insert all of the store instructions.
+            for (auto& store : stores) {
+                GenerateStore(store, total_count, index);
+            }
+
+            b.Continue(loop);
+        });
+        b.Append(loop->Continuing(), [&] {  //
+            // Increment the loop index by linearized workgroup size.
+            b.NextIteration(loop, b.Add(ty.u32(), index, u32(wgsize)));
+        });
+    }
+
+    /// Check if a type can be efficiently zeroed with a single store. Returns `false` if there are
+    /// any nested arrays or atomics.
+    /// @param type the type to inspect
+    /// @returns true if a variable with store type @p ty can be efficiently zeroed
+    bool CanTriviallyZero(const core::type::Type* type) {
+        if (type->IsAnyOf<core::type::Atomic, core::type::Array>()) {
+            return false;
+        }
+        if (auto* str = type->As<core::type::Struct>()) {
+            for (auto* member : str->Members()) {
+                if (!CanTriviallyZero(member->Type())) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+};
+
+}  // namespace
+
+Result<SuccessType> ZeroInitWorkgroupMemory(Module& ir) {
+    auto result = ValidateAndDumpIfNeeded(ir, "ZeroInitWorkgroupMemory transform");
+    if (!result) {
+        return result;
+    }
+
+    State{ir}.Process();
+
+    return Success;
+}
+
+}  // namespace tint::core::ir::transform
diff --git a/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.h b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.h
new file mode 100644
index 0000000..02306c5
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.h
@@ -0,0 +1,37 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_LANG_CORE_IR_TRANSFORM_ZERO_INIT_WORKGROUP_MEMORY_H_
+#define SRC_TINT_LANG_CORE_IR_TRANSFORM_ZERO_INIT_WORKGROUP_MEMORY_H_
+
+#include <string>
+
+#include "src/tint/utils/result/result.h"
+
+// Forward declarations.
+namespace tint::core::ir {
+class Module;
+}
+
+namespace tint::core::ir::transform {
+
+/// ZeroInitWorkgroupMemory is a transform that injects code at the top of each entry point to
+/// zero-initialize workgroup memory used by that entry point.
+/// @param module the module to transform
+/// @returns success or failure
+Result<SuccessType> ZeroInitWorkgroupMemory(Module& module);
+
+}  // namespace tint::core::ir::transform
+
+#endif  // SRC_TINT_LANG_CORE_IR_TRANSFORM_ZERO_INIT_WORKGROUP_MEMORY_H_
diff --git a/src/tint/lang/core/ir/transform/zero_init_workgroup_memory_test.cc b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory_test.cc
new file mode 100644
index 0000000..026d5e3
--- /dev/null
+++ b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory_test.cc
@@ -0,0 +1,1940 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/lang/core/ir/transform/zero_init_workgroup_memory.h"
+
+#include <utility>
+
+#include "src/tint/lang/core/ir/transform/helper_test.h"
+
+namespace tint::core::ir::transform {
+namespace {
+
+using namespace tint::core::fluent_types;     // NOLINT
+using namespace tint::core::number_suffixes;  // NOLINT
+
+class IR_ZeroInitWorkgroupMemoryTest : public TransformTest {
+  protected:
+    Function* MakeEntryPoint(const char* name,
+                             uint32_t wgsize_x,
+                             uint32_t wgsize_y,
+                             uint32_t wgsize_z) {
+        auto* func = b.Function(name, ty.void_(), Function::PipelineStage::kCompute);
+        func->SetWorkgroupSize(wgsize_x, wgsize_y, wgsize_z);
+        return func;
+    }
+
+    Var* MakeVar(const char* name, const type::Type* store_type) {
+        auto* var = b.Var(name, ty.ptr(workgroup, store_type));
+        mod.root_block->Append(var);
+        return var;
+    }
+};
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, NoRootBlock) {
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Return(func);
+    });
+
+    auto* expect = R"(
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
+  %b1 = block {
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, WorkgroupVarUnused) {
+    MakeVar("wgvar", ty.i32());
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, i32, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = src;
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, ScalarBool) {
+    auto* var = MakeVar("wgvar", ty.bool_());
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, bool, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    %3:bool = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, bool, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %4:bool = eq %tint_local_index, 0u
+    if %4 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        store %wgvar, false
+        exit_if  # if_1
+      }
+    }
+    %5:void = workgroupBarrier
+    %6:bool = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, ScalarI32) {
+    auto* var = MakeVar("wgvar", ty.i32());
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, i32, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    %3:i32 = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, i32, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %4:bool = eq %tint_local_index, 0u
+    if %4 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        store %wgvar, 0i
+        exit_if  # if_1
+      }
+    }
+    %5:void = workgroupBarrier
+    %6:i32 = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, ScalarU32) {
+    auto* var = MakeVar("wgvar", ty.u32());
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, u32, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    %3:u32 = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, u32, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %4:bool = eq %tint_local_index, 0u
+    if %4 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        store %wgvar, 0u
+        exit_if  # if_1
+      }
+    }
+    %5:void = workgroupBarrier
+    %6:u32 = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, ScalarF32) {
+    auto* var = MakeVar("wgvar", ty.f32());
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, f32, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    %3:f32 = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, f32, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %4:bool = eq %tint_local_index, 0u
+    if %4 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        store %wgvar, 0.0f
+        exit_if  # if_1
+      }
+    }
+    %5:void = workgroupBarrier
+    %6:f32 = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, ScalarF16) {
+    auto* var = MakeVar("wgvar", ty.f16());
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, f16, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    %3:f16 = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, f16, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %4:bool = eq %tint_local_index, 0u
+    if %4 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        store %wgvar, 0.0h
+        exit_if  # if_1
+      }
+    }
+    %5:void = workgroupBarrier
+    %6:f16 = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, AtomicI32) {
+    auto* var = MakeVar("wgvar", ty.atomic<i32>());
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Call(ty.i32(), core::BuiltinFn::kAtomicLoad, var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, atomic<i32>, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    %3:i32 = atomicLoad %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, atomic<i32>, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %4:bool = eq %tint_local_index, 0u
+    if %4 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        %5:void = atomicStore %wgvar, 0i
+        exit_if  # if_1
+      }
+    }
+    %6:void = workgroupBarrier
+    %7:i32 = atomicLoad %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, AtomicU32) {
+    auto* var = MakeVar("wgvar", ty.atomic<u32>());
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Call(ty.u32(), core::BuiltinFn::kAtomicLoad, var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, atomic<u32>, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    %3:u32 = atomicLoad %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, atomic<u32>, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %4:bool = eq %tint_local_index, 0u
+    if %4 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        %5:void = atomicStore %wgvar, 0u
+        exit_if  # if_1
+      }
+    }
+    %6:void = workgroupBarrier
+    %7:u32 = atomicLoad %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, ArrayOfI32) {
+    auto* var = MakeVar("wgvar", ty.array<i32, 4>());
+
+    auto* func = MakeEntryPoint("main", 11, 2, 3);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<i32, 4>, read_write> = var
+}
+
+%main = @compute @workgroup_size(11, 2, 3) func():void -> %b2 {
+  %b2 = block {
+    %3:array<i32, 4> = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<i32, 4>, read_write> = var
+}
+
+%main = @compute @workgroup_size(11, 2, 3) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    loop [i: %b3, b: %b4, c: %b5] {  # loop_1
+      %b3 = block {  # initializer
+        next_iteration %b4 %tint_local_index
+      }
+      %b4 = block (%4:u32) {  # body
+        %5:bool = gt %4:u32, 3u
+        if %5 [t: %b6] {  # if_1
+          %b6 = block {  # true
+            exit_loop  # loop_1
+          }
+        }
+        %6:ptr<workgroup, i32, read_write> = access %wgvar, %4:u32
+        store %6, 0i
+        continue %b5
+      }
+      %b5 = block {  # continuing
+        %7:u32 = add %4:u32, 66u
+        next_iteration %b4 %7
+      }
+    }
+    %8:void = workgroupBarrier
+    %9:array<i32, 4> = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, ArrayOfArrayOfU32) {
+    auto* var = MakeVar("wgvar", ty.array(ty.array<u32, 5>(), 7));
+
+    auto* func = MakeEntryPoint("main", 11, 2, 3);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<array<u32, 5>, 7>, read_write> = var
+}
+
+%main = @compute @workgroup_size(11, 2, 3) func():void -> %b2 {
+  %b2 = block {
+    %3:array<array<u32, 5>, 7> = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<array<u32, 5>, 7>, read_write> = var
+}
+
+%main = @compute @workgroup_size(11, 2, 3) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    loop [i: %b3, b: %b4, c: %b5] {  # loop_1
+      %b3 = block {  # initializer
+        next_iteration %b4 %tint_local_index
+      }
+      %b4 = block (%4:u32) {  # body
+        %5:bool = gt %4:u32, 34u
+        if %5 [t: %b6] {  # if_1
+          %b6 = block {  # true
+            exit_loop  # loop_1
+          }
+        }
+        %6:u32 = mod %4:u32, 5u
+        %7:u32 = div %4:u32, 5u
+        %8:ptr<workgroup, u32, read_write> = access %wgvar, %7, %6
+        store %8, 0u
+        continue %b5
+      }
+      %b5 = block {  # continuing
+        %9:u32 = add %4:u32, 66u
+        next_iteration %b4 %9
+      }
+    }
+    %10:void = workgroupBarrier
+    %11:array<array<u32, 5>, 7> = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, ArrayOfArrayOfArray) {
+    auto* var = MakeVar("wgvar", ty.array(ty.array(ty.array<i32, 7>(), 5), 3));
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<array<array<i32, 7>, 5>, 3>, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    %3:array<array<array<i32, 7>, 5>, 3> = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<array<array<i32, 7>, 5>, 3>, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    loop [i: %b3, b: %b4, c: %b5] {  # loop_1
+      %b3 = block {  # initializer
+        next_iteration %b4 %tint_local_index
+      }
+      %b4 = block (%4:u32) {  # body
+        %5:bool = gt %4:u32, 104u
+        if %5 [t: %b6] {  # if_1
+          %b6 = block {  # true
+            exit_loop  # loop_1
+          }
+        }
+        %6:u32 = mod %4:u32, 7u
+        %7:u32 = div %4:u32, 7u
+        %8:u32 = mod %7, 5u
+        %9:u32 = div %4:u32, 35u
+        %10:ptr<workgroup, i32, read_write> = access %wgvar, %9, %8, %6
+        store %10, 0i
+        continue %b5
+      }
+      %b5 = block {  # continuing
+        %11:u32 = add %4:u32, 1u
+        next_iteration %b4 %11
+      }
+    }
+    %12:void = workgroupBarrier
+    %13:array<array<array<i32, 7>, 5>, 3> = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, NestedArrayInnerSizeOne) {
+    auto* var = MakeVar("wgvar", ty.array(ty.array(ty.array<i32, 1>(), 5), 3));
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<array<array<i32, 1>, 5>, 3>, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    %3:array<array<array<i32, 1>, 5>, 3> = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<array<array<i32, 1>, 5>, 3>, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    loop [i: %b3, b: %b4, c: %b5] {  # loop_1
+      %b3 = block {  # initializer
+        next_iteration %b4 %tint_local_index
+      }
+      %b4 = block (%4:u32) {  # body
+        %5:bool = gt %4:u32, 14u
+        if %5 [t: %b6] {  # if_1
+          %b6 = block {  # true
+            exit_loop  # loop_1
+          }
+        }
+        %6:u32 = mod %4:u32, 5u
+        %7:u32 = div %4:u32, 5u
+        %8:ptr<workgroup, i32, read_write> = access %wgvar, %7, %6, 0u
+        store %8, 0i
+        continue %b5
+      }
+      %b5 = block {  # continuing
+        %9:u32 = add %4:u32, 1u
+        next_iteration %b4 %9
+      }
+    }
+    %10:void = workgroupBarrier
+    %11:array<array<array<i32, 1>, 5>, 3> = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, NestedArrayMiddleSizeOne) {
+    auto* var = MakeVar("wgvar", ty.array(ty.array(ty.array<i32, 3>(), 1), 5));
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<array<array<i32, 3>, 1>, 5>, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    %3:array<array<array<i32, 3>, 1>, 5> = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<array<array<i32, 3>, 1>, 5>, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    loop [i: %b3, b: %b4, c: %b5] {  # loop_1
+      %b3 = block {  # initializer
+        next_iteration %b4 %tint_local_index
+      }
+      %b4 = block (%4:u32) {  # body
+        %5:bool = gt %4:u32, 14u
+        if %5 [t: %b6] {  # if_1
+          %b6 = block {  # true
+            exit_loop  # loop_1
+          }
+        }
+        %6:u32 = mod %4:u32, 3u
+        %7:u32 = div %4:u32, 3u
+        %8:ptr<workgroup, i32, read_write> = access %wgvar, %7, 0u, %6
+        store %8, 0i
+        continue %b5
+      }
+      %b5 = block {  # continuing
+        %9:u32 = add %4:u32, 1u
+        next_iteration %b4 %9
+      }
+    }
+    %10:void = workgroupBarrier
+    %11:array<array<array<i32, 3>, 1>, 5> = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, NestedArrayOuterSizeOne) {
+    auto* var = MakeVar("wgvar", ty.array(ty.array(ty.array<i32, 3>(), 5), 1));
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<array<array<i32, 3>, 5>, 1>, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    %3:array<array<array<i32, 3>, 5>, 1> = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<array<array<i32, 3>, 5>, 1>, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    loop [i: %b3, b: %b4, c: %b5] {  # loop_1
+      %b3 = block {  # initializer
+        next_iteration %b4 %tint_local_index
+      }
+      %b4 = block (%4:u32) {  # body
+        %5:bool = gt %4:u32, 14u
+        if %5 [t: %b6] {  # if_1
+          %b6 = block {  # true
+            exit_loop  # loop_1
+          }
+        }
+        %6:u32 = mod %4:u32, 3u
+        %7:u32 = div %4:u32, 3u
+        %8:ptr<workgroup, i32, read_write> = access %wgvar, 0u, %7, %6
+        store %8, 0i
+        continue %b5
+      }
+      %b5 = block {  # continuing
+        %9:u32 = add %4:u32, 1u
+        next_iteration %b4 %9
+      }
+    }
+    %10:void = workgroupBarrier
+    %11:array<array<array<i32, 3>, 5>, 1> = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, NestedArrayTotalSizeOne) {
+    auto* var = MakeVar("wgvar", ty.array(ty.array<i32, 1>(), 1));
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<array<i32, 1>, 1>, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    %3:array<array<i32, 1>, 1> = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<array<i32, 1>, 1>, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %4:bool = eq %tint_local_index, 0u
+    if %4 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        %5:ptr<workgroup, i32, read_write> = access %wgvar, 0u, 0u
+        store %5, 0i
+        exit_if  # if_1
+      }
+    }
+    %6:void = workgroupBarrier
+    %7:array<array<i32, 1>, 1> = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, StructOfScalars) {
+    auto* s = ty.Struct(mod.symbols.New("MyStruct"), {
+                                                         {mod.symbols.New("a"), ty.i32()},
+                                                         {mod.symbols.New("b"), ty.u32()},
+                                                         {mod.symbols.New("c"), ty.f32()},
+                                                     });
+    auto* var = MakeVar("wgvar", s);
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+MyStruct = struct @align(4) {
+  a:i32 @offset(0)
+  b:u32 @offset(4)
+  c:f32 @offset(8)
+}
+
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, MyStruct, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    %3:MyStruct = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+MyStruct = struct @align(4) {
+  a:i32 @offset(0)
+  b:u32 @offset(4)
+  c:f32 @offset(8)
+}
+
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, MyStruct, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %4:bool = eq %tint_local_index, 0u
+    if %4 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        store %wgvar, MyStruct(0i, 0u, 0.0f)
+        exit_if  # if_1
+      }
+    }
+    %5:void = workgroupBarrier
+    %6:MyStruct = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, NestedStructOfScalars) {
+    auto* inner = ty.Struct(mod.symbols.New("Inner"), {
+                                                          {mod.symbols.New("a"), ty.i32()},
+                                                          {mod.symbols.New("b"), ty.u32()},
+                                                      });
+    auto* outer = ty.Struct(mod.symbols.New("Outer"), {
+                                                          {mod.symbols.New("c"), ty.f32()},
+                                                          {mod.symbols.New("inner"), inner},
+                                                          {mod.symbols.New("d"), ty.bool_()},
+                                                      });
+    auto* var = MakeVar("wgvar", outer);
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+Inner = struct @align(4) {
+  a:i32 @offset(0)
+  b:u32 @offset(4)
+}
+
+Outer = struct @align(4) {
+  c:f32 @offset(0)
+  inner:Inner @offset(4)
+  d:bool @offset(12)
+}
+
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, Outer, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    %3:Outer = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+Inner = struct @align(4) {
+  a:i32 @offset(0)
+  b:u32 @offset(4)
+}
+
+Outer = struct @align(4) {
+  c:f32 @offset(0)
+  inner:Inner @offset(4)
+  d:bool @offset(12)
+}
+
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, Outer, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %4:bool = eq %tint_local_index, 0u
+    if %4 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        store %wgvar, Outer(0.0f, Inner(0i, 0u), false)
+        exit_if  # if_1
+      }
+    }
+    %5:void = workgroupBarrier
+    %6:Outer = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, NestedStructOfScalarsWithAtomic) {
+    auto* inner = ty.Struct(mod.symbols.New("Inner"), {
+                                                          {mod.symbols.New("a"), ty.i32()},
+                                                          {mod.symbols.New("b"), ty.atomic<u32>()},
+                                                      });
+    auto* outer = ty.Struct(mod.symbols.New("Outer"), {
+                                                          {mod.symbols.New("c"), ty.f32()},
+                                                          {mod.symbols.New("inner"), inner},
+                                                          {mod.symbols.New("d"), ty.bool_()},
+                                                      });
+    auto* var = MakeVar("wgvar", outer);
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+Inner = struct @align(4) {
+  a:i32 @offset(0)
+  b:atomic<u32> @offset(4)
+}
+
+Outer = struct @align(4) {
+  c:f32 @offset(0)
+  inner:Inner @offset(4)
+  d:bool @offset(12)
+}
+
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, Outer, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    %3:Outer = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+Inner = struct @align(4) {
+  a:i32 @offset(0)
+  b:atomic<u32> @offset(4)
+}
+
+Outer = struct @align(4) {
+  c:f32 @offset(0)
+  inner:Inner @offset(4)
+  d:bool @offset(12)
+}
+
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, Outer, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %4:bool = eq %tint_local_index, 0u
+    if %4 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        %5:ptr<workgroup, f32, read_write> = access %wgvar, 0u
+        store %5, 0.0f
+        %6:ptr<workgroup, i32, read_write> = access %wgvar, 1u, 0u
+        store %6, 0i
+        %7:ptr<workgroup, atomic<u32>, read_write> = access %wgvar, 1u, 1u
+        %8:void = atomicStore %7, 0u
+        %9:ptr<workgroup, bool, read_write> = access %wgvar, 2u
+        store %9, false
+        exit_if  # if_1
+      }
+    }
+    %10:void = workgroupBarrier
+    %11:Outer = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, ArrayOfStructOfArrayOfStructWithAtomic) {
+    auto* inner = ty.Struct(mod.symbols.New("Inner"), {
+                                                          {mod.symbols.New("a"), ty.i32()},
+                                                          {mod.symbols.New("b"), ty.atomic<u32>()},
+                                                      });
+    auto* outer =
+        ty.Struct(mod.symbols.New("Outer"), {
+                                                {mod.symbols.New("c"), ty.f32()},
+                                                {mod.symbols.New("inner"), ty.array(inner, 13)},
+                                                {mod.symbols.New("d"), ty.bool_()},
+                                            });
+    auto* var = MakeVar("wgvar", ty.array(outer, 7));
+
+    auto* func = MakeEntryPoint("main", 7, 3, 2);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+Inner = struct @align(4) {
+  a:i32 @offset(0)
+  b:atomic<u32> @offset(4)
+}
+
+Outer = struct @align(4) {
+  c:f32 @offset(0)
+  inner:array<Inner, 13> @offset(4)
+  d:bool @offset(108)
+}
+
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<Outer, 7>, read_write> = var
+}
+
+%main = @compute @workgroup_size(7, 3, 2) func():void -> %b2 {
+  %b2 = block {
+    %3:array<Outer, 7> = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+Inner = struct @align(4) {
+  a:i32 @offset(0)
+  b:atomic<u32> @offset(4)
+}
+
+Outer = struct @align(4) {
+  c:f32 @offset(0)
+  inner:array<Inner, 13> @offset(4)
+  d:bool @offset(108)
+}
+
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, array<Outer, 7>, read_write> = var
+}
+
+%main = @compute @workgroup_size(7, 3, 2) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    loop [i: %b3, b: %b4, c: %b5] {  # loop_1
+      %b3 = block {  # initializer
+        next_iteration %b4 %tint_local_index
+      }
+      %b4 = block (%4:u32) {  # body
+        %5:bool = gt %4:u32, 6u
+        if %5 [t: %b6] {  # if_1
+          %b6 = block {  # true
+            exit_loop  # loop_1
+          }
+        }
+        %6:ptr<workgroup, f32, read_write> = access %wgvar, %4:u32, 0u
+        store %6, 0.0f
+        %7:ptr<workgroup, bool, read_write> = access %wgvar, %4:u32, 2u
+        store %7, false
+        continue %b5
+      }
+      %b5 = block {  # continuing
+        %8:u32 = add %4:u32, 42u
+        next_iteration %b4 %8
+      }
+    }
+    loop [i: %b7, b: %b8, c: %b9] {  # loop_2
+      %b7 = block {  # initializer
+        next_iteration %b8 %tint_local_index
+      }
+      %b8 = block (%9:u32) {  # body
+        %10:bool = gt %9:u32, 90u
+        if %10 [t: %b10] {  # if_2
+          %b10 = block {  # true
+            exit_loop  # loop_2
+          }
+        }
+        %11:u32 = mod %9:u32, 13u
+        %12:u32 = div %9:u32, 13u
+        %13:ptr<workgroup, i32, read_write> = access %wgvar, %12, 1u, %11, 0u
+        store %13, 0i
+        %14:u32 = mod %9:u32, 13u
+        %15:u32 = div %9:u32, 13u
+        %16:ptr<workgroup, atomic<u32>, read_write> = access %wgvar, %15, 1u, %14, 1u
+        %17:void = atomicStore %16, 0u
+        continue %b9
+      }
+      %b9 = block {  # continuing
+        %18:u32 = add %9:u32, 42u
+        next_iteration %b8 %18
+      }
+    }
+    %19:void = workgroupBarrier
+    %20:array<Outer, 7> = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, MultipleVariables_DifferentIterationCounts) {
+    auto* var_a = MakeVar("var_a", ty.bool_());
+    auto* var_b = MakeVar("var_b", ty.array<i32, 4>());
+    auto* var_c = MakeVar("var_c", ty.array(ty.array<u32, 5>(), 7));
+
+    auto* func = MakeEntryPoint("main", 11, 2, 3);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var_a);
+        b.Load(var_b);
+        b.Load(var_c);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %var_a:ptr<workgroup, bool, read_write> = var
+  %var_b:ptr<workgroup, array<i32, 4>, read_write> = var
+  %var_c:ptr<workgroup, array<array<u32, 5>, 7>, read_write> = var
+}
+
+%main = @compute @workgroup_size(11, 2, 3) func():void -> %b2 {
+  %b2 = block {
+    %5:bool = load %var_a
+    %6:array<i32, 4> = load %var_b
+    %7:array<array<u32, 5>, 7> = load %var_c
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %var_a:ptr<workgroup, bool, read_write> = var
+  %var_b:ptr<workgroup, array<i32, 4>, read_write> = var
+  %var_c:ptr<workgroup, array<array<u32, 5>, 7>, read_write> = var
+}
+
+%main = @compute @workgroup_size(11, 2, 3) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %6:bool = eq %tint_local_index, 0u
+    if %6 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        store %var_a, false
+        exit_if  # if_1
+      }
+    }
+    loop [i: %b4, b: %b5, c: %b6] {  # loop_1
+      %b4 = block {  # initializer
+        next_iteration %b5 %tint_local_index
+      }
+      %b5 = block (%7:u32) {  # body
+        %8:bool = gt %7:u32, 3u
+        if %8 [t: %b7] {  # if_2
+          %b7 = block {  # true
+            exit_loop  # loop_1
+          }
+        }
+        %9:ptr<workgroup, i32, read_write> = access %var_b, %7:u32
+        store %9, 0i
+        continue %b6
+      }
+      %b6 = block {  # continuing
+        %10:u32 = add %7:u32, 66u
+        next_iteration %b5 %10
+      }
+    }
+    loop [i: %b8, b: %b9, c: %b10] {  # loop_2
+      %b8 = block {  # initializer
+        next_iteration %b9 %tint_local_index
+      }
+      %b9 = block (%11:u32) {  # body
+        %12:bool = gt %11:u32, 34u
+        if %12 [t: %b11] {  # if_3
+          %b11 = block {  # true
+            exit_loop  # loop_2
+          }
+        }
+        %13:u32 = mod %11:u32, 5u
+        %14:u32 = div %11:u32, 5u
+        %15:ptr<workgroup, u32, read_write> = access %var_c, %14, %13
+        store %15, 0u
+        continue %b10
+      }
+      %b10 = block {  # continuing
+        %16:u32 = add %11:u32, 66u
+        next_iteration %b9 %16
+      }
+    }
+    %17:void = workgroupBarrier
+    %18:bool = load %var_a
+    %19:array<i32, 4> = load %var_b
+    %20:array<array<u32, 5>, 7> = load %var_c
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, MultipleVariables_SharedIterationCounts) {
+    auto* var_a = MakeVar("var_a", ty.bool_());
+    auto* var_b = MakeVar("var_b", ty.i32());
+    auto* var_c = MakeVar("var_c", ty.array<i32, 42>());
+    auto* var_d = MakeVar("var_d", ty.array(ty.array<u32, 6>(), 7));
+
+    auto* func = MakeEntryPoint("main", 11, 2, 3);
+    b.Append(func->Block(), [&] {  //
+        b.Load(var_a);
+        b.Load(var_b);
+        b.Load(var_c);
+        b.Load(var_d);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %var_a:ptr<workgroup, bool, read_write> = var
+  %var_b:ptr<workgroup, i32, read_write> = var
+  %var_c:ptr<workgroup, array<i32, 42>, read_write> = var
+  %var_d:ptr<workgroup, array<array<u32, 6>, 7>, read_write> = var
+}
+
+%main = @compute @workgroup_size(11, 2, 3) func():void -> %b2 {
+  %b2 = block {
+    %6:bool = load %var_a
+    %7:i32 = load %var_b
+    %8:array<i32, 42> = load %var_c
+    %9:array<array<u32, 6>, 7> = load %var_d
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %var_a:ptr<workgroup, bool, read_write> = var
+  %var_b:ptr<workgroup, i32, read_write> = var
+  %var_c:ptr<workgroup, array<i32, 42>, read_write> = var
+  %var_d:ptr<workgroup, array<array<u32, 6>, 7>, read_write> = var
+}
+
+%main = @compute @workgroup_size(11, 2, 3) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %7:bool = eq %tint_local_index, 0u
+    if %7 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        store %var_a, false
+        store %var_b, 0i
+        exit_if  # if_1
+      }
+    }
+    loop [i: %b4, b: %b5, c: %b6] {  # loop_1
+      %b4 = block {  # initializer
+        next_iteration %b5 %tint_local_index
+      }
+      %b5 = block (%8:u32) {  # body
+        %9:bool = gt %8:u32, 41u
+        if %9 [t: %b7] {  # if_2
+          %b7 = block {  # true
+            exit_loop  # loop_1
+          }
+        }
+        %10:ptr<workgroup, i32, read_write> = access %var_c, %8:u32
+        store %10, 0i
+        %11:u32 = mod %8:u32, 6u
+        %12:u32 = div %8:u32, 6u
+        %13:ptr<workgroup, u32, read_write> = access %var_d, %12, %11
+        store %13, 0u
+        continue %b6
+      }
+      %b6 = block {  # continuing
+        %14:u32 = add %8:u32, 66u
+        next_iteration %b5 %14
+      }
+    }
+    %15:void = workgroupBarrier
+    %16:bool = load %var_a
+    %17:i32 = load %var_b
+    %18:array<i32, 42> = load %var_c
+    %19:array<array<u32, 6>, 7> = load %var_d
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, ExistingLocalInvocationIndex) {
+    auto* var = MakeVar("wgvar", ty.bool_());
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    auto* global_id = b.FunctionParam("global_id", ty.vec4<u32>());
+    global_id->SetBuiltin(FunctionParam::Builtin::kGlobalInvocationId);
+    auto* index = b.FunctionParam("index", ty.u32());
+    index->SetBuiltin(FunctionParam::Builtin::kLocalInvocationIndex);
+    func->SetParams({global_id, index});
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, bool, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%global_id:vec4<u32> [@global_invocation_id], %index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %5:bool = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, bool, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%global_id:vec4<u32> [@global_invocation_id], %index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %5:bool = eq %index, 0u
+    if %5 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        store %wgvar, false
+        exit_if  # if_1
+      }
+    }
+    %6:void = workgroupBarrier
+    %7:bool = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, ExistingLocalInvocationIndexInStruct) {
+    auto* var = MakeVar("wgvar", ty.bool_());
+
+    auto* structure =
+        ty.Struct(mod.symbols.New("MyStruct"),
+                  {
+                      {
+                          mod.symbols.New("global_id"),
+                          ty.vec3<u32>(),
+                          {{}, {}, core::BuiltinValue::kGlobalInvocationId, {}, false},
+                      },
+                      {
+                          mod.symbols.New("index"),
+                          ty.u32(),
+                          {{}, {}, core::BuiltinValue::kLocalInvocationIndex, {}, false},
+                      },
+                  });
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    func->SetParams({b.FunctionParam("params", structure)});
+    b.Append(func->Block(), [&] {  //
+        b.Load(var);
+        b.Return(func);
+    });
+
+    auto* src = R"(
+MyStruct = struct @align(16) {
+  global_id:vec3<u32> @offset(0), @builtin(global_invocation_id)
+  index:u32 @offset(12), @builtin(local_invocation_index)
+}
+
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, bool, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%params:MyStruct):void -> %b2 {
+  %b2 = block {
+    %4:bool = load %wgvar
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+MyStruct = struct @align(16) {
+  global_id:vec3<u32> @offset(0), @builtin(global_invocation_id)
+  index:u32 @offset(12), @builtin(local_invocation_index)
+}
+
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, bool, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%params:MyStruct):void -> %b2 {
+  %b2 = block {
+    %4:u32 = access %params, 1u
+    %5:bool = eq %4, 0u
+    if %5 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        store %wgvar, false
+        exit_if  # if_1
+      }
+    }
+    %6:void = workgroupBarrier
+    %7:bool = load %wgvar
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, UseInsideNestedBlock) {
+    auto* var = MakeVar("wgvar", ty.bool_());
+
+    auto* func = MakeEntryPoint("main", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        auto* ifelse = b.If(true);
+        b.Append(ifelse->True(), [&] {  //
+            auto* sw = b.Switch(42_i);
+            auto* def_case = b.Case(sw, Vector{core::ir::Switch::CaseSelector()});
+            b.Append(def_case, [&] {  //
+                auto* loop = b.Loop();
+                b.Append(loop->Body(), [&] {  //
+                    b.Continue(loop);
+                    b.Append(loop->Continuing(), [&] {  //
+                        auto* load = b.Load(var);
+                        b.BreakIf(loop, load);
+                    });
+                });
+                b.ExitSwitch(sw);
+            });
+            b.ExitIf(ifelse);
+        });
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, bool, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func():void -> %b2 {
+  %b2 = block {
+    if true [t: %b3] {  # if_1
+      %b3 = block {  # true
+        switch 42i [c: (default, %b4)] {  # switch_1
+          %b4 = block {  # case
+            loop [b: %b5, c: %b6] {  # loop_1
+              %b5 = block {  # body
+                continue %b6
+              }
+              %b6 = block {  # continuing
+                %3:bool = load %wgvar
+                break_if %3 %b5
+              }
+            }
+            exit_switch  # switch_1
+          }
+        }
+        exit_if  # if_1
+      }
+    }
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, bool, read_write> = var
+}
+
+%main = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b2 {
+  %b2 = block {
+    %4:bool = eq %tint_local_index, 0u
+    if %4 [t: %b3] {  # if_1
+      %b3 = block {  # true
+        store %wgvar, false
+        exit_if  # if_1
+      }
+    }
+    %5:void = workgroupBarrier
+    if true [t: %b4] {  # if_2
+      %b4 = block {  # true
+        switch 42i [c: (default, %b5)] {  # switch_1
+          %b5 = block {  # case
+            loop [b: %b6, c: %b7] {  # loop_1
+              %b6 = block {  # body
+                continue %b7
+              }
+              %b7 = block {  # continuing
+                %6:bool = load %wgvar
+                break_if %6 %b6
+              }
+            }
+            exit_switch  # switch_1
+          }
+        }
+        exit_if  # if_2
+      }
+    }
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, UseInsideIndirectFunctionCall) {
+    auto* var = MakeVar("wgvar", ty.bool_());
+
+    auto* foo = b.Function("foo", ty.void_());
+    b.Append(foo->Block(), [&] {  //
+        auto* loop = b.Loop();
+        b.Append(loop->Body(), [&] {  //
+            b.Continue(loop);
+            b.Append(loop->Continuing(), [&] {  //
+                auto* load = b.Load(var);
+                b.BreakIf(loop, load);
+            });
+        });
+        b.Return(foo);
+    });
+
+    auto* bar = b.Function("foo", ty.void_());
+    b.Append(bar->Block(), [&] {  //
+        auto* ifelse = b.If(true);
+        b.Append(ifelse->True(), [&] {  //
+            b.Call(ty.void_(), foo);
+            b.ExitIf(ifelse);
+        });
+        b.Return(bar);
+    });
+
+    auto* func = MakeEntryPoint("func", 1, 1, 1);
+    b.Append(func->Block(), [&] {  //
+        auto* ifelse = b.If(true);
+        b.Append(ifelse->True(), [&] {  //
+            auto* sw = b.Switch(42_i);
+            auto* def_case = b.Case(sw, Vector{core::ir::Switch::CaseSelector()});
+            b.Append(def_case, [&] {  //
+                auto* loop = b.Loop();
+                b.Append(loop->Body(), [&] {  //
+                    b.Continue(loop);
+                    b.Append(loop->Continuing(), [&] {  //
+                        b.Call(ty.void_(), bar);
+                        b.BreakIf(loop, true);
+                    });
+                });
+                b.ExitSwitch(sw);
+            });
+            b.ExitIf(ifelse);
+        });
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, bool, read_write> = var
+}
+
+%foo = func():void -> %b2 {
+  %b2 = block {
+    loop [b: %b3, c: %b4] {  # loop_1
+      %b3 = block {  # body
+        continue %b4
+      }
+      %b4 = block {  # continuing
+        %3:bool = load %wgvar
+        break_if %3 %b3
+      }
+    }
+    ret
+  }
+}
+%foo_1 = func():void -> %b5 {  # %foo_1: 'foo'
+  %b5 = block {
+    if true [t: %b6] {  # if_1
+      %b6 = block {  # true
+        %5:void = call %foo
+        exit_if  # if_1
+      }
+    }
+    ret
+  }
+}
+%func = @compute @workgroup_size(1, 1, 1) func():void -> %b7 {
+  %b7 = block {
+    if true [t: %b8] {  # if_2
+      %b8 = block {  # true
+        switch 42i [c: (default, %b9)] {  # switch_1
+          %b9 = block {  # case
+            loop [b: %b10, c: %b11] {  # loop_2
+              %b10 = block {  # body
+                continue %b11
+              }
+              %b11 = block {  # continuing
+                %7:void = call %foo_1
+                break_if true %b10
+              }
+            }
+            exit_switch  # switch_1
+          }
+        }
+        exit_if  # if_2
+      }
+    }
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, bool, read_write> = var
+}
+
+%foo = func():void -> %b2 {
+  %b2 = block {
+    loop [b: %b3, c: %b4] {  # loop_1
+      %b3 = block {  # body
+        continue %b4
+      }
+      %b4 = block {  # continuing
+        %3:bool = load %wgvar
+        break_if %3 %b3
+      }
+    }
+    ret
+  }
+}
+%foo_1 = func():void -> %b5 {  # %foo_1: 'foo'
+  %b5 = block {
+    if true [t: %b6] {  # if_1
+      %b6 = block {  # true
+        %5:void = call %foo
+        exit_if  # if_1
+      }
+    }
+    ret
+  }
+}
+%func = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b7 {
+  %b7 = block {
+    %8:bool = eq %tint_local_index, 0u
+    if %8 [t: %b8] {  # if_2
+      %b8 = block {  # true
+        store %wgvar, false
+        exit_if  # if_2
+      }
+    }
+    %9:void = workgroupBarrier
+    if true [t: %b9] {  # if_3
+      %b9 = block {  # true
+        switch 42i [c: (default, %b10)] {  # switch_1
+          %b10 = block {  # case
+            loop [b: %b11, c: %b12] {  # loop_2
+              %b11 = block {  # body
+                continue %b12
+              }
+              %b12 = block {  # continuing
+                %10:void = call %foo_1
+                break_if true %b11
+              }
+            }
+            exit_switch  # switch_1
+          }
+        }
+        exit_if  # if_3
+      }
+    }
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(IR_ZeroInitWorkgroupMemoryTest, MultipleEntryPoints_SameVarViaHelper) {
+    auto* var = MakeVar("wgvar", ty.bool_());
+
+    auto* foo = b.Function("foo", ty.void_());
+    b.Append(foo->Block(), [&] {  //
+        auto* loop = b.Loop();
+        b.Append(loop->Body(), [&] {  //
+            b.Continue(loop);
+            b.Append(loop->Continuing(), [&] {  //
+                auto* load = b.Load(var);
+                b.BreakIf(loop, load);
+            });
+        });
+        b.Return(foo);
+    });
+
+    auto* ep1 = MakeEntryPoint("ep1", 1, 1, 1);
+    b.Append(ep1->Block(), [&] {  //
+        b.Call(ty.void_(), foo);
+        b.Return(ep1);
+    });
+
+    auto* ep2 = MakeEntryPoint("ep2", 1, 1, 1);
+    b.Append(ep2->Block(), [&] {  //
+        b.Call(ty.void_(), foo);
+        b.Return(ep2);
+    });
+
+    auto* src = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, bool, read_write> = var
+}
+
+%foo = func():void -> %b2 {
+  %b2 = block {
+    loop [b: %b3, c: %b4] {  # loop_1
+      %b3 = block {  # body
+        continue %b4
+      }
+      %b4 = block {  # continuing
+        %3:bool = load %wgvar
+        break_if %3 %b3
+      }
+    }
+    ret
+  }
+}
+%ep1 = @compute @workgroup_size(1, 1, 1) func():void -> %b5 {
+  %b5 = block {
+    %5:void = call %foo
+    ret
+  }
+}
+%ep2 = @compute @workgroup_size(1, 1, 1) func():void -> %b6 {
+  %b6 = block {
+    %7:void = call %foo
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%b1 = block {  # root
+  %wgvar:ptr<workgroup, bool, read_write> = var
+}
+
+%foo = func():void -> %b2 {
+  %b2 = block {
+    loop [b: %b3, c: %b4] {  # loop_1
+      %b3 = block {  # body
+        continue %b4
+      }
+      %b4 = block {  # continuing
+        %3:bool = load %wgvar
+        break_if %3 %b3
+      }
+    }
+    ret
+  }
+}
+%ep1 = @compute @workgroup_size(1, 1, 1) func(%tint_local_index:u32 [@local_invocation_index]):void -> %b5 {
+  %b5 = block {
+    %6:bool = eq %tint_local_index, 0u
+    if %6 [t: %b6] {  # if_1
+      %b6 = block {  # true
+        store %wgvar, false
+        exit_if  # if_1
+      }
+    }
+    %7:void = workgroupBarrier
+    %8:void = call %foo
+    ret
+  }
+}
+%ep2 = @compute @workgroup_size(1, 1, 1) func(%tint_local_index_1:u32 [@local_invocation_index]):void -> %b7 {  # %tint_local_index_1: 'tint_local_index'
+  %b7 = block {
+    %11:bool = eq %tint_local_index_1, 0u
+    if %11 [t: %b8] {  # if_2
+      %b8 = block {  # true
+        store %wgvar, false
+        exit_if  # if_2
+      }
+    }
+    %12:void = workgroupBarrier
+    %13:void = call %foo
+    ret
+  }
+}
+)";
+
+    Run(ZeroInitWorkgroupMemory);
+
+    EXPECT_EQ(expect, str());
+}
+
+}  // namespace
+}  // namespace tint::core::ir::transform
diff --git a/src/tint/lang/core/ir/user_call.cc b/src/tint/lang/core/ir/user_call.cc
index 0f20129..5c6f4e3 100644
--- a/src/tint/lang/core/ir/user_call.cc
+++ b/src/tint/lang/core/ir/user_call.cc
@@ -24,6 +24,7 @@
 namespace tint::core::ir {
 
 UserCall::UserCall(InstructionResult* result, Function* func, VectorRef<Value*> arguments) {
+    flags_.Add(Flag::kSequenced);
     AddOperand(UserCall::kFunctionOperandOffset, func);
     AddOperands(UserCall::kArgsOperandOffset, std::move(arguments));
     AddResult(result);
diff --git a/src/tint/lang/core/ir/user_call_test.cc b/src/tint/lang/core/ir/user_call_test.cc
index efbe64c..acb69ce 100644
--- a/src/tint/lang/core/ir/user_call_test.cc
+++ b/src/tint/lang/core/ir/user_call_test.cc
@@ -51,7 +51,7 @@
         {
             Module mod;
             Builder b{mod};
-            b.Call(nullptr, b.Function("myfunc", mod.Types().void_()));
+            b.Call(static_cast<type::Type*>(nullptr), b.Function("myfunc", mod.Types().void_()));
         },
         "");
 }
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index 055940c..013fcb0 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -83,9 +83,8 @@
     ~Validator();
 
     /// Runs the validator over the module provided during construction
-    /// @returns the results of validation, either a success result object or the diagnostics of
-    /// validation failures.
-    Result<SuccessType, diag::List> IsValid();
+    /// @returns success or failure
+    Result<SuccessType> Run();
 
   protected:
     /// @param inst the instruction
@@ -191,6 +190,10 @@
     /// @param call the call to validate
     void CheckBuiltinCall(BuiltinCall* call);
 
+    /// Validates the given user call
+    /// @param call the call to validate
+    void CheckUserCall(UserCall* call);
+
     /// Validates the given access
     /// @param a the access to validate
     void CheckAccess(ir::Access* a);
@@ -267,7 +270,7 @@
     diag::List diagnostics_;
     Disassembler dis_{mod_};
     Block* current_block_ = nullptr;
-    Hashset<Function*, 4> seen_functions_;
+    Hashset<Function*, 4> all_functions_;
     Vector<ControlInstruction*, 8> control_stack_;
 
     void DisassembleIfNeeded();
@@ -284,10 +287,16 @@
     mod_.disassembly_file = std::make_unique<Source::File>("", dis_.Disassemble());
 }
 
-Result<SuccessType, diag::List> Validator::IsValid() {
+Result<SuccessType> Validator::Run() {
     CheckRootBlock(mod_.root_block);
 
     for (auto* func : mod_.functions) {
+        if (!all_functions_.Add(func)) {
+            AddError("function '" + Name(func) + "' added to module multiple times");
+        }
+    }
+
+    for (auto* func : mod_.functions) {
         CheckFunction(func);
     }
 
@@ -295,7 +304,7 @@
         DisassembleIfNeeded();
         diagnostics_.add_note(tint::diag::System::IR,
                               "# Disassembly\n" + mod_.disassembly_file->content.data, {});
-        return std::move(diagnostics_);
+        return Failure{std::move(diagnostics_)};
     }
     return Success;
 }
@@ -393,13 +402,15 @@
 }
 
 void Validator::CheckRootBlock(Block* blk) {
-    if (!blk) {
-        return;
-    }
-
     TINT_SCOPED_ASSIGNMENT(current_block_, blk);
 
     for (auto* inst : *blk) {
+        if (inst->Block() != blk) {
+            AddError(
+                inst,
+                InstError(inst, "instruction in root block does not have root block as parent"));
+            continue;
+        }
         auto* var = inst->As<ir::Var>();
         if (!var) {
             AddError(inst,
@@ -411,10 +422,6 @@
 }
 
 void Validator::CheckFunction(Function* func) {
-    if (!seen_functions_.Add(func)) {
-        AddError("function '" + Name(func) + "' added to module multiple times");
-    }
-
     CheckBlock(func->Block());
 }
 
@@ -426,6 +433,11 @@
     }
 
     for (auto* inst : *blk) {
+        if (inst->Block() != blk) {
+            AddError(inst, InstError(inst, "block instruction does not have same block as parent"));
+            AddNote(current_block_, "In block");
+            continue;
+        }
         if (inst->Is<ir::Terminator>() && inst != blk->Terminator()) {
             AddError(inst, "block: terminator which isn't the final instruction");
             continue;
@@ -468,11 +480,14 @@
         // Note, a `nullptr` is a valid operand in some cases, like `var` so we can't just check
         // for `nullptr` here.
         if (!op->Alive()) {
-            AddError(inst, i, InstError(inst, "instruction has operand which is not alive"));
+            AddError(inst, i,
+                     InstError(inst, "instruction operand " + std::to_string(i) + " is not alive"));
         }
 
         if (!op->Usages().Contains({inst, i})) {
-            AddError(inst, i, InstError(inst, "instruction operand missing usage"));
+            AddError(
+                inst, i,
+                InstError(inst, "instruction operand " + std::to_string(i) + " missing usage"));
         }
     }
 
@@ -522,7 +537,7 @@
         [&](Construct*) {},                            //
         [&](Convert*) {},                              //
         [&](Discard*) {},                              //
-        [&](UserCall*) {},                             //
+        [&](UserCall* c) { CheckUserCall(c); },        //
         [&](Default) {
             // Validation of custom IR instructions
         });
@@ -532,8 +547,8 @@
     auto args = Transform<8>(call->Args(), [&](ir::Value* v) { return v->Type(); });
     intrinsic::Context context{call->TableData(), mod_.Types(), mod_.symbols, diagnostics_};
 
-    auto result = core::intrinsic::Lookup(context, call->IntrinsicName(), call->FuncId(), args,
-                                          core::EvaluationStage::kRuntime, Source{});
+    auto result = core::intrinsic::Lookup(context, call->FriendlyName().c_str(), call->FuncId(),
+                                          args, core::EvaluationStage::kRuntime, Source{});
     if (result) {
         if (result->return_type != call->Result()->Type()) {
             AddError(call, InstError(call, "call result type does not match builtin return type"));
@@ -541,6 +556,13 @@
     }
 }
 
+void Validator::CheckUserCall(UserCall* call) {
+    if (!all_functions_.Contains(call->Target())) {
+        AddError(call, UserCall::kFunctionOperandOffset,
+                 InstError(call, "call target is not part of the module"));
+    }
+}
+
 void Validator::CheckAccess(ir::Access* a) {
     bool is_ptr = a->Object()->Type()->Is<core::type::Pointer>();
     auto* ty = a->Object()->Type()->UnwrapPtr();
@@ -863,13 +885,13 @@
 
 }  // namespace
 
-Result<SuccessType, diag::List> Validate(Module& mod) {
+Result<SuccessType> Validate(Module& mod) {
     Validator v(mod);
-    return v.IsValid();
+    return v.Run();
 }
 
-Result<SuccessType, std::string> ValidateAndDumpIfNeeded([[maybe_unused]] Module& ir,
-                                                         [[maybe_unused]] const char* msg) {
+Result<SuccessType> ValidateAndDumpIfNeeded([[maybe_unused]] Module& ir,
+                                            [[maybe_unused]] const char* msg) {
 #if TINT_DUMP_IR_WHEN_VALIDATING
     Disassembler disasm(ir);
     std::cout << "=========================================================" << std::endl;
@@ -881,10 +903,7 @@
 #ifndef NDEBUG
     auto result = Validate(ir);
     if (!result) {
-        diag::List errors;
-        StringStream ss;
-        ss << "validating input to " << msg << " failed" << std::endl << result.Failure().str();
-        return ss.str();
+        return result.Failure();
     }
 #endif
 
diff --git a/src/tint/lang/core/ir/validator.h b/src/tint/lang/core/ir/validator.h
index 497defa..4760f5d 100644
--- a/src/tint/lang/core/ir/validator.h
+++ b/src/tint/lang/core/ir/validator.h
@@ -17,7 +17,6 @@
 
 #include <string>
 
-#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward declarations
@@ -29,14 +28,14 @@
 
 /// Validates that a given IR module is correctly formed
 /// @param mod the module to validate
-/// @returns true on success, an error result otherwise
-Result<SuccessType, diag::List> Validate(Module& mod);
+/// @returns success or failure
+Result<SuccessType> Validate(Module& mod);
 
 /// Validates the module @p ir and dumps its contents if required by the build configuration.
 /// @param ir the module to transform
 /// @param msg the msg to accompany the output
-/// @returns an error string if the module is not valid
-Result<SuccessType, std::string> ValidateAndDumpIfNeeded(Module& ir, const char* msg);
+/// @returns success or failure
+Result<SuccessType> ValidateAndDumpIfNeeded(Module& ir, const char* msg);
 
 }  // namespace tint::core::ir
 
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index 777cd01..56ec9da 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -34,22 +34,20 @@
 using IR_ValidatorTest = IRTestHelper;
 
 TEST_F(IR_ValidatorTest, RootBlock_Var) {
-    mod.root_block = b.RootBlock();
     mod.root_block->Append(b.Var(ty.ptr<private_, i32>()));
     auto res = ir::Validate(mod);
-    EXPECT_TRUE(res) << res.Failure().str();
+    EXPECT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, RootBlock_NonVar) {
     auto* l = b.Loop();
     l->Body()->Append(b.Continue(l));
 
-    mod.root_block = b.RootBlock();
     mod.root_block->Append(l);
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:2:3 error: root block: invalid instruction: tint::core::ir::Loop
   loop [b: %b2] {  # loop_1
   ^^^^^^^^^^^^^
@@ -70,6 +68,38 @@
 )");
 }
 
+TEST_F(IR_ValidatorTest, RootBlock_VarBlockMismatch) {
+    auto* var = b.Var(ty.ptr<private_, i32>());
+    mod.root_block->Append(var);
+
+    auto* f = b.Function("f", ty.void_());
+    f->Block()->Append(b.Return(f));
+    var->SetBlock(f->Block());
+
+    auto res = ir::Validate(mod);
+    ASSERT_FALSE(res);
+    EXPECT_EQ(res.Failure().reason.str(),
+              R"(:2:38 error: var: instruction in root block does not have root block as parent
+  %1:ptr<private, i32, read_write> = var
+                                     ^^^
+
+:1:1 note: In block
+%b1 = block {  # root
+^^^^^^^^^^^
+
+note: # Disassembly
+%b1 = block {  # root
+  %1:ptr<private, i32, read_write> = var
+}
+
+%f = func():void -> %b2 {
+  %b2 = block {
+    ret
+  }
+}
+)");
+}
+
 TEST_F(IR_ValidatorTest, Function) {
     auto* f = b.Function("my_func", ty.void_());
 
@@ -77,7 +107,7 @@
     f->Block()->Append(b.Return(f));
 
     auto res = ir::Validate(mod);
-    EXPECT_TRUE(res) << res.Failure().str();
+    EXPECT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, Function_Duplicate) {
@@ -90,7 +120,8 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(error: function 'my_func' added to module multiple times
+    EXPECT_EQ(res.Failure().reason.str(),
+              R"(error: function 'my_func' added to module multiple times
 note: # Disassembly
 %my_func = func(%2:i32, %3:f32):void -> %b1 {
   %b1 = block {
@@ -105,12 +136,45 @@
 )");
 }
 
+TEST_F(IR_ValidatorTest, CallToFunctionOutsideModule) {
+    auto* f = b.Function("f", ty.void_());
+    auto* g = b.Function("g", ty.void_());
+    mod.functions.Pop();  // Remove g
+
+    b.Append(f->Block(), [&] {
+        b.Call(g);
+        b.Return(f);
+    });
+    b.Append(g->Block(), [&] { b.Return(g); });
+
+    auto res = ir::Validate(mod);
+    ASSERT_FALSE(res);
+    EXPECT_EQ(res.Failure().reason.str(),
+              R"(:3:20 error: call: call target is not part of the module
+    %2:void = call %g
+                   ^^
+
+:2:3 note: In block
+  %b1 = block {
+  ^^^^^^^^^^^
+
+note: # Disassembly
+%f = func():void -> %b1 {
+  %b1 = block {
+    %2:void = call %g
+    ret
+  }
+}
+)");
+}
+
 TEST_F(IR_ValidatorTest, Block_NoTerminator) {
     b.Function("my_func", ty.void_());
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:2:3 error: block: does not end in a terminator instruction
+    EXPECT_EQ(res.Failure().reason.str(),
+              R"(:2:3 error: block: does not end in a terminator instruction
   %b1 = block {
   ^^^^^^^^^^^
 
@@ -122,6 +186,48 @@
 )");
 }
 
+TEST_F(IR_ValidatorTest, Block_VarBlockMismatch) {
+    auto* var = b.Var(ty.ptr<function, i32>());
+
+    auto* f = b.Function("f", ty.void_());
+    f->Block()->Append(var);
+    f->Block()->Append(b.Return(f));
+
+    auto* g = b.Function("g", ty.void_());
+    g->Block()->Append(b.Return(g));
+
+    var->SetBlock(g->Block());
+
+    auto res = ir::Validate(mod);
+    ASSERT_FALSE(res);
+    EXPECT_EQ(res.Failure().reason.str(),
+              R"(:3:41 error: var: block instruction does not have same block as parent
+    %2:ptr<function, i32, read_write> = var
+                                        ^^^
+
+:2:3 note: In block
+  %b1 = block {
+  ^^^^^^^^^^^
+
+:2:3 note: In block
+  %b1 = block {
+  ^^^^^^^^^^^
+
+note: # Disassembly
+%f = func():void -> %b1 {
+  %b1 = block {
+    %2:ptr<function, i32, read_write> = var
+    ret
+  }
+}
+%g = func():void -> %b2 {
+  %b2 = block {
+    ret
+  }
+}
+)");
+}
+
 TEST_F(IR_ValidatorTest, Access_NegativeIndex) {
     auto* f = b.Function("my_func", ty.void_());
     auto* obj = b.FunctionParam(ty.vec3<f32>());
@@ -134,7 +240,8 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:25 error: access: constant index must be positive, got -1
+    EXPECT_EQ(res.Failure().reason.str(),
+              R"(:3:25 error: access: constant index must be positive, got -1
     %3:f32 = access %2, -1i
                         ^^^
 
@@ -164,7 +271,8 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:29 error: access: index out of bounds for type vec2<f32>
+    EXPECT_EQ(res.Failure().reason.str(),
+              R"(:3:29 error: access: index out of bounds for type vec2<f32>
     %3:f32 = access %2, 1u, 3u
                             ^^
 
@@ -198,7 +306,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:3:55 error: access: index out of bounds for type ptr<array<f32, 2>>
     %3:ptr<private, f32, read_write> = access %2, 1u, 3u
                                                       ^^
@@ -233,7 +341,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:25 error: access: type f32 cannot be indexed
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:25 error: access: type f32 cannot be indexed
     %3:f32 = access %2, 1u
                         ^^
 
@@ -263,7 +371,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:51 error: access: type ptr<f32> cannot be indexed
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:51 error: access: type ptr<f32> cannot be indexed
     %3:ptr<private, f32, read_write> = access %2, 1u
                                                   ^^
 
@@ -299,7 +407,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:8:25 error: access: type MyStruct cannot be dynamically indexed
     %4:i32 = access %2, %3
                         ^^
@@ -341,7 +449,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:8:25 error: access: type ptr<MyStruct> cannot be dynamically indexed
     %4:i32 = access %2, %3
                         ^^
@@ -377,7 +485,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:3:14 error: access: result of access chain is type f32 but instruction type is i32
     %3:i32 = access %2, 1u, 1u
              ^^^^^^
@@ -409,7 +517,7 @@
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
     EXPECT_EQ(
-        res.Failure().str(),
+        res.Failure().reason.str(),
         R"(:3:40 error: access: result of access chain is type ptr<f32> but instruction type is ptr<i32>
     %3:ptr<private, i32, read_write> = access %2, 1u, 1u
                                        ^^^^^^
@@ -441,7 +549,7 @@
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
     EXPECT_EQ(
-        res.Failure().str(),
+        res.Failure().reason.str(),
         R"(:3:14 error: access: result of access chain is type ptr<f32> but instruction type is f32
     %3:f32 = access %2, 1u, 1u
              ^^^^^^
@@ -472,7 +580,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:3:25 error: access: cannot obtain address of vector element
     %3:f32 = access %2, 1u
                         ^^
@@ -503,7 +611,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:3:29 error: access: cannot obtain address of vector element
     %3:f32 = access %2, 1u, 1u
                             ^^
@@ -533,7 +641,7 @@
     });
 
     auto res = ir::Validate(mod);
-    ASSERT_TRUE(res) << res.Failure().str();
+    ASSERT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, Access_IndexVector_ViaMatrix) {
@@ -547,7 +655,7 @@
     });
 
     auto res = ir::Validate(mod);
-    ASSERT_TRUE(res) << res.Failure().str();
+    ASSERT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, Block_TerminatorInMiddle) {
@@ -560,7 +668,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:3:5 error: block: terminator which isn't the final instruction
     ret
     ^^^
@@ -589,7 +697,7 @@
     f->Block()->Append(b.Return(f));
 
     auto res = ir::Validate(mod);
-    EXPECT_TRUE(res) << res.Failure().str();
+    EXPECT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, If_EmptyTrue) {
@@ -603,7 +711,8 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:4:7 error: block: does not end in a terminator instruction
+    EXPECT_EQ(res.Failure().reason.str(),
+              R"(:4:7 error: block: does not end in a terminator instruction
       %b2 = block {  # true
       ^^^^^^^^^^^
 
@@ -635,7 +744,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:8 error: if: condition must be a `bool` type
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:8 error: if: condition must be a `bool` type
     if 1i [t: %b2, f: %b3] {  # if_1
        ^^
 
@@ -672,7 +781,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:8 error: if: operand is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:8 error: if: operand is undefined
     if undef [t: %b2, f: %b3] {  # if_1
        ^^^^^
 
@@ -711,7 +820,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:5 error: if: instruction result is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: if: instruction result is undefined
     undef = if true [t: %b2, f: %b3] {  # if_1
     ^^^^^
 
@@ -747,7 +856,7 @@
     sb.Return(f);
 
     auto res = ir::Validate(mod);
-    EXPECT_TRUE(res) << res.Failure().str();
+    EXPECT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, Loop_EmptyBody) {
@@ -759,7 +868,8 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:4:7 error: block: does not end in a terminator instruction
+    EXPECT_EQ(res.Failure().reason.str(),
+              R"(:4:7 error: block: does not end in a terminator instruction
       %b2 = block {  # body
       ^^^^^^^^^^^
 
@@ -778,11 +888,11 @@
 
 TEST_F(IR_ValidatorTest, Var_RootBlock_NullResult) {
     auto* v = mod.instructions.Create<ir::Var>(nullptr);
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:2:3 error: var: instruction result is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:2:3 error: var: instruction result is undefined
   undef = var
   ^^^^^
 
@@ -809,7 +919,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:5 error: var: instruction result is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: var: instruction result is undefined
     undef = var
     ^^^^^
 
@@ -839,7 +949,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:41 error: var: initializer has incorrect type
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:41 error: var: initializer has incorrect type
     %2:ptr<function, f32, read_write> = var, %3
                                         ^^^
 
@@ -868,7 +978,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:5 error: let: instruction result is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: let: instruction result is undefined
     undef = let 1i
     ^^^^^
 
@@ -897,7 +1007,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:18 error: let: operand is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:18 error: let: operand is undefined
     %2:f32 = let undef
                  ^^^^^
 
@@ -926,7 +1036,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:14 error: let: result type does not match value type
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:14 error: let: result type does not match value type
     %2:f32 = let 1i
              ^^^
 
@@ -979,7 +1089,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), expected);
+    EXPECT_EQ(res.Failure().reason.str(), expected);
 }
 
 TEST_F(IR_ValidatorTest, Instruction_NullSource) {
@@ -993,7 +1103,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:5 error: var: instruction result source is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: var: instruction result source is undefined
     %2:ptr<function, f32, read_write> = var
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -1024,7 +1134,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:46 error: var: instruction has operand which is not alive
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:46 error: var: instruction operand 0 is not alive
     %2:ptr<function, f32, read_write> = var, %3
                                              ^^
 
@@ -1055,7 +1165,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:46 error: var: instruction operand missing usage
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:46 error: var: instruction operand 0 missing usage
     %2:ptr<function, f32, read_write> = var, %3
                                              ^^
 
@@ -1082,7 +1192,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:18 error: binary: operand is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:18 error: binary: operand is undefined
     %2:i32 = add undef, 2i
                  ^^^^^
 
@@ -1109,7 +1219,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:22 error: binary: operand is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:22 error: binary: operand is undefined
     %2:i32 = add 2i, undef
                      ^^^^^
 
@@ -1139,7 +1249,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:5 error: binary: instruction result is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: binary: instruction result is undefined
     undef = add 3i, 2i
     ^^^^^
 
@@ -1166,7 +1276,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:23 error: unary: operand is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:23 error: unary: operand is undefined
     %2:i32 = negation undef
                       ^^^^^
 
@@ -1196,7 +1306,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:5 error: unary: instruction result is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: unary: instruction result is undefined
     undef = negation 2i
     ^^^^^
 
@@ -1225,7 +1335,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:5 error: unary: result type must match value type
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: unary: result type must match value type
     %2:f32 = complement 2i
     ^^^^^^^^^^^^^^^^^^^^^^
 
@@ -1253,7 +1363,7 @@
     sb.Return(f);
 
     auto res = ir::Validate(mod);
-    EXPECT_TRUE(res) << res.Failure().str();
+    EXPECT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, ExitIf_NullIf) {
@@ -1267,7 +1377,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:5:9 error: exit_if: has no parent control instruction
+    EXPECT_EQ(res.Failure().reason.str(), R"(:5:9 error: exit_if: has no parent control instruction
         exit_if  # undef
         ^^^^^^^
 
@@ -1305,7 +1415,7 @@
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
     EXPECT_EQ(
-        res.Failure().str(),
+        res.Failure().reason.str(),
         R"(:5:9 error: exit_if: args count (1) does not match control instruction result count (2)
         exit_if 1i  # if_1
         ^^^^^^^^^^
@@ -1349,7 +1459,7 @@
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
     EXPECT_EQ(
-        res.Failure().str(),
+        res.Failure().reason.str(),
         R"(:5:9 error: exit_if: args count (3) does not match control instruction result count (2)
         exit_if 1i, 2.0f, 3i  # if_1
         ^^^^^^^^^^^^^^^^^^^^
@@ -1391,7 +1501,7 @@
     sb.Return(f);
 
     auto res = ir::Validate(mod);
-    ASSERT_TRUE(res) << res.Failure().str();
+    ASSERT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, ExitIf_IncorrectResultType) {
@@ -1410,7 +1520,7 @@
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
     EXPECT_EQ(
-        res.Failure().str(),
+        res.Failure().reason.str(),
         R"(:5:21 error: exit_if: argument type (f32) does not match control instruction type (i32)
         exit_if 1i, 2i  # if_1
                     ^^
@@ -1450,7 +1560,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:8:5 error: exit_if: found outside all control instructions
     exit_if  # if_1
     ^^^^^^^
@@ -1493,7 +1603,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:7:13 error: exit_if: if target jumps over other control instructions
             exit_if  # if_1
             ^^^^^^^
@@ -1546,7 +1656,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:7:13 error: exit_if: if target jumps over other control instructions
             exit_if  # if_1
             ^^^^^^^
@@ -1598,7 +1708,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:7:13 error: exit_if: if target jumps over other control instructions
             exit_if  # if_1
             ^^^^^^^
@@ -1642,7 +1752,7 @@
     sb.Return(f);
 
     auto res = ir::Validate(mod);
-    EXPECT_TRUE(res) << res.Failure().str();
+    EXPECT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, ExitSwitch_NullSwitch) {
@@ -1658,7 +1768,8 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:5:9 error: exit_switch: has no parent control instruction
+    EXPECT_EQ(res.Failure().reason.str(),
+              R"(:5:9 error: exit_switch: has no parent control instruction
         exit_switch  # undef
         ^^^^^^^^^^^
 
@@ -1698,7 +1809,7 @@
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
     EXPECT_EQ(
-        res.Failure().str(),
+        res.Failure().reason.str(),
         R"(:5:9 error: exit_switch: args count (1) does not match control instruction result count (2)
         exit_switch 1i  # switch_1
         ^^^^^^^^^^^^^^
@@ -1742,7 +1853,7 @@
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
     EXPECT_EQ(
-        res.Failure().str(),
+        res.Failure().reason.str(),
         R"(:5:9 error: exit_switch: args count (3) does not match control instruction result count (2)
         exit_switch 1i, 2.0f, 3i  # switch_1
         ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1784,7 +1895,7 @@
     sb.Return(f);
 
     auto res = ir::Validate(mod);
-    ASSERT_TRUE(res) << res.Failure().str();
+    ASSERT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, ExitSwitch_IncorrectResultType) {
@@ -1804,7 +1915,7 @@
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
     EXPECT_EQ(
-        res.Failure().str(),
+        res.Failure().reason.str(),
         R"(:5:25 error: exit_switch: argument type (f32) does not match control instruction type (i32)
         exit_switch 1i, 2i  # switch_1
                         ^^
@@ -1848,7 +1959,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:10:9 error: exit_switch: switch not found in parent control instructions
         exit_switch  # switch_1
         ^^^^^^^^^^^
@@ -1906,7 +2017,7 @@
     sb.Return(f);
 
     auto res = ir::Validate(mod);
-    EXPECT_TRUE(res) << res.Failure().str();
+    EXPECT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, ExitSwitch_InvalidJumpOverSwitch) {
@@ -1930,7 +2041,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:7:13 error: exit_switch: switch target jumps over other control instructions
             exit_switch  # switch_1
             ^^^^^^^^^^^
@@ -1981,7 +2092,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:7:13 error: exit_switch: switch target jumps over other control instructions
             exit_switch  # switch_1
             ^^^^^^^^^^^
@@ -2024,7 +2135,7 @@
     sb.Return(f);
 
     auto res = ir::Validate(mod);
-    EXPECT_TRUE(res) << res.Failure().str();
+    EXPECT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, ExitLoop_NullLoop) {
@@ -2039,7 +2150,8 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:5:9 error: exit_loop: has no parent control instruction
+    EXPECT_EQ(res.Failure().reason.str(),
+              R"(:5:9 error: exit_loop: has no parent control instruction
         exit_loop  # undef
         ^^^^^^^^^
 
@@ -2081,7 +2193,7 @@
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
     EXPECT_EQ(
-        res.Failure().str(),
+        res.Failure().reason.str(),
         R"(:5:9 error: exit_loop: args count (1) does not match control instruction result count (2)
         exit_loop 1i  # loop_1
         ^^^^^^^^^^^^
@@ -2128,7 +2240,7 @@
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
     EXPECT_EQ(
-        res.Failure().str(),
+        res.Failure().reason.str(),
         R"(:5:9 error: exit_loop: args count (3) does not match control instruction result count (2)
         exit_loop 1i, 2.0f, 3i  # loop_1
         ^^^^^^^^^^^^^^^^^^^^^^
@@ -2173,7 +2285,7 @@
     sb.Return(f);
 
     auto res = ir::Validate(mod);
-    ASSERT_TRUE(res) << res.Failure().str();
+    ASSERT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, ExitLoop_IncorrectResultType) {
@@ -2193,7 +2305,7 @@
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
     EXPECT_EQ(
-        res.Failure().str(),
+        res.Failure().reason.str(),
         R"(:5:23 error: exit_loop: argument type (f32) does not match control instruction type (i32)
         exit_loop 1i, 2i  # loop_1
                       ^^
@@ -2239,7 +2351,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:13:9 error: exit_loop: loop not found in parent control instructions
         exit_loop  # loop_1
         ^^^^^^^^^
@@ -2299,7 +2411,7 @@
     sb.Return(f);
 
     auto res = ir::Validate(mod);
-    EXPECT_TRUE(res) << res.Failure().str();
+    EXPECT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, ExitLoop_InvalidJumpOverSwitch) {
@@ -2323,7 +2435,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:7:13 error: exit_loop: loop target jumps over other control instructions
             exit_loop  # loop_1
             ^^^^^^^^^
@@ -2378,7 +2490,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:7:13 error: exit_loop: loop target jumps over other control instructions
             exit_loop  # loop_1
             ^^^^^^^^^
@@ -2428,7 +2540,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:8:9 error: exit_loop: loop exit jumps out of continuing block
         exit_loop  # loop_1
         ^^^^^^^^^
@@ -2474,7 +2586,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:10:13 error: exit_loop: loop exit jumps out of continuing block
             exit_loop  # loop_1
             ^^^^^^^^^
@@ -2526,7 +2638,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:5:9 error: exit_loop: loop exit not permitted in loop initializer
         exit_loop  # loop_1
         ^^^^^^^^^
@@ -2576,7 +2688,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:7:13 error: exit_loop: loop exit not permitted in loop initializer
             exit_loop  # loop_1
             ^^^^^^^^^
@@ -2621,7 +2733,7 @@
     });
 
     auto res = ir::Validate(mod);
-    EXPECT_TRUE(res) << res.Failure().str();
+    EXPECT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, Return_WithValue) {
@@ -2631,7 +2743,7 @@
     });
 
     auto res = ir::Validate(mod);
-    EXPECT_TRUE(res) << res.Failure().str();
+    EXPECT_TRUE(res) << res.Failure().reason.str();
 }
 
 TEST_F(IR_ValidatorTest, Return_NullFunction) {
@@ -2642,7 +2754,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:5 error: return: undefined function
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: return: undefined function
     ret
     ^^^
 
@@ -2667,7 +2779,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:5 error: return: unexpected return value
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: return: unexpected return value
     ret 42i
     ^^^^^^^
 
@@ -2692,7 +2804,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:5 error: return: expected return value
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: return: expected return value
     ret
     ^^^
 
@@ -2717,7 +2829,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:3:5 error: return: return value type does not match function return type
     ret 42.0f
     ^^^^^^^^^
@@ -2745,7 +2857,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:11 error: store: operand is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:11 error: store: operand is undefined
     store undef, 42i
           ^^^^^
 
@@ -2774,7 +2886,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:4:15 error: store: operand is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:4:15 error: store: operand is undefined
     store %2, undef
               ^^^^^
 
@@ -2804,7 +2916,8 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:4:15 error: value type does not match pointer element type
+    EXPECT_EQ(res.Failure().reason.str(),
+              R"(:4:15 error: value type does not match pointer element type
     store %2, 42u
               ^^^
 
@@ -2835,7 +2948,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(),
+    EXPECT_EQ(res.Failure().reason.str(),
               R"(:4:5 error: load_vector_element: instruction result is undefined
     undef = load_vector_element %2, 1i
     ^^^^^
@@ -2866,7 +2979,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:34 error: load_vector_element: operand is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:34 error: load_vector_element: operand is undefined
     %2:f32 = load_vector_element undef, 1i
                                  ^^^^^
 
@@ -2896,7 +3009,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:4:38 error: load_vector_element: operand is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:4:38 error: load_vector_element: operand is undefined
     %3:f32 = load_vector_element %2, undef
                                      ^^^^^
 
@@ -2926,7 +3039,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:3:26 error: store_vector_element: operand is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:3:26 error: store_vector_element: operand is undefined
     store_vector_element undef, 1i, 2i
                          ^^^^^
 
@@ -2956,7 +3069,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:4:30 error: store_vector_element: operand is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:4:30 error: store_vector_element: operand is undefined
     store_vector_element %2, undef, 2i
                              ^^^^^
 
@@ -2995,7 +3108,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_FALSE(res);
-    EXPECT_EQ(res.Failure().str(), R"(:4:34 error: store_vector_element: operand is undefined
+    EXPECT_EQ(res.Failure().reason.str(), R"(:4:34 error: store_vector_element: operand is undefined
     store_vector_element %2, 1i, undef
                                  ^^^^^
 
diff --git a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
index 89387ae..e61c9c6 100644
--- a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
@@ -245,7 +245,7 @@
 
     data.Add<ast::transform::BindingRemapper::Remappings>(
         options.binding_remapper_options.binding_points,
-        options.binding_remapper_options.access_controls,
+        std::unordered_map<BindingPoint, core::Access>{},
         options.binding_remapper_options.allow_collisions);
     manager.Add<ast::transform::BindingRemapper>();
 
@@ -856,35 +856,35 @@
     auto* expr = call->Declaration();
     if (builtin->IsTexture()) {
         EmitTextureCall(out, call, builtin);
-    } else if (builtin->Fn() == core::BuiltinFn::kCountOneBits) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kCountOneBits) {
         EmitCountOneBitsCall(out, expr);
-    } else if (builtin->Fn() == core::BuiltinFn::kSelect) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kSelect) {
         EmitSelectCall(out, expr, builtin);
-    } else if (builtin->Fn() == core::BuiltinFn::kDot) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kDot) {
         EmitDotCall(out, expr, builtin);
-    } else if (builtin->Fn() == core::BuiltinFn::kModf) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kModf) {
         EmitModfCall(out, expr, builtin);
-    } else if (builtin->Fn() == core::BuiltinFn::kFrexp) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kFrexp) {
         EmitFrexpCall(out, expr, builtin);
-    } else if (builtin->Fn() == core::BuiltinFn::kDegrees) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kDegrees) {
         EmitDegreesCall(out, expr, builtin);
-    } else if (builtin->Fn() == core::BuiltinFn::kRadians) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kRadians) {
         EmitRadiansCall(out, expr, builtin);
-    } else if (builtin->Fn() == core::BuiltinFn::kQuantizeToF16) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kQuantizeToF16) {
         EmitQuantizeToF16Call(out, expr, builtin);
-    } else if (builtin->Fn() == core::BuiltinFn::kArrayLength) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kArrayLength) {
         EmitArrayLength(out, expr);
-    } else if (builtin->Fn() == core::BuiltinFn::kExtractBits) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kExtractBits) {
         EmitExtractBits(out, expr);
-    } else if (builtin->Fn() == core::BuiltinFn::kInsertBits) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kInsertBits) {
         EmitInsertBits(out, expr);
-    } else if (builtin->Fn() == core::BuiltinFn::kFma && version_.IsES()) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kFma && version_.IsES()) {
         EmitEmulatedFMA(out, expr);
-    } else if (builtin->Fn() == core::BuiltinFn::kAbs &&
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kAbs &&
                TypeOf(expr->args[0])->UnwrapRef()->is_unsigned_integer_scalar_or_vector()) {
         // GLSL does not support abs() on unsigned arguments. However, it's a no-op.
         EmitExpression(out, expr->args[0]);
-    } else if ((builtin->Fn() == core::BuiltinFn::kAny || builtin->Fn() == core::BuiltinFn::kAll) &&
+    } else if ((builtin->Fn() == wgsl::BuiltinFn::kAny || builtin->Fn() == wgsl::BuiltinFn::kAll) &&
                TypeOf(expr->args[0])->UnwrapRef()->Is<core::type::Scalar>()) {
         // GLSL does not support any() or all() on scalar arguments. It's a no-op.
         EmitExpression(out, expr->args[0]);
@@ -966,7 +966,7 @@
     };
 
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kAtomicLoad: {
+        case wgsl::BuiltinFn::kAtomicLoad: {
             // GLSL does not have an atomicLoad, so we emulate it with
             // atomicOr using 0 as the OR value
             out << "atomicOr";
@@ -980,7 +980,7 @@
             }
             return;
         }
-        case core::BuiltinFn::kAtomicCompareExchangeWeak: {
+        case wgsl::BuiltinFn::kAtomicCompareExchangeWeak: {
             EmitStructType(&helpers_, builtin->ReturnType()->As<core::type::Struct>());
 
             auto* dest = expr->args[0];
@@ -1019,33 +1019,33 @@
             return;
         }
 
-        case core::BuiltinFn::kAtomicAdd:
-        case core::BuiltinFn::kAtomicSub:
+        case wgsl::BuiltinFn::kAtomicAdd:
+        case wgsl::BuiltinFn::kAtomicSub:
             call("atomicAdd");
             return;
 
-        case core::BuiltinFn::kAtomicMax:
+        case wgsl::BuiltinFn::kAtomicMax:
             call("atomicMax");
             return;
 
-        case core::BuiltinFn::kAtomicMin:
+        case wgsl::BuiltinFn::kAtomicMin:
             call("atomicMin");
             return;
 
-        case core::BuiltinFn::kAtomicAnd:
+        case wgsl::BuiltinFn::kAtomicAnd:
             call("atomicAnd");
             return;
 
-        case core::BuiltinFn::kAtomicOr:
+        case wgsl::BuiltinFn::kAtomicOr:
             call("atomicOr");
             return;
 
-        case core::BuiltinFn::kAtomicXor:
+        case wgsl::BuiltinFn::kAtomicXor:
             call("atomicXor");
             return;
 
-        case core::BuiltinFn::kAtomicExchange:
-        case core::BuiltinFn::kAtomicStore:
+        case wgsl::BuiltinFn::kAtomicExchange:
+        case wgsl::BuiltinFn::kAtomicStore:
             // GLSL does not have an atomicStore, so we emulate it with
             // atomicExchange.
             call("atomicExchange");
@@ -1301,14 +1301,14 @@
 void ASTPrinter::EmitBarrierCall(StringStream& out, const sem::BuiltinFn* builtin) {
     // TODO(crbug.com/tint/661): Combine sequential barriers to a single
     // instruction.
-    if (builtin->Fn() == core::BuiltinFn::kWorkgroupBarrier) {
+    if (builtin->Fn() == wgsl::BuiltinFn::kWorkgroupBarrier) {
         out << "barrier()";
-    } else if (builtin->Fn() == core::BuiltinFn::kStorageBarrier) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kStorageBarrier) {
         out << "{ barrier(); memoryBarrierBuffer(); }";
-    } else if (builtin->Fn() == core::BuiltinFn::kTextureBarrier) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kTextureBarrier) {
         out << "{ barrier(); memoryBarrierImage(); }";
     } else {
-        TINT_UNREACHABLE() << "unexpected barrier builtin type " << core::str(builtin->Fn());
+        TINT_UNREACHABLE() << "unexpected barrier builtin type " << builtin->Fn();
     }
 }
 
@@ -1376,7 +1376,7 @@
     };
 
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kTextureDimensions: {
+        case wgsl::BuiltinFn::kTextureDimensions: {
             // textureDimensions() returns an unsigned scalar / vector in WGSL.
             // textureSize() / imageSize() returns a signed scalar / vector in GLSL.
             // Cast.
@@ -1411,7 +1411,7 @@
             }
             return;
         }
-        case core::BuiltinFn::kTextureNumLayers: {
+        case wgsl::BuiltinFn::kTextureNumLayers: {
             // textureNumLayers() returns an unsigned scalar in WGSL.
             // textureSize() / imageSize() returns a signed scalar / vector in GLSL.
             // Cast.
@@ -1442,7 +1442,7 @@
             out << ").z";
             return;
         }
-        case core::BuiltinFn::kTextureNumLevels: {
+        case wgsl::BuiltinFn::kTextureNumLevels: {
             // textureNumLevels() returns an unsigned scalar in WGSL.
             // textureQueryLevels() returns a signed scalar in GLSL.
             // Cast.
@@ -1454,7 +1454,7 @@
             out << ")";
             return;
         }
-        case core::BuiltinFn::kTextureNumSamples: {
+        case wgsl::BuiltinFn::kTextureNumSamples: {
             // textureNumSamples() returns an unsigned scalar in WGSL.
             // textureSamples() returns a signed scalar in GLSL.
             // Cast.
@@ -1475,40 +1475,40 @@
     bool is_depth = texture_type->Is<core::type::DepthTexture>();
 
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kTextureSample:
-        case core::BuiltinFn::kTextureSampleBias:
+        case wgsl::BuiltinFn::kTextureSample:
+        case wgsl::BuiltinFn::kTextureSampleBias:
             out << "texture";
             if (is_depth) {
                 glsl_ret_width = 1u;
             }
             break;
-        case core::BuiltinFn::kTextureSampleLevel:
+        case wgsl::BuiltinFn::kTextureSampleLevel:
             out << "textureLod";
             if (is_depth) {
                 glsl_ret_width = 1u;
             }
             break;
-        case core::BuiltinFn::kTextureGather:
-        case core::BuiltinFn::kTextureGatherCompare:
+        case wgsl::BuiltinFn::kTextureGather:
+        case wgsl::BuiltinFn::kTextureGatherCompare:
             out << "textureGather";
             append_depth_ref_to_coords = false;
             break;
-        case core::BuiltinFn::kTextureSampleGrad:
+        case wgsl::BuiltinFn::kTextureSampleGrad:
             out << "textureGrad";
             break;
-        case core::BuiltinFn::kTextureSampleCompare:
-        case core::BuiltinFn::kTextureSampleCompareLevel:
+        case wgsl::BuiltinFn::kTextureSampleCompare:
+        case wgsl::BuiltinFn::kTextureSampleCompareLevel:
             out << "texture";
             glsl_ret_width = 1;
             break;
-        case core::BuiltinFn::kTextureLoad:
+        case wgsl::BuiltinFn::kTextureLoad:
             if (texture_type->Is<core::type::StorageTexture>()) {
                 out << "imageLoad";
             } else {
                 out << "texelFetch";
             }
             break;
-        case core::BuiltinFn::kTextureStore:
+        case wgsl::BuiltinFn::kTextureStore:
             out << "imageStore";
             break;
         default:
@@ -1579,7 +1579,7 @@
     }
 
     // GLSL's textureGather always requires a refZ parameter.
-    if (is_depth && builtin->Fn() == core::BuiltinFn::kTextureGather) {
+    if (is_depth && builtin->Fn() == wgsl::BuiltinFn::kTextureGather) {
         out << ", 0.0";
     }
 
@@ -1588,7 +1588,7 @@
         if (auto* e = arg(Usage::kDepthRef)) {
             out << ", ";
             EmitExpression(out, e);
-        } else if (builtin->Fn() == core::BuiltinFn::kTextureSample) {
+        } else if (builtin->Fn() == wgsl::BuiltinFn::kTextureSample) {
             out << ", 0.0f";
         }
     }
@@ -1628,114 +1628,114 @@
 
 std::string ASTPrinter::generate_builtin_name(const sem::BuiltinFn* builtin) {
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kAbs:
-        case core::BuiltinFn::kAcos:
-        case core::BuiltinFn::kAcosh:
-        case core::BuiltinFn::kAll:
-        case core::BuiltinFn::kAny:
-        case core::BuiltinFn::kAsin:
-        case core::BuiltinFn::kAsinh:
-        case core::BuiltinFn::kAtan:
-        case core::BuiltinFn::kAtanh:
-        case core::BuiltinFn::kCeil:
-        case core::BuiltinFn::kClamp:
-        case core::BuiltinFn::kCos:
-        case core::BuiltinFn::kCosh:
-        case core::BuiltinFn::kCross:
-        case core::BuiltinFn::kDeterminant:
-        case core::BuiltinFn::kDistance:
-        case core::BuiltinFn::kDot:
-        case core::BuiltinFn::kExp:
-        case core::BuiltinFn::kExp2:
-        case core::BuiltinFn::kFloor:
-        case core::BuiltinFn::kFrexp:
-        case core::BuiltinFn::kLdexp:
-        case core::BuiltinFn::kLength:
-        case core::BuiltinFn::kLog:
-        case core::BuiltinFn::kLog2:
-        case core::BuiltinFn::kMax:
-        case core::BuiltinFn::kMin:
-        case core::BuiltinFn::kModf:
-        case core::BuiltinFn::kNormalize:
-        case core::BuiltinFn::kPow:
-        case core::BuiltinFn::kReflect:
-        case core::BuiltinFn::kRefract:
-        case core::BuiltinFn::kRound:
-        case core::BuiltinFn::kSign:
-        case core::BuiltinFn::kSin:
-        case core::BuiltinFn::kSinh:
-        case core::BuiltinFn::kSqrt:
-        case core::BuiltinFn::kStep:
-        case core::BuiltinFn::kTan:
-        case core::BuiltinFn::kTanh:
-        case core::BuiltinFn::kTranspose:
-        case core::BuiltinFn::kTrunc:
+        case wgsl::BuiltinFn::kAbs:
+        case wgsl::BuiltinFn::kAcos:
+        case wgsl::BuiltinFn::kAcosh:
+        case wgsl::BuiltinFn::kAll:
+        case wgsl::BuiltinFn::kAny:
+        case wgsl::BuiltinFn::kAsin:
+        case wgsl::BuiltinFn::kAsinh:
+        case wgsl::BuiltinFn::kAtan:
+        case wgsl::BuiltinFn::kAtanh:
+        case wgsl::BuiltinFn::kCeil:
+        case wgsl::BuiltinFn::kClamp:
+        case wgsl::BuiltinFn::kCos:
+        case wgsl::BuiltinFn::kCosh:
+        case wgsl::BuiltinFn::kCross:
+        case wgsl::BuiltinFn::kDeterminant:
+        case wgsl::BuiltinFn::kDistance:
+        case wgsl::BuiltinFn::kDot:
+        case wgsl::BuiltinFn::kExp:
+        case wgsl::BuiltinFn::kExp2:
+        case wgsl::BuiltinFn::kFloor:
+        case wgsl::BuiltinFn::kFrexp:
+        case wgsl::BuiltinFn::kLdexp:
+        case wgsl::BuiltinFn::kLength:
+        case wgsl::BuiltinFn::kLog:
+        case wgsl::BuiltinFn::kLog2:
+        case wgsl::BuiltinFn::kMax:
+        case wgsl::BuiltinFn::kMin:
+        case wgsl::BuiltinFn::kModf:
+        case wgsl::BuiltinFn::kNormalize:
+        case wgsl::BuiltinFn::kPow:
+        case wgsl::BuiltinFn::kReflect:
+        case wgsl::BuiltinFn::kRefract:
+        case wgsl::BuiltinFn::kRound:
+        case wgsl::BuiltinFn::kSign:
+        case wgsl::BuiltinFn::kSin:
+        case wgsl::BuiltinFn::kSinh:
+        case wgsl::BuiltinFn::kSqrt:
+        case wgsl::BuiltinFn::kStep:
+        case wgsl::BuiltinFn::kTan:
+        case wgsl::BuiltinFn::kTanh:
+        case wgsl::BuiltinFn::kTranspose:
+        case wgsl::BuiltinFn::kTrunc:
             return builtin->str();
-        case core::BuiltinFn::kAtan2:
+        case wgsl::BuiltinFn::kAtan2:
             return "atan";
-        case core::BuiltinFn::kCountOneBits:
+        case wgsl::BuiltinFn::kCountOneBits:
             return "bitCount";
-        case core::BuiltinFn::kDpdx:
+        case wgsl::BuiltinFn::kDpdx:
             return "dFdx";
-        case core::BuiltinFn::kDpdxCoarse:
+        case wgsl::BuiltinFn::kDpdxCoarse:
             if (version_.IsES()) {
                 return "dFdx";
             }
             return "dFdxCoarse";
-        case core::BuiltinFn::kDpdxFine:
+        case wgsl::BuiltinFn::kDpdxFine:
             if (version_.IsES()) {
                 return "dFdx";
             }
             return "dFdxFine";
-        case core::BuiltinFn::kDpdy:
+        case wgsl::BuiltinFn::kDpdy:
             return "dFdy";
-        case core::BuiltinFn::kDpdyCoarse:
+        case wgsl::BuiltinFn::kDpdyCoarse:
             if (version_.IsES()) {
                 return "dFdy";
             }
             return "dFdyCoarse";
-        case core::BuiltinFn::kDpdyFine:
+        case wgsl::BuiltinFn::kDpdyFine:
             if (version_.IsES()) {
                 return "dFdy";
             }
             return "dFdyFine";
-        case core::BuiltinFn::kFaceForward:
+        case wgsl::BuiltinFn::kFaceForward:
             return "faceforward";
-        case core::BuiltinFn::kFract:
+        case wgsl::BuiltinFn::kFract:
             return "fract";
-        case core::BuiltinFn::kFma:
+        case wgsl::BuiltinFn::kFma:
             return "fma";
-        case core::BuiltinFn::kFwidth:
-        case core::BuiltinFn::kFwidthCoarse:
-        case core::BuiltinFn::kFwidthFine:
+        case wgsl::BuiltinFn::kFwidth:
+        case wgsl::BuiltinFn::kFwidthCoarse:
+        case wgsl::BuiltinFn::kFwidthFine:
             return "fwidth";
-        case core::BuiltinFn::kInverseSqrt:
+        case wgsl::BuiltinFn::kInverseSqrt:
             return "inversesqrt";
-        case core::BuiltinFn::kMix:
+        case wgsl::BuiltinFn::kMix:
             return "mix";
-        case core::BuiltinFn::kPack2X16Float:
+        case wgsl::BuiltinFn::kPack2X16Float:
             return "packHalf2x16";
-        case core::BuiltinFn::kPack2X16Snorm:
+        case wgsl::BuiltinFn::kPack2X16Snorm:
             return "packSnorm2x16";
-        case core::BuiltinFn::kPack2X16Unorm:
+        case wgsl::BuiltinFn::kPack2X16Unorm:
             return "packUnorm2x16";
-        case core::BuiltinFn::kPack4X8Snorm:
+        case wgsl::BuiltinFn::kPack4X8Snorm:
             return "packSnorm4x8";
-        case core::BuiltinFn::kPack4X8Unorm:
+        case wgsl::BuiltinFn::kPack4X8Unorm:
             return "packUnorm4x8";
-        case core::BuiltinFn::kReverseBits:
+        case wgsl::BuiltinFn::kReverseBits:
             return "bitfieldReverse";
-        case core::BuiltinFn::kSmoothstep:
+        case wgsl::BuiltinFn::kSmoothstep:
             return "smoothstep";
-        case core::BuiltinFn::kUnpack2X16Float:
+        case wgsl::BuiltinFn::kUnpack2X16Float:
             return "unpackHalf2x16";
-        case core::BuiltinFn::kUnpack2X16Snorm:
+        case wgsl::BuiltinFn::kUnpack2X16Snorm:
             return "unpackSnorm2x16";
-        case core::BuiltinFn::kUnpack2X16Unorm:
+        case wgsl::BuiltinFn::kUnpack2X16Unorm:
             return "unpackUnorm2x16";
-        case core::BuiltinFn::kUnpack4X8Snorm:
+        case wgsl::BuiltinFn::kUnpack4X8Snorm:
             return "unpackSnorm4x8";
-        case core::BuiltinFn::kUnpack4X8Unorm:
+        case wgsl::BuiltinFn::kUnpack4X8Unorm:
             return "unpackUnorm4x8";
         default:
             diagnostics_.add_error(diag::System::Writer,
@@ -2964,7 +2964,7 @@
         TextBuffer b;
         TINT_DEFER(helpers_.Append(b));
 
-        auto fn_name = UniqueIdentifier(std::string("tint_") + core::str(builtin->Fn()));
+        auto fn_name = UniqueIdentifier(std::string("tint_") + wgsl::str(builtin->Fn()));
         std::vector<std::string> parameter_names;
         {
             auto decl = Line(&b);
diff --git a/src/tint/lang/glsl/writer/ast_printer/ast_printer_test.cc b/src/tint/lang/glsl/writer/ast_printer/ast_printer_test.cc
index fe63847..8412fc6 100644
--- a/src/tint/lang/glsl/writer/ast_printer/ast_printer_test.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/ast_printer_test.cc
@@ -28,7 +28,7 @@
     ASSERT_FALSE(program.IsValid());
     auto result = Generate(program, Options{}, "");
     EXPECT_FALSE(result);
-    EXPECT_EQ(result.Failure(), "input program is not valid");
+    EXPECT_EQ(result.Failure().reason.str(), "error: make the program invalid");
 }
 
 TEST_F(GlslASTPrinterTest, Generate) {
diff --git a/src/tint/lang/glsl/writer/ast_printer/builtin_test.cc b/src/tint/lang/glsl/writer/ast_printer/builtin_test.cc
index c23b308..843b66d 100644
--- a/src/tint/lang/glsl/writer/ast_printer/builtin_test.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/builtin_test.cc
@@ -36,7 +36,7 @@
 };
 
 struct BuiltinData {
-    core::BuiltinFn builtin;
+    wgsl::BuiltinFn builtin;
     CallParamType type;
     const char* glsl_name;
 };
@@ -60,86 +60,86 @@
     return out;
 }
 
-const ast::CallExpression* GenerateCall(core::BuiltinFn builtin,
+const ast::CallExpression* GenerateCall(wgsl::BuiltinFn builtin,
                                         CallParamType type,
                                         ProgramBuilder* builder) {
     std::string name;
     StringStream str;
     str << name << builtin;
     switch (builtin) {
-        case core::BuiltinFn::kAcos:
-        case core::BuiltinFn::kAsin:
-        case core::BuiltinFn::kAtan:
-        case core::BuiltinFn::kCeil:
-        case core::BuiltinFn::kCos:
-        case core::BuiltinFn::kCosh:
-        case core::BuiltinFn::kDpdx:
-        case core::BuiltinFn::kDpdxCoarse:
-        case core::BuiltinFn::kDpdxFine:
-        case core::BuiltinFn::kDpdy:
-        case core::BuiltinFn::kDpdyCoarse:
-        case core::BuiltinFn::kDpdyFine:
-        case core::BuiltinFn::kExp:
-        case core::BuiltinFn::kExp2:
-        case core::BuiltinFn::kFloor:
-        case core::BuiltinFn::kFract:
-        case core::BuiltinFn::kFwidth:
-        case core::BuiltinFn::kFwidthCoarse:
-        case core::BuiltinFn::kFwidthFine:
-        case core::BuiltinFn::kInverseSqrt:
-        case core::BuiltinFn::kLength:
-        case core::BuiltinFn::kLog:
-        case core::BuiltinFn::kLog2:
-        case core::BuiltinFn::kNormalize:
-        case core::BuiltinFn::kRound:
-        case core::BuiltinFn::kSin:
-        case core::BuiltinFn::kSinh:
-        case core::BuiltinFn::kSqrt:
-        case core::BuiltinFn::kTan:
-        case core::BuiltinFn::kTanh:
-        case core::BuiltinFn::kTrunc:
-        case core::BuiltinFn::kSign:
+        case wgsl::BuiltinFn::kAcos:
+        case wgsl::BuiltinFn::kAsin:
+        case wgsl::BuiltinFn::kAtan:
+        case wgsl::BuiltinFn::kCeil:
+        case wgsl::BuiltinFn::kCos:
+        case wgsl::BuiltinFn::kCosh:
+        case wgsl::BuiltinFn::kDpdx:
+        case wgsl::BuiltinFn::kDpdxCoarse:
+        case wgsl::BuiltinFn::kDpdxFine:
+        case wgsl::BuiltinFn::kDpdy:
+        case wgsl::BuiltinFn::kDpdyCoarse:
+        case wgsl::BuiltinFn::kDpdyFine:
+        case wgsl::BuiltinFn::kExp:
+        case wgsl::BuiltinFn::kExp2:
+        case wgsl::BuiltinFn::kFloor:
+        case wgsl::BuiltinFn::kFract:
+        case wgsl::BuiltinFn::kFwidth:
+        case wgsl::BuiltinFn::kFwidthCoarse:
+        case wgsl::BuiltinFn::kFwidthFine:
+        case wgsl::BuiltinFn::kInverseSqrt:
+        case wgsl::BuiltinFn::kLength:
+        case wgsl::BuiltinFn::kLog:
+        case wgsl::BuiltinFn::kLog2:
+        case wgsl::BuiltinFn::kNormalize:
+        case wgsl::BuiltinFn::kRound:
+        case wgsl::BuiltinFn::kSin:
+        case wgsl::BuiltinFn::kSinh:
+        case wgsl::BuiltinFn::kSqrt:
+        case wgsl::BuiltinFn::kTan:
+        case wgsl::BuiltinFn::kTanh:
+        case wgsl::BuiltinFn::kTrunc:
+        case wgsl::BuiltinFn::kSign:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2");
             } else {
                 return builder->Call(str.str(), "f2");
             }
-        case core::BuiltinFn::kLdexp:
+        case wgsl::BuiltinFn::kLdexp:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "i2");
             } else {
                 return builder->Call(str.str(), "f2", "i2");
             }
-        case core::BuiltinFn::kAtan2:
-        case core::BuiltinFn::kDot:
-        case core::BuiltinFn::kDistance:
-        case core::BuiltinFn::kPow:
-        case core::BuiltinFn::kReflect:
-        case core::BuiltinFn::kStep:
+        case wgsl::BuiltinFn::kAtan2:
+        case wgsl::BuiltinFn::kDot:
+        case wgsl::BuiltinFn::kDistance:
+        case wgsl::BuiltinFn::kPow:
+        case wgsl::BuiltinFn::kReflect:
+        case wgsl::BuiltinFn::kStep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2");
             }
-        case core::BuiltinFn::kCross:
+        case wgsl::BuiltinFn::kCross:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h3", "h3");
             } else {
                 return builder->Call(str.str(), "f3", "f3");
             }
-        case core::BuiltinFn::kFma:
-        case core::BuiltinFn::kMix:
-        case core::BuiltinFn::kFaceForward:
-        case core::BuiltinFn::kSmoothstep:
+        case wgsl::BuiltinFn::kFma:
+        case wgsl::BuiltinFn::kMix:
+        case wgsl::BuiltinFn::kFaceForward:
+        case wgsl::BuiltinFn::kSmoothstep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             }
-        case core::BuiltinFn::kAll:
-        case core::BuiltinFn::kAny:
+        case wgsl::BuiltinFn::kAll:
+        case wgsl::BuiltinFn::kAny:
             return builder->Call(str.str(), "b2");
-        case core::BuiltinFn::kAbs:
+        case wgsl::BuiltinFn::kAbs:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2");
             } else if (type == CallParamType::kF16) {
@@ -147,11 +147,11 @@
             } else {
                 return builder->Call(str.str(), "u2");
             }
-        case core::BuiltinFn::kCountOneBits:
-        case core::BuiltinFn::kReverseBits:
+        case wgsl::BuiltinFn::kCountOneBits:
+        case wgsl::BuiltinFn::kReverseBits:
             return builder->Call(str.str(), "u2");
-        case core::BuiltinFn::kMax:
-        case core::BuiltinFn::kMin:
+        case wgsl::BuiltinFn::kMax:
+        case wgsl::BuiltinFn::kMin:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -159,7 +159,7 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2");
             }
-        case core::BuiltinFn::kClamp:
+        case wgsl::BuiltinFn::kClamp:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -167,19 +167,19 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2", "u2");
             }
-        case core::BuiltinFn::kSelect:
+        case wgsl::BuiltinFn::kSelect:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "b2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "b2");
             }
-        case core::BuiltinFn::kDeterminant:
+        case wgsl::BuiltinFn::kDeterminant:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm2x2");
             } else {
                 return builder->Call(str.str(), "m2x2");
             }
-        case core::BuiltinFn::kTranspose:
+        case wgsl::BuiltinFn::kTranspose:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm3x2");
             } else {
@@ -234,110 +234,110 @@
     GlslASTPrinterTest_Builtin,
     GlslBuiltinTest,
     testing::Values(/* Logical built-in */
-                    BuiltinData{core::BuiltinFn::kAll, CallParamType::kBool, "all"},
-                    BuiltinData{core::BuiltinFn::kAny, CallParamType::kBool, "any"},
+                    BuiltinData{wgsl::BuiltinFn::kAll, CallParamType::kBool, "all"},
+                    BuiltinData{wgsl::BuiltinFn::kAny, CallParamType::kBool, "any"},
                     /* Float built-in */
-                    BuiltinData{core::BuiltinFn::kAbs, CallParamType::kF32, "abs"},
-                    BuiltinData{core::BuiltinFn::kAbs, CallParamType::kF16, "abs"},
-                    BuiltinData{core::BuiltinFn::kAcos, CallParamType::kF32, "acos"},
-                    BuiltinData{core::BuiltinFn::kAcos, CallParamType::kF16, "acos"},
-                    BuiltinData{core::BuiltinFn::kAsin, CallParamType::kF32, "asin"},
-                    BuiltinData{core::BuiltinFn::kAsin, CallParamType::kF16, "asin"},
-                    BuiltinData{core::BuiltinFn::kAtan, CallParamType::kF32, "atan"},
-                    BuiltinData{core::BuiltinFn::kAtan, CallParamType::kF16, "atan"},
-                    BuiltinData{core::BuiltinFn::kAtan2, CallParamType::kF32, "atan"},
-                    BuiltinData{core::BuiltinFn::kAtan2, CallParamType::kF16, "atan"},
-                    BuiltinData{core::BuiltinFn::kCeil, CallParamType::kF32, "ceil"},
-                    BuiltinData{core::BuiltinFn::kCeil, CallParamType::kF16, "ceil"},
-                    BuiltinData{core::BuiltinFn::kClamp, CallParamType::kF32, "clamp"},
-                    BuiltinData{core::BuiltinFn::kClamp, CallParamType::kF16, "clamp"},
-                    BuiltinData{core::BuiltinFn::kCos, CallParamType::kF32, "cos"},
-                    BuiltinData{core::BuiltinFn::kCos, CallParamType::kF16, "cos"},
-                    BuiltinData{core::BuiltinFn::kCosh, CallParamType::kF32, "cosh"},
-                    BuiltinData{core::BuiltinFn::kCosh, CallParamType::kF16, "cosh"},
-                    BuiltinData{core::BuiltinFn::kCross, CallParamType::kF32, "cross"},
-                    BuiltinData{core::BuiltinFn::kCross, CallParamType::kF16, "cross"},
-                    BuiltinData{core::BuiltinFn::kDistance, CallParamType::kF32, "distance"},
-                    BuiltinData{core::BuiltinFn::kDistance, CallParamType::kF16, "distance"},
-                    BuiltinData{core::BuiltinFn::kExp, CallParamType::kF32, "exp"},
-                    BuiltinData{core::BuiltinFn::kExp, CallParamType::kF16, "exp"},
-                    BuiltinData{core::BuiltinFn::kExp2, CallParamType::kF32, "exp2"},
-                    BuiltinData{core::BuiltinFn::kExp2, CallParamType::kF16, "exp2"},
-                    BuiltinData{core::BuiltinFn::kFaceForward, CallParamType::kF32, "faceforward"},
-                    BuiltinData{core::BuiltinFn::kFaceForward, CallParamType::kF16, "faceforward"},
-                    BuiltinData{core::BuiltinFn::kFloor, CallParamType::kF32, "floor"},
-                    BuiltinData{core::BuiltinFn::kFloor, CallParamType::kF16, "floor"},
-                    BuiltinData{core::BuiltinFn::kFma, CallParamType::kF32, "fma"},
-                    BuiltinData{core::BuiltinFn::kFma, CallParamType::kF16, "fma"},
-                    BuiltinData{core::BuiltinFn::kFract, CallParamType::kF32, "fract"},
-                    BuiltinData{core::BuiltinFn::kFract, CallParamType::kF16, "fract"},
-                    BuiltinData{core::BuiltinFn::kInverseSqrt, CallParamType::kF32, "inversesqrt"},
-                    BuiltinData{core::BuiltinFn::kInverseSqrt, CallParamType::kF16, "inversesqrt"},
-                    BuiltinData{core::BuiltinFn::kLdexp, CallParamType::kF32, "ldexp"},
-                    BuiltinData{core::BuiltinFn::kLdexp, CallParamType::kF16, "ldexp"},
-                    BuiltinData{core::BuiltinFn::kLength, CallParamType::kF32, "length"},
-                    BuiltinData{core::BuiltinFn::kLength, CallParamType::kF16, "length"},
-                    BuiltinData{core::BuiltinFn::kLog, CallParamType::kF32, "log"},
-                    BuiltinData{core::BuiltinFn::kLog, CallParamType::kF16, "log"},
-                    BuiltinData{core::BuiltinFn::kLog2, CallParamType::kF32, "log2"},
-                    BuiltinData{core::BuiltinFn::kLog2, CallParamType::kF16, "log2"},
-                    BuiltinData{core::BuiltinFn::kMax, CallParamType::kF32, "max"},
-                    BuiltinData{core::BuiltinFn::kMax, CallParamType::kF16, "max"},
-                    BuiltinData{core::BuiltinFn::kMin, CallParamType::kF32, "min"},
-                    BuiltinData{core::BuiltinFn::kMin, CallParamType::kF16, "min"},
-                    BuiltinData{core::BuiltinFn::kMix, CallParamType::kF32, "mix"},
-                    BuiltinData{core::BuiltinFn::kMix, CallParamType::kF16, "mix"},
-                    BuiltinData{core::BuiltinFn::kNormalize, CallParamType::kF32, "normalize"},
-                    BuiltinData{core::BuiltinFn::kNormalize, CallParamType::kF16, "normalize"},
-                    BuiltinData{core::BuiltinFn::kPow, CallParamType::kF32, "pow"},
-                    BuiltinData{core::BuiltinFn::kPow, CallParamType::kF16, "pow"},
-                    BuiltinData{core::BuiltinFn::kReflect, CallParamType::kF32, "reflect"},
-                    BuiltinData{core::BuiltinFn::kReflect, CallParamType::kF16, "reflect"},
-                    BuiltinData{core::BuiltinFn::kSign, CallParamType::kF32, "sign"},
-                    BuiltinData{core::BuiltinFn::kSign, CallParamType::kF16, "sign"},
-                    BuiltinData{core::BuiltinFn::kSin, CallParamType::kF32, "sin"},
-                    BuiltinData{core::BuiltinFn::kSin, CallParamType::kF16, "sin"},
-                    BuiltinData{core::BuiltinFn::kSinh, CallParamType::kF32, "sinh"},
-                    BuiltinData{core::BuiltinFn::kSinh, CallParamType::kF16, "sinh"},
-                    BuiltinData{core::BuiltinFn::kSmoothstep, CallParamType::kF32, "smoothstep"},
-                    BuiltinData{core::BuiltinFn::kSmoothstep, CallParamType::kF16, "smoothstep"},
-                    BuiltinData{core::BuiltinFn::kSqrt, CallParamType::kF32, "sqrt"},
-                    BuiltinData{core::BuiltinFn::kSqrt, CallParamType::kF16, "sqrt"},
-                    BuiltinData{core::BuiltinFn::kStep, CallParamType::kF32, "step"},
-                    BuiltinData{core::BuiltinFn::kStep, CallParamType::kF16, "step"},
-                    BuiltinData{core::BuiltinFn::kTan, CallParamType::kF32, "tan"},
-                    BuiltinData{core::BuiltinFn::kTan, CallParamType::kF16, "tan"},
-                    BuiltinData{core::BuiltinFn::kTanh, CallParamType::kF32, "tanh"},
-                    BuiltinData{core::BuiltinFn::kTanh, CallParamType::kF16, "tanh"},
-                    BuiltinData{core::BuiltinFn::kTrunc, CallParamType::kF32, "trunc"},
-                    BuiltinData{core::BuiltinFn::kTrunc, CallParamType::kF16, "trunc"},
+                    BuiltinData{wgsl::BuiltinFn::kAbs, CallParamType::kF32, "abs"},
+                    BuiltinData{wgsl::BuiltinFn::kAbs, CallParamType::kF16, "abs"},
+                    BuiltinData{wgsl::BuiltinFn::kAcos, CallParamType::kF32, "acos"},
+                    BuiltinData{wgsl::BuiltinFn::kAcos, CallParamType::kF16, "acos"},
+                    BuiltinData{wgsl::BuiltinFn::kAsin, CallParamType::kF32, "asin"},
+                    BuiltinData{wgsl::BuiltinFn::kAsin, CallParamType::kF16, "asin"},
+                    BuiltinData{wgsl::BuiltinFn::kAtan, CallParamType::kF32, "atan"},
+                    BuiltinData{wgsl::BuiltinFn::kAtan, CallParamType::kF16, "atan"},
+                    BuiltinData{wgsl::BuiltinFn::kAtan2, CallParamType::kF32, "atan"},
+                    BuiltinData{wgsl::BuiltinFn::kAtan2, CallParamType::kF16, "atan"},
+                    BuiltinData{wgsl::BuiltinFn::kCeil, CallParamType::kF32, "ceil"},
+                    BuiltinData{wgsl::BuiltinFn::kCeil, CallParamType::kF16, "ceil"},
+                    BuiltinData{wgsl::BuiltinFn::kClamp, CallParamType::kF32, "clamp"},
+                    BuiltinData{wgsl::BuiltinFn::kClamp, CallParamType::kF16, "clamp"},
+                    BuiltinData{wgsl::BuiltinFn::kCos, CallParamType::kF32, "cos"},
+                    BuiltinData{wgsl::BuiltinFn::kCos, CallParamType::kF16, "cos"},
+                    BuiltinData{wgsl::BuiltinFn::kCosh, CallParamType::kF32, "cosh"},
+                    BuiltinData{wgsl::BuiltinFn::kCosh, CallParamType::kF16, "cosh"},
+                    BuiltinData{wgsl::BuiltinFn::kCross, CallParamType::kF32, "cross"},
+                    BuiltinData{wgsl::BuiltinFn::kCross, CallParamType::kF16, "cross"},
+                    BuiltinData{wgsl::BuiltinFn::kDistance, CallParamType::kF32, "distance"},
+                    BuiltinData{wgsl::BuiltinFn::kDistance, CallParamType::kF16, "distance"},
+                    BuiltinData{wgsl::BuiltinFn::kExp, CallParamType::kF32, "exp"},
+                    BuiltinData{wgsl::BuiltinFn::kExp, CallParamType::kF16, "exp"},
+                    BuiltinData{wgsl::BuiltinFn::kExp2, CallParamType::kF32, "exp2"},
+                    BuiltinData{wgsl::BuiltinFn::kExp2, CallParamType::kF16, "exp2"},
+                    BuiltinData{wgsl::BuiltinFn::kFaceForward, CallParamType::kF32, "faceforward"},
+                    BuiltinData{wgsl::BuiltinFn::kFaceForward, CallParamType::kF16, "faceforward"},
+                    BuiltinData{wgsl::BuiltinFn::kFloor, CallParamType::kF32, "floor"},
+                    BuiltinData{wgsl::BuiltinFn::kFloor, CallParamType::kF16, "floor"},
+                    BuiltinData{wgsl::BuiltinFn::kFma, CallParamType::kF32, "fma"},
+                    BuiltinData{wgsl::BuiltinFn::kFma, CallParamType::kF16, "fma"},
+                    BuiltinData{wgsl::BuiltinFn::kFract, CallParamType::kF32, "fract"},
+                    BuiltinData{wgsl::BuiltinFn::kFract, CallParamType::kF16, "fract"},
+                    BuiltinData{wgsl::BuiltinFn::kInverseSqrt, CallParamType::kF32, "inversesqrt"},
+                    BuiltinData{wgsl::BuiltinFn::kInverseSqrt, CallParamType::kF16, "inversesqrt"},
+                    BuiltinData{wgsl::BuiltinFn::kLdexp, CallParamType::kF32, "ldexp"},
+                    BuiltinData{wgsl::BuiltinFn::kLdexp, CallParamType::kF16, "ldexp"},
+                    BuiltinData{wgsl::BuiltinFn::kLength, CallParamType::kF32, "length"},
+                    BuiltinData{wgsl::BuiltinFn::kLength, CallParamType::kF16, "length"},
+                    BuiltinData{wgsl::BuiltinFn::kLog, CallParamType::kF32, "log"},
+                    BuiltinData{wgsl::BuiltinFn::kLog, CallParamType::kF16, "log"},
+                    BuiltinData{wgsl::BuiltinFn::kLog2, CallParamType::kF32, "log2"},
+                    BuiltinData{wgsl::BuiltinFn::kLog2, CallParamType::kF16, "log2"},
+                    BuiltinData{wgsl::BuiltinFn::kMax, CallParamType::kF32, "max"},
+                    BuiltinData{wgsl::BuiltinFn::kMax, CallParamType::kF16, "max"},
+                    BuiltinData{wgsl::BuiltinFn::kMin, CallParamType::kF32, "min"},
+                    BuiltinData{wgsl::BuiltinFn::kMin, CallParamType::kF16, "min"},
+                    BuiltinData{wgsl::BuiltinFn::kMix, CallParamType::kF32, "mix"},
+                    BuiltinData{wgsl::BuiltinFn::kMix, CallParamType::kF16, "mix"},
+                    BuiltinData{wgsl::BuiltinFn::kNormalize, CallParamType::kF32, "normalize"},
+                    BuiltinData{wgsl::BuiltinFn::kNormalize, CallParamType::kF16, "normalize"},
+                    BuiltinData{wgsl::BuiltinFn::kPow, CallParamType::kF32, "pow"},
+                    BuiltinData{wgsl::BuiltinFn::kPow, CallParamType::kF16, "pow"},
+                    BuiltinData{wgsl::BuiltinFn::kReflect, CallParamType::kF32, "reflect"},
+                    BuiltinData{wgsl::BuiltinFn::kReflect, CallParamType::kF16, "reflect"},
+                    BuiltinData{wgsl::BuiltinFn::kSign, CallParamType::kF32, "sign"},
+                    BuiltinData{wgsl::BuiltinFn::kSign, CallParamType::kF16, "sign"},
+                    BuiltinData{wgsl::BuiltinFn::kSin, CallParamType::kF32, "sin"},
+                    BuiltinData{wgsl::BuiltinFn::kSin, CallParamType::kF16, "sin"},
+                    BuiltinData{wgsl::BuiltinFn::kSinh, CallParamType::kF32, "sinh"},
+                    BuiltinData{wgsl::BuiltinFn::kSinh, CallParamType::kF16, "sinh"},
+                    BuiltinData{wgsl::BuiltinFn::kSmoothstep, CallParamType::kF32, "smoothstep"},
+                    BuiltinData{wgsl::BuiltinFn::kSmoothstep, CallParamType::kF16, "smoothstep"},
+                    BuiltinData{wgsl::BuiltinFn::kSqrt, CallParamType::kF32, "sqrt"},
+                    BuiltinData{wgsl::BuiltinFn::kSqrt, CallParamType::kF16, "sqrt"},
+                    BuiltinData{wgsl::BuiltinFn::kStep, CallParamType::kF32, "step"},
+                    BuiltinData{wgsl::BuiltinFn::kStep, CallParamType::kF16, "step"},
+                    BuiltinData{wgsl::BuiltinFn::kTan, CallParamType::kF32, "tan"},
+                    BuiltinData{wgsl::BuiltinFn::kTan, CallParamType::kF16, "tan"},
+                    BuiltinData{wgsl::BuiltinFn::kTanh, CallParamType::kF32, "tanh"},
+                    BuiltinData{wgsl::BuiltinFn::kTanh, CallParamType::kF16, "tanh"},
+                    BuiltinData{wgsl::BuiltinFn::kTrunc, CallParamType::kF32, "trunc"},
+                    BuiltinData{wgsl::BuiltinFn::kTrunc, CallParamType::kF16, "trunc"},
                     /* Integer built-in */
-                    BuiltinData{core::BuiltinFn::kAbs, CallParamType::kU32, "abs"},
-                    BuiltinData{core::BuiltinFn::kClamp, CallParamType::kU32, "clamp"},
-                    BuiltinData{core::BuiltinFn::kCountOneBits, CallParamType::kU32, "bitCount"},
-                    BuiltinData{core::BuiltinFn::kMax, CallParamType::kU32, "max"},
-                    BuiltinData{core::BuiltinFn::kMin, CallParamType::kU32, "min"},
-                    BuiltinData{core::BuiltinFn::kReverseBits, CallParamType::kU32,
+                    BuiltinData{wgsl::BuiltinFn::kAbs, CallParamType::kU32, "abs"},
+                    BuiltinData{wgsl::BuiltinFn::kClamp, CallParamType::kU32, "clamp"},
+                    BuiltinData{wgsl::BuiltinFn::kCountOneBits, CallParamType::kU32, "bitCount"},
+                    BuiltinData{wgsl::BuiltinFn::kMax, CallParamType::kU32, "max"},
+                    BuiltinData{wgsl::BuiltinFn::kMin, CallParamType::kU32, "min"},
+                    BuiltinData{wgsl::BuiltinFn::kReverseBits, CallParamType::kU32,
                                 "bitfieldReverse"},
-                    BuiltinData{core::BuiltinFn::kRound, CallParamType::kU32, "round"},
+                    BuiltinData{wgsl::BuiltinFn::kRound, CallParamType::kU32, "round"},
                     /* Matrix built-in */
-                    BuiltinData{core::BuiltinFn::kDeterminant, CallParamType::kF32, "determinant"},
-                    BuiltinData{core::BuiltinFn::kDeterminant, CallParamType::kF16, "determinant"},
-                    BuiltinData{core::BuiltinFn::kTranspose, CallParamType::kF32, "transpose"},
-                    BuiltinData{core::BuiltinFn::kTranspose, CallParamType::kF16, "transpose"},
+                    BuiltinData{wgsl::BuiltinFn::kDeterminant, CallParamType::kF32, "determinant"},
+                    BuiltinData{wgsl::BuiltinFn::kDeterminant, CallParamType::kF16, "determinant"},
+                    BuiltinData{wgsl::BuiltinFn::kTranspose, CallParamType::kF32, "transpose"},
+                    BuiltinData{wgsl::BuiltinFn::kTranspose, CallParamType::kF16, "transpose"},
                     /* Vector built-in */
-                    BuiltinData{core::BuiltinFn::kDot, CallParamType::kF32, "dot"},
-                    BuiltinData{core::BuiltinFn::kDot, CallParamType::kF16, "dot"},
+                    BuiltinData{wgsl::BuiltinFn::kDot, CallParamType::kF32, "dot"},
+                    BuiltinData{wgsl::BuiltinFn::kDot, CallParamType::kF16, "dot"},
                     /* Derivate built-in */
-                    BuiltinData{core::BuiltinFn::kDpdx, CallParamType::kF32, "dFdx"},
-                    BuiltinData{core::BuiltinFn::kDpdxCoarse, CallParamType::kF32, "dFdx"},
-                    BuiltinData{core::BuiltinFn::kDpdxFine, CallParamType::kF32, "dFdx"},
-                    BuiltinData{core::BuiltinFn::kDpdy, CallParamType::kF32, "dFdy"},
-                    BuiltinData{core::BuiltinFn::kDpdyCoarse, CallParamType::kF32, "dFdy"},
-                    BuiltinData{core::BuiltinFn::kDpdyFine, CallParamType::kF32, "dFdy"},
-                    BuiltinData{core::BuiltinFn::kFwidth, CallParamType::kF32, "fwidth"},
-                    BuiltinData{core::BuiltinFn::kFwidthCoarse, CallParamType::kF32, "fwidth"},
-                    BuiltinData{core::BuiltinFn::kFwidthFine, CallParamType::kF32, "fwidth"}));
+                    BuiltinData{wgsl::BuiltinFn::kDpdx, CallParamType::kF32, "dFdx"},
+                    BuiltinData{wgsl::BuiltinFn::kDpdxCoarse, CallParamType::kF32, "dFdx"},
+                    BuiltinData{wgsl::BuiltinFn::kDpdxFine, CallParamType::kF32, "dFdx"},
+                    BuiltinData{wgsl::BuiltinFn::kDpdy, CallParamType::kF32, "dFdy"},
+                    BuiltinData{wgsl::BuiltinFn::kDpdyCoarse, CallParamType::kF32, "dFdy"},
+                    BuiltinData{wgsl::BuiltinFn::kDpdyFine, CallParamType::kF32, "dFdy"},
+                    BuiltinData{wgsl::BuiltinFn::kFwidth, CallParamType::kF32, "fwidth"},
+                    BuiltinData{wgsl::BuiltinFn::kFwidthCoarse, CallParamType::kF32, "fwidth"},
+                    BuiltinData{wgsl::BuiltinFn::kFwidthFine, CallParamType::kF32, "fwidth"}));
 
 TEST_F(GlslASTPrinterTest_Builtin, Builtin_Call) {
     auto* call = Call("dot", "param1", "param2");
diff --git a/src/tint/lang/glsl/writer/ast_raise/BUILD.bazel b/src/tint/lang/glsl/writer/ast_raise/BUILD.bazel
index a71fcf7..e0b9f70 100644
--- a/src/tint/lang/glsl/writer/ast_raise/BUILD.bazel
+++ b/src/tint/lang/glsl/writer/ast_raise/BUILD.bazel
@@ -80,6 +80,7 @@
     "//src/tint/api/options",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
diff --git a/src/tint/lang/glsl/writer/ast_raise/BUILD.cmake b/src/tint/lang/glsl/writer/ast_raise/BUILD.cmake
index eeaa334..0666ae3 100644
--- a/src/tint/lang/glsl/writer/ast_raise/BUILD.cmake
+++ b/src/tint/lang/glsl/writer/ast_raise/BUILD.cmake
@@ -84,6 +84,7 @@
   tint_api_options
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
diff --git a/src/tint/lang/glsl/writer/ast_raise/BUILD.gn b/src/tint/lang/glsl/writer/ast_raise/BUILD.gn
index 938e417..7b7a0e0 100644
--- a/src/tint/lang/glsl/writer/ast_raise/BUILD.gn
+++ b/src/tint/lang/glsl/writer/ast_raise/BUILD.gn
@@ -84,6 +84,7 @@
         "${tint_src_dir}/api/options",
         "${tint_src_dir}/lang/core",
         "${tint_src_dir}/lang/core/constant",
+        "${tint_src_dir}/lang/core/ir",
         "${tint_src_dir}/lang/core/type",
         "${tint_src_dir}/lang/wgsl",
         "${tint_src_dir}/lang/wgsl/ast",
diff --git a/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc b/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc
index 0908a70..c00f0fe3 100644
--- a/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc
+++ b/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc
@@ -145,6 +145,51 @@
         }
     }
 
+    /// Insert a new texture/sampler pair into the combined samplers maps (global or local, as
+    /// appropriate). If local, also add a function parameter to "params".
+    /// @param pair the texture/sampler pair to insert
+    /// @param fn the function scope in which to insert (if local)
+    /// @param params the calling function's parameter list to modify (if local)
+    void InsertPair(sem::VariablePair pair,
+                    const sem::Function* fn,
+                    tint::Vector<const ast::Parameter*, 8>* params) {
+        const sem::Variable* texture_var = pair.first;
+        const sem::Variable* sampler_var = pair.second;
+        std::string name = texture_var->Declaration()->name->symbol.Name();
+        if (sampler_var) {
+            name += "_" + sampler_var->Declaration()->name->symbol.Name();
+        }
+        if (IsGlobal(pair)) {
+            // Both texture and sampler are global; add a new global variable
+            // to represent the combined sampler (if not already created).
+            GetOrCreate(global_combined_texture_samplers_, pair,
+                        [&] { return CreateCombinedGlobal(texture_var, sampler_var, name); });
+        } else {
+            // Either texture or sampler (or both) is a function parameter;
+            // add a new function parameter to represent the combined sampler.
+            ast::Type type = CreateCombinedASTTypeFor(texture_var, sampler_var);
+            auto* var = ctx.dst->Param(ctx.dst->Symbols().New(name), type);
+            params->Push(var);
+            function_combined_texture_samplers_[fn][pair] = var;
+        }
+    }
+
+    /// For a given texture, find any texture/sampler pair with a non-null sampler in the given
+    /// function scope.
+    /// @param texture_var the texture variable of interest
+    /// @param fn the function scope in which to search
+    /// @returns the full pair, if found
+    const sem::VariablePair* FindFullTextureSamplerPair(const sem::Variable* texture_var,
+                                                        const sem::Function* fn) {
+        for (auto pairIter = fn->TextureSamplerPairs().begin();
+             pairIter != fn->TextureSamplerPairs().end(); pairIter++) {
+            if (pairIter->first == texture_var && pairIter->second) {
+                return pairIter;
+            }
+        }
+        return nullptr;
+    }
+
     /// Runs the transform
     /// @returns the new program or SkipTransform if the transform is not required
     ApplyResult Run() {
@@ -177,25 +222,30 @@
                 }
                 Vector<const ast::Parameter*, 8> params;
                 for (auto pair : fn->TextureSamplerPairs()) {
-                    const sem::Variable* texture_var = pair.first;
-                    const sem::Variable* sampler_var = pair.second;
-                    std::string name = texture_var->Declaration()->name->symbol.Name();
-                    if (sampler_var) {
-                        name += "_" + sampler_var->Declaration()->name->symbol.Name();
+                    if (!pair.second) {
+                        continue;
                     }
-                    if (IsGlobal(pair)) {
-                        // Both texture and sampler are global; add a new global variable
-                        // to represent the combined sampler (if not already created).
-                        GetOrCreate(global_combined_texture_samplers_, pair, [&] {
-                            return CreateCombinedGlobal(texture_var, sampler_var, name);
-                        });
+                    InsertPair(pair, fn, &params);
+                }
+                for (auto pair : fn->TextureSamplerPairs()) {
+                    if (pair.second) {
+                        continue;
+                    }
+                    // Look for another pair with a non-null sampler.
+                    // NOTE: this is O(N^2) in the number of pairs, since
+                    // FindFullTextureSamplerPair() also loops over all pairs. If this proves
+                    // problematic, it could be optimized.
+                    if (const sem::VariablePair* fullPair =
+                            FindFullTextureSamplerPair(pair.first, fn)) {
+                        if (IsGlobal(pair)) {
+                            global_combined_texture_samplers_[pair] =
+                                global_combined_texture_samplers_[*fullPair];
+                        } else {
+                            auto* var = function_combined_texture_samplers_[fn][*fullPair];
+                            function_combined_texture_samplers_[fn][pair] = var;
+                        }
                     } else {
-                        // Either texture or sampler (or both) is a function parameter;
-                        // add a new function parameter to represent the combined sampler.
-                        ast::Type type = CreateCombinedASTTypeFor(texture_var, sampler_var);
-                        auto* var = ctx.dst->Param(ctx.dst->Symbols().New(name), type);
-                        params.Push(var);
-                        function_combined_texture_samplers_[fn][pair] = var;
+                        InsertPair(pair, fn, &params);
                     }
                 }
                 // Filter out separate textures and samplers from the original
@@ -270,7 +320,7 @@
                         }
                     }
                     const ast::Expression* value = ctx.dst->Call(ctx.Clone(expr->target), args);
-                    if (builtin->Fn() == core::BuiltinFn::kTextureLoad &&
+                    if (builtin->Fn() == wgsl::BuiltinFn::kTextureLoad &&
                         texture_var->Type()->UnwrapRef()->Is<core::type::DepthTexture>() &&
                         !call->Stmt()->Declaration()->Is<ast::CallStatement>()) {
                         value = ctx.dst->MemberAccessor(value, "x");
@@ -285,6 +335,12 @@
                         if (IsGlobal(pair)) {
                             continue;
                         }
+                        // Texture-only pairs do not require a function parameter if they've been
+                        // replaced by a real pair.
+                        if (!pair.second && FindFullTextureSamplerPair(pair.first, callee)) {
+                            continue;
+                        }
+
                         const sem::Variable* texture_var = pair.first;
                         const sem::Variable* sampler_var = pair.second;
                         if (auto* param = texture_var->As<sem::Parameter>()) {
diff --git a/src/tint/lang/glsl/writer/ast_raise/combine_samplers_test.cc b/src/tint/lang/glsl/writer/ast_raise/combine_samplers_test.cc
index 28f8c74..d408a8b 100644
--- a/src/tint/lang/glsl/writer/ast_raise/combine_samplers_test.cc
+++ b/src/tint/lang/glsl/writer/ast_raise/combine_samplers_test.cc
@@ -794,14 +794,12 @@
 }
 )";
     auto* expect = R"(
-@group(0) @binding(0) @internal(disable_validation__binding_point_collision) var fred : texture_2d<f32>;
-
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var barney : texture_2d<f32>;
 
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
 
 fn main() -> vec4<f32> {
-  return (textureLoad(fred, vec2<i32>(), 0) + textureSample(barney, placeholder_sampler, vec2<f32>()));
+  return (textureLoad(barney, vec2<i32>(), 0) + textureSample(barney, placeholder_sampler, vec2<f32>()));
 }
 )";
 
diff --git a/src/tint/lang/glsl/writer/ast_raise/texture_1d_to_2d.cc b/src/tint/lang/glsl/writer/ast_raise/texture_1d_to_2d.cc
index 3306a9a..1e80e28 100644
--- a/src/tint/lang/glsl/writer/ast_raise/texture_1d_to_2d.cc
+++ b/src/tint/lang/glsl/writer/ast_raise/texture_1d_to_2d.cc
@@ -140,7 +140,7 @@
                 return nullptr;
             }
 
-            if (builtin->Fn() == core::BuiltinFn::kTextureDimensions) {
+            if (builtin->Fn() == wgsl::BuiltinFn::kTextureDimensions) {
                 // If this textureDimensions() call is in a CallStatement, we can leave it
                 // unmodified since the return value will be dropped on the floor anyway.
                 if (call->Stmt()->Declaration()->Is<ast::CallStatement>()) {
diff --git a/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc b/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc
index 61851e4..baef3bc 100644
--- a/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc
+++ b/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc
@@ -51,10 +51,10 @@
             for (auto* builtin : sem_fn->DirectlyCalledBuiltins()) {
                 // GLSL ES  has no native support for the counterpart of
                 // textureNumLevels (textureQueryLevels) and textureNumSamples (textureSamples)
-                if (builtin->Fn() == core::BuiltinFn::kTextureNumLevels) {
+                if (builtin->Fn() == wgsl::BuiltinFn::kTextureNumLevels) {
                     return true;
                 }
-                if (builtin->Fn() == core::BuiltinFn::kTextureNumSamples) {
+                if (builtin->Fn() == wgsl::BuiltinFn::kTextureNumSamples) {
                     return true;
                 }
             }
@@ -111,8 +111,8 @@
                     tint::Switch(
                         call->Target(),
                         [&](const sem::BuiltinFn* builtin) {
-                            if (builtin->Fn() != core::BuiltinFn::kTextureNumLevels &&
-                                builtin->Fn() != core::BuiltinFn::kTextureNumSamples) {
+                            if (builtin->Fn() != wgsl::BuiltinFn::kTextureNumLevels &&
+                                builtin->Fn() != wgsl::BuiltinFn::kTextureNumSamples) {
                                 return;
                             }
                             if (auto* call_stmt =
@@ -462,11 +462,11 @@
     /// @param type of the builtin function
     /// @returns corresponding TextureBuiltinsFromUniformOptions::Field for the builtin
     static TextureBuiltinsFromUniformOptions::Field GetFieldFromBuiltinFunctionType(
-        core::BuiltinFn type) {
+        wgsl::BuiltinFn type) {
         switch (type) {
-            case core::BuiltinFn::kTextureNumLevels:
+            case wgsl::BuiltinFn::kTextureNumLevels:
                 return TextureBuiltinsFromUniformOptions::Field::TextureNumLevels;
-            case core::BuiltinFn::kTextureNumSamples:
+            case wgsl::BuiltinFn::kTextureNumSamples:
                 return TextureBuiltinsFromUniformOptions::Field::TextureNumSamples;
             default:
                 TINT_UNREACHABLE() << "unsupported builtin function type " << type;
diff --git a/src/tint/lang/glsl/writer/common/options.h b/src/tint/lang/glsl/writer/common/options.h
index 1fe8e43..2c9fdcd 100644
--- a/src/tint/lang/glsl/writer/common/options.h
+++ b/src/tint/lang/glsl/writer/common/options.h
@@ -41,6 +41,15 @@
     /// Copy constructor
     Options(const Options&);
 
+    /// Set to `true` to disable software robustness that prevents out-of-bounds accesses.
+    bool disable_robustness = false;
+
+    /// Set to `true` to disable workgroup memory zero initialization
+    bool disable_workgroup_init = false;
+
+    /// The GLSL version to emit
+    Version version;
+
     /// A map of SamplerTexturePair to combined sampler names for the
     /// CombineSamplers transform
     BindingMap binding_map;
@@ -48,12 +57,6 @@
     /// The binding point to use for placeholder samplers.
     BindingPoint placeholder_binding_point;
 
-    /// Set to `true` to disable software robustness that prevents out-of-bounds accesses.
-    bool disable_robustness = false;
-
-    /// Set to `true` to disable workgroup memory zero initialization
-    bool disable_workgroup_init = false;
-
     /// Options used in the bindings remapper
     BindingRemapperOptions binding_remapper_options = {};
 
@@ -65,18 +68,15 @@
     /// textureQueryLevels/textureSamples directly.
     std::optional<TextureBuiltinsFromUniformOptions> texture_builtins_from_uniform = std::nullopt;
 
-    /// The GLSL version to emit
-    Version version;
-
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(binding_map,
-                 placeholder_binding_point,
-                 disable_robustness,
+    TINT_REFLECT(disable_robustness,
                  disable_workgroup_init,
+                 version,
+                 binding_map,
+                 placeholder_binding_point,
                  binding_remapper_options,
                  external_texture_options,
-                 texture_builtins_from_uniform,
-                 version);
+                 texture_builtins_from_uniform);
 };
 
 }  // namespace tint::glsl::writer
diff --git a/src/tint/lang/glsl/writer/writer.cc b/src/tint/lang/glsl/writer/writer.cc
index 5931ad5..ca9aa99 100644
--- a/src/tint/lang/glsl/writer/writer.cc
+++ b/src/tint/lang/glsl/writer/writer.cc
@@ -22,23 +22,23 @@
 
 namespace tint::glsl::writer {
 
-Result<Output, std::string> Generate(const Program& program,
-                                     const Options& options,
-                                     const std::string& entry_point) {
+Result<Output> Generate(const Program& program,
+                        const Options& options,
+                        const std::string& entry_point) {
     if (!program.IsValid()) {
-        return std::string("input program is not valid");
+        return Failure{program.Diagnostics()};
     }
 
     // Sanitize the program.
     auto sanitized_result = Sanitize(program, options, entry_point);
     if (!sanitized_result.program.IsValid()) {
-        return sanitized_result.program.Diagnostics().str();
+        return Failure{sanitized_result.program.Diagnostics()};
     }
 
     // Generate the GLSL code.
     auto impl = std::make_unique<ASTPrinter>(sanitized_result.program, options.version);
     if (!impl->Generate()) {
-        return impl->Diagnostics().str();
+        return Failure{impl->Diagnostics()};
     }
 
     Output output;
diff --git a/src/tint/lang/glsl/writer/writer.h b/src/tint/lang/glsl/writer/writer.h
index 7b6be46..247e676 100644
--- a/src/tint/lang/glsl/writer/writer.h
+++ b/src/tint/lang/glsl/writer/writer.h
@@ -19,6 +19,7 @@
 
 #include "src/tint/lang/glsl/writer/common/options.h"
 #include "src/tint/lang/glsl/writer/output.h"
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward declarations
@@ -29,15 +30,15 @@
 namespace tint::glsl::writer {
 
 /// Generate GLSL for a program, according to a set of configuration options.
-/// The result will contain the GLSL and supplementary information, or an error string.
+/// The result will contain the GLSL and supplementary information, or failure.
 /// information.
 /// @param program the program to translate to GLSL
 /// @param options the configuration options to use when generating GLSL
 /// @param entry_point the entry point to generate GLSL for
-/// @returns the resulting GLSL and supplementary information, or an error string
-Result<Output, std::string> Generate(const Program& program,
-                                     const Options& options,
-                                     const std::string& entry_point);
+/// @returns the resulting GLSL and supplementary information, or failure
+Result<Output> Generate(const Program& program,
+                        const Options& options,
+                        const std::string& entry_point);
 
 }  // namespace tint::glsl::writer
 
diff --git a/src/tint/lang/glsl/writer/writer_bench.cc b/src/tint/lang/glsl/writer/writer_bench.cc
index 1c58f4b..de9d3e6 100644
--- a/src/tint/lang/glsl/writer/writer_bench.cc
+++ b/src/tint/lang/glsl/writer/writer_bench.cc
@@ -40,7 +40,7 @@
         for (auto& ep : entry_points) {
             auto res = Generate(program, {}, ep);
             if (!res) {
-                state.SkipWithError(res.Failure().c_str());
+                state.SkipWithError(res.Failure().reason.str());
             }
         }
     }
diff --git a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
index a22ac90..976266a 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
@@ -217,8 +217,7 @@
     // BindingRemapper must come after MultiplanarExternalTexture
     manager.Add<ast::transform::BindingRemapper>();
     data.Add<ast::transform::BindingRemapper::Remappings>(
-        options.binding_remapper_options.binding_points,
-        options.binding_remapper_options.access_controls,
+        options.binding_remapper_options.binding_points, options.access_controls,
         options.binding_remapper_options.allow_collisions);
 
     {  // Builtin polyfills
@@ -1173,28 +1172,28 @@
     if (builtin->IsTexture()) {
         return EmitTextureCall(out, call, builtin);
     }
-    if (type == core::BuiltinFn::kSelect) {
+    if (type == wgsl::BuiltinFn::kSelect) {
         return EmitSelectCall(out, expr);
     }
-    if (type == core::BuiltinFn::kModf) {
+    if (type == wgsl::BuiltinFn::kModf) {
         return EmitModfCall(out, expr, builtin);
     }
-    if (type == core::BuiltinFn::kFrexp) {
+    if (type == wgsl::BuiltinFn::kFrexp) {
         return EmitFrexpCall(out, expr, builtin);
     }
-    if (type == core::BuiltinFn::kDegrees) {
+    if (type == wgsl::BuiltinFn::kDegrees) {
         return EmitDegreesCall(out, expr, builtin);
     }
-    if (type == core::BuiltinFn::kRadians) {
+    if (type == wgsl::BuiltinFn::kRadians) {
         return EmitRadiansCall(out, expr, builtin);
     }
-    if (type == core::BuiltinFn::kSign) {
+    if (type == wgsl::BuiltinFn::kSign) {
         return EmitSignCall(out, call, builtin);
     }
-    if (type == core::BuiltinFn::kQuantizeToF16) {
+    if (type == wgsl::BuiltinFn::kQuantizeToF16) {
         return EmitQuantizeToF16Call(out, expr, builtin);
     }
-    if (type == core::BuiltinFn::kTrunc) {
+    if (type == wgsl::BuiltinFn::kTrunc) {
         return EmitTruncCall(out, expr, builtin);
     }
     if (builtin->IsDataPacking()) {
@@ -1213,7 +1212,7 @@
         return EmitDP4aCall(out, expr, builtin);
     }
     if (builtin->IsSubgroup()) {
-        if (builtin->Fn() == core::BuiltinFn::kSubgroupBroadcast) {
+        if (builtin->Fn() == wgsl::BuiltinFn::kSubgroupBroadcast) {
             // Fall through the regular path.
         } else {
             return EmitSubgroupCall(out, expr, builtin);
@@ -1228,7 +1227,7 @@
     // Handle single argument builtins that only accept and return uint (not int overload). We need
     // to explicitly cast the return value (we also cast the arg for good measure). See
     // crbug.com/tint/1550
-    if (type == core::BuiltinFn::kCountOneBits || type == core::BuiltinFn::kReverseBits) {
+    if (type == wgsl::BuiltinFn::kCountOneBits || type == wgsl::BuiltinFn::kReverseBits) {
         auto* arg = call->Arguments()[0];
         if (arg->Type()->UnwrapRef()->is_signed_integer_scalar_or_vector()) {
             out << "asint(" << name << "(asuint(";
@@ -2018,7 +2017,7 @@
                 if (i > 0) {
                     pre << ", ";
                 }
-                if (i == 1 && builtin->Fn() == core::BuiltinFn::kAtomicSub) {
+                if (i == 1 && builtin->Fn() == wgsl::BuiltinFn::kAtomicSub) {
                     // Sub uses InterlockedAdd with the operand negated.
                     pre << "-";
                 }
@@ -2037,7 +2036,7 @@
     };
 
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kAtomicLoad: {
+        case wgsl::BuiltinFn::kAtomicLoad: {
             // HLSL does not have an InterlockedLoad, so we emulate it with
             // InterlockedOr using 0 as the OR value
             auto pre = Line();
@@ -2054,7 +2053,7 @@
             out << result;
             return true;
         }
-        case core::BuiltinFn::kAtomicStore: {
+        case wgsl::BuiltinFn::kAtomicStore: {
             // HLSL does not have an InterlockedStore, so we emulate it with
             // InterlockedExchange and discard the returned value
             {  // T result = 0;
@@ -2085,7 +2084,7 @@
             }
             return true;
         }
-        case core::BuiltinFn::kAtomicCompareExchangeWeak: {
+        case wgsl::BuiltinFn::kAtomicCompareExchangeWeak: {
             if (!EmitStructType(&helpers_, builtin->ReturnType()->As<core::type::Struct>())) {
                 return false;
             }
@@ -2134,26 +2133,26 @@
             return true;
         }
 
-        case core::BuiltinFn::kAtomicAdd:
-        case core::BuiltinFn::kAtomicSub:
+        case wgsl::BuiltinFn::kAtomicAdd:
+        case wgsl::BuiltinFn::kAtomicSub:
             return call("InterlockedAdd");
 
-        case core::BuiltinFn::kAtomicMax:
+        case wgsl::BuiltinFn::kAtomicMax:
             return call("InterlockedMax");
 
-        case core::BuiltinFn::kAtomicMin:
+        case wgsl::BuiltinFn::kAtomicMin:
             return call("InterlockedMin");
 
-        case core::BuiltinFn::kAtomicAnd:
+        case wgsl::BuiltinFn::kAtomicAnd:
             return call("InterlockedAnd");
 
-        case core::BuiltinFn::kAtomicOr:
+        case wgsl::BuiltinFn::kAtomicOr:
             return call("InterlockedOr");
 
-        case core::BuiltinFn::kAtomicXor:
+        case wgsl::BuiltinFn::kAtomicXor:
             return call("InterlockedXor");
 
-        case core::BuiltinFn::kAtomicExchange:
+        case wgsl::BuiltinFn::kAtomicExchange:
             return call("InterlockedExchange");
 
         default:
@@ -2339,21 +2338,21 @@
             uint32_t dims = 2;
             bool is_signed = false;
             uint32_t scale = 65535;
-            if (builtin->Fn() == core::BuiltinFn::kPack4X8Snorm ||
-                builtin->Fn() == core::BuiltinFn::kPack4X8Unorm) {
+            if (builtin->Fn() == wgsl::BuiltinFn::kPack4X8Snorm ||
+                builtin->Fn() == wgsl::BuiltinFn::kPack4X8Unorm) {
                 dims = 4;
                 scale = 255;
             }
-            if (builtin->Fn() == core::BuiltinFn::kPack4X8Snorm ||
-                builtin->Fn() == core::BuiltinFn::kPack2X16Snorm) {
+            if (builtin->Fn() == wgsl::BuiltinFn::kPack4X8Snorm ||
+                builtin->Fn() == wgsl::BuiltinFn::kPack2X16Snorm) {
                 is_signed = true;
                 scale = (scale - 1) / 2;
             }
             switch (builtin->Fn()) {
-                case core::BuiltinFn::kPack4X8Snorm:
-                case core::BuiltinFn::kPack4X8Unorm:
-                case core::BuiltinFn::kPack2X16Snorm:
-                case core::BuiltinFn::kPack2X16Unorm: {
+                case wgsl::BuiltinFn::kPack4X8Snorm:
+                case wgsl::BuiltinFn::kPack4X8Unorm:
+                case wgsl::BuiltinFn::kPack2X16Snorm:
+                case wgsl::BuiltinFn::kPack2X16Unorm: {
                     {
                         auto l = Line(b);
                         l << (is_signed ? "" : "u") << "int" << dims
@@ -2379,7 +2378,7 @@
                     }
                     break;
                 }
-                case core::BuiltinFn::kPack2X16Float: {
+                case wgsl::BuiltinFn::kPack2X16Float: {
                     Line(b) << "uint2 i = f32tof16(" << params[0] << ");";
                     Line(b) << "return i.x | (i.y << 16);";
                     break;
@@ -2402,19 +2401,19 @@
             uint32_t dims = 2;
             bool is_signed = false;
             uint32_t scale = 65535;
-            if (builtin->Fn() == core::BuiltinFn::kUnpack4X8Snorm ||
-                builtin->Fn() == core::BuiltinFn::kUnpack4X8Unorm) {
+            if (builtin->Fn() == wgsl::BuiltinFn::kUnpack4X8Snorm ||
+                builtin->Fn() == wgsl::BuiltinFn::kUnpack4X8Unorm) {
                 dims = 4;
                 scale = 255;
             }
-            if (builtin->Fn() == core::BuiltinFn::kUnpack4X8Snorm ||
-                builtin->Fn() == core::BuiltinFn::kUnpack2X16Snorm) {
+            if (builtin->Fn() == wgsl::BuiltinFn::kUnpack4X8Snorm ||
+                builtin->Fn() == wgsl::BuiltinFn::kUnpack2X16Snorm) {
                 is_signed = true;
                 scale = (scale - 1) / 2;
             }
             switch (builtin->Fn()) {
-                case core::BuiltinFn::kUnpack4X8Snorm:
-                case core::BuiltinFn::kUnpack2X16Snorm: {
+                case wgsl::BuiltinFn::kUnpack4X8Snorm:
+                case wgsl::BuiltinFn::kUnpack2X16Snorm: {
                     Line(b) << "int j = int(" << params[0] << ");";
                     {  // Perform sign extension on the converted values.
                         auto l = Line(b);
@@ -2430,8 +2429,8 @@
                             << (is_signed ? "-1.0" : "0.0") << ", 1.0);";
                     break;
                 }
-                case core::BuiltinFn::kUnpack4X8Unorm:
-                case core::BuiltinFn::kUnpack2X16Unorm: {
+                case wgsl::BuiltinFn::kUnpack4X8Unorm:
+                case wgsl::BuiltinFn::kUnpack2X16Unorm: {
                     Line(b) << "uint j = " << params[0] << ";";
                     {
                         auto l = Line(b);
@@ -2447,7 +2446,7 @@
                     Line(b) << "return float" << dims << "(i) / " << scale << ".0;";
                     break;
                 }
-                case core::BuiltinFn::kUnpack2X16Float:
+                case wgsl::BuiltinFn::kUnpack2X16Float:
                     Line(b) << "uint i = " << params[0] << ";";
                     Line(b) << "return f16tof32(uint2(i & 0xffff, i >> 16));";
                     break;
@@ -2469,11 +2468,11 @@
         out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
             std::string functionName;
             switch (builtin->Fn()) {
-                case core::BuiltinFn::kDot4I8Packed:
+                case wgsl::BuiltinFn::kDot4I8Packed:
                     Line(b) << "int accumulator = 0;";
                     functionName = "dot4add_i8packed";
                     break;
-                case core::BuiltinFn::kDot4U8Packed:
+                case wgsl::BuiltinFn::kDot4U8Packed:
                     Line(b) << "uint accumulator = 0u;";
                     functionName = "dot4add_u8packed";
                     break;
@@ -2492,14 +2491,14 @@
 bool ASTPrinter::EmitBarrierCall(StringStream& out, const sem::BuiltinFn* builtin) {
     // TODO(crbug.com/tint/661): Combine sequential barriers to a single
     // instruction.
-    if (builtin->Fn() == core::BuiltinFn::kWorkgroupBarrier) {
+    if (builtin->Fn() == wgsl::BuiltinFn::kWorkgroupBarrier) {
         out << "GroupMemoryBarrierWithGroupSync()";
-    } else if (builtin->Fn() == core::BuiltinFn::kStorageBarrier) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kStorageBarrier) {
         out << "DeviceMemoryBarrierWithGroupSync()";
-    } else if (builtin->Fn() == core::BuiltinFn::kTextureBarrier) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kTextureBarrier) {
         out << "DeviceMemoryBarrierWithGroupSync()";
     } else {
-        TINT_UNREACHABLE() << "unexpected barrier builtin type " << core::str(builtin->Fn());
+        TINT_UNREACHABLE() << "unexpected barrier builtin type " << builtin->Fn();
         return false;
     }
     return true;
@@ -2508,11 +2507,11 @@
 bool ASTPrinter::EmitSubgroupCall(StringStream& out,
                                   [[maybe_unused]] const ast::CallExpression* expr,
                                   const sem::BuiltinFn* builtin) {
-    if (builtin->Fn() == core::BuiltinFn::kSubgroupBallot) {
+    if (builtin->Fn() == wgsl::BuiltinFn::kSubgroupBallot) {
         out << "WaveActiveBallot(true)";
     } else {
         // subgroupBroadcast is already handled in the regular builtin flow.
-        TINT_UNREACHABLE() << "unexpected subgroup builtin type " << core::str(builtin->Fn());
+        TINT_UNREACHABLE() << "unexpected subgroup builtin type " << builtin->Fn();
         return false;
     }
     return true;
@@ -2573,10 +2572,10 @@
     auto* texture_type = TypeOf(texture)->UnwrapRef()->As<core::type::Texture>();
 
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kTextureDimensions:
-        case core::BuiltinFn::kTextureNumLayers:
-        case core::BuiltinFn::kTextureNumLevels:
-        case core::BuiltinFn::kTextureNumSamples: {
+        case wgsl::BuiltinFn::kTextureDimensions:
+        case wgsl::BuiltinFn::kTextureNumLayers:
+        case wgsl::BuiltinFn::kTextureNumLevels:
+        case wgsl::BuiltinFn::kTextureNumSamples: {
             // All of these builtins use the GetDimensions() method on the texture
             bool is_ms = texture_type->IsAnyOf<core::type::MultisampledTexture,
                                                core::type::DepthMultisampledTexture>();
@@ -2584,7 +2583,7 @@
             std::string swizzle;
 
             switch (builtin->Fn()) {
-                case core::BuiltinFn::kTextureDimensions:
+                case wgsl::BuiltinFn::kTextureDimensions:
                     switch (texture_type->dim()) {
                         case core::type::TextureDimension::kNone:
                             TINT_ICE() << "texture dimension is kNone";
@@ -2612,7 +2611,7 @@
                             break;
                     }
                     break;
-                case core::BuiltinFn::kTextureNumLayers:
+                case wgsl::BuiltinFn::kTextureNumLayers:
                     switch (texture_type->dim()) {
                         default:
                             TINT_ICE() << "texture dimension is not arrayed";
@@ -2627,7 +2626,7 @@
                             break;
                     }
                     break;
-                case core::BuiltinFn::kTextureNumLevels:
+                case wgsl::BuiltinFn::kTextureNumLevels:
                     switch (texture_type->dim()) {
                         default:
                             TINT_ICE() << "texture dimension does not support mips";
@@ -2649,7 +2648,7 @@
                             break;
                     }
                     break;
-                case core::BuiltinFn::kTextureNumSamples:
+                case wgsl::BuiltinFn::kTextureNumSamples:
                     switch (texture_type->dim()) {
                         default:
                             TINT_ICE() << "texture dimension does not support multisampling";
@@ -2712,7 +2711,7 @@
                         return false;
                     }
                     pre << ", ";
-                } else if (builtin->Fn() == core::BuiltinFn::kTextureNumLevels) {
+                } else if (builtin->Fn() == wgsl::BuiltinFn::kTextureNumLevels) {
                     pre << "0, ";
                 }
 
@@ -2758,34 +2757,34 @@
     uint32_t hlsl_ret_width = 4u;
 
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kTextureSample:
+        case wgsl::BuiltinFn::kTextureSample:
             out << ".Sample(";
             break;
-        case core::BuiltinFn::kTextureSampleBias:
+        case wgsl::BuiltinFn::kTextureSampleBias:
             out << ".SampleBias(";
             break;
-        case core::BuiltinFn::kTextureSampleLevel:
+        case wgsl::BuiltinFn::kTextureSampleLevel:
             out << ".SampleLevel(";
             break;
-        case core::BuiltinFn::kTextureSampleGrad:
+        case wgsl::BuiltinFn::kTextureSampleGrad:
             out << ".SampleGrad(";
             break;
-        case core::BuiltinFn::kTextureSampleCompare:
+        case wgsl::BuiltinFn::kTextureSampleCompare:
             out << ".SampleCmp(";
             hlsl_ret_width = 1;
             break;
-        case core::BuiltinFn::kTextureSampleCompareLevel:
+        case wgsl::BuiltinFn::kTextureSampleCompareLevel:
             out << ".SampleCmpLevelZero(";
             hlsl_ret_width = 1;
             break;
-        case core::BuiltinFn::kTextureLoad:
+        case wgsl::BuiltinFn::kTextureLoad:
             out << ".Load(";
             // Multisampled textures do not support mip-levels.
             if (!texture_type->Is<core::type::MultisampledTexture>()) {
                 pack_level_in_coords = true;
             }
             break;
-        case core::BuiltinFn::kTextureGather:
+        case wgsl::BuiltinFn::kTextureGather:
             out << ".Gather";
             if (builtin->Parameters()[0]->Usage() == core::ParameterUsage::kComponent) {
                 switch (call->Arguments()[0]->ConstantValue()->ValueAs<AInt>()) {
@@ -2805,10 +2804,10 @@
             }
             out << "(";
             break;
-        case core::BuiltinFn::kTextureGatherCompare:
+        case wgsl::BuiltinFn::kTextureGatherCompare:
             out << ".GatherCmp(";
             break;
-        case core::BuiltinFn::kTextureStore:
+        case wgsl::BuiltinFn::kTextureStore:
             out << "[";
             break;
         default:
@@ -2869,7 +2868,7 @@
         if (!emit_vector_appended_with_level(param_coords)) {
             return false;
         }
-    } else if (builtin->Fn() == core::BuiltinFn::kTextureStore) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kTextureStore) {
         // param_coords is an index expression, not a function arg
         if (!EmitExpression(out, param_coords)) {
             return false;
@@ -2891,7 +2890,7 @@
         }
     }
 
-    if (builtin->Fn() == core::BuiltinFn::kTextureStore) {
+    if (builtin->Fn() == wgsl::BuiltinFn::kTextureStore) {
         out << "] = ";
         if (!EmitExpression(out, arg(Usage::kValue))) {
             return false;
@@ -2925,79 +2924,79 @@
 
 std::string ASTPrinter::generate_builtin_name(const sem::BuiltinFn* builtin) {
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kAbs:
-        case core::BuiltinFn::kAcos:
-        case core::BuiltinFn::kAll:
-        case core::BuiltinFn::kAny:
-        case core::BuiltinFn::kAsin:
-        case core::BuiltinFn::kAtan:
-        case core::BuiltinFn::kAtan2:
-        case core::BuiltinFn::kCeil:
-        case core::BuiltinFn::kClamp:
-        case core::BuiltinFn::kCos:
-        case core::BuiltinFn::kCosh:
-        case core::BuiltinFn::kCross:
-        case core::BuiltinFn::kDeterminant:
-        case core::BuiltinFn::kDistance:
-        case core::BuiltinFn::kDot:
-        case core::BuiltinFn::kExp:
-        case core::BuiltinFn::kExp2:
-        case core::BuiltinFn::kFloor:
-        case core::BuiltinFn::kFrexp:
-        case core::BuiltinFn::kLdexp:
-        case core::BuiltinFn::kLength:
-        case core::BuiltinFn::kLog:
-        case core::BuiltinFn::kLog2:
-        case core::BuiltinFn::kMax:
-        case core::BuiltinFn::kMin:
-        case core::BuiltinFn::kModf:
-        case core::BuiltinFn::kNormalize:
-        case core::BuiltinFn::kPow:
-        case core::BuiltinFn::kReflect:
-        case core::BuiltinFn::kRefract:
-        case core::BuiltinFn::kRound:
-        case core::BuiltinFn::kSaturate:
-        case core::BuiltinFn::kSin:
-        case core::BuiltinFn::kSinh:
-        case core::BuiltinFn::kSqrt:
-        case core::BuiltinFn::kStep:
-        case core::BuiltinFn::kTan:
-        case core::BuiltinFn::kTanh:
-        case core::BuiltinFn::kTranspose:
+        case wgsl::BuiltinFn::kAbs:
+        case wgsl::BuiltinFn::kAcos:
+        case wgsl::BuiltinFn::kAll:
+        case wgsl::BuiltinFn::kAny:
+        case wgsl::BuiltinFn::kAsin:
+        case wgsl::BuiltinFn::kAtan:
+        case wgsl::BuiltinFn::kAtan2:
+        case wgsl::BuiltinFn::kCeil:
+        case wgsl::BuiltinFn::kClamp:
+        case wgsl::BuiltinFn::kCos:
+        case wgsl::BuiltinFn::kCosh:
+        case wgsl::BuiltinFn::kCross:
+        case wgsl::BuiltinFn::kDeterminant:
+        case wgsl::BuiltinFn::kDistance:
+        case wgsl::BuiltinFn::kDot:
+        case wgsl::BuiltinFn::kExp:
+        case wgsl::BuiltinFn::kExp2:
+        case wgsl::BuiltinFn::kFloor:
+        case wgsl::BuiltinFn::kFrexp:
+        case wgsl::BuiltinFn::kLdexp:
+        case wgsl::BuiltinFn::kLength:
+        case wgsl::BuiltinFn::kLog:
+        case wgsl::BuiltinFn::kLog2:
+        case wgsl::BuiltinFn::kMax:
+        case wgsl::BuiltinFn::kMin:
+        case wgsl::BuiltinFn::kModf:
+        case wgsl::BuiltinFn::kNormalize:
+        case wgsl::BuiltinFn::kPow:
+        case wgsl::BuiltinFn::kReflect:
+        case wgsl::BuiltinFn::kRefract:
+        case wgsl::BuiltinFn::kRound:
+        case wgsl::BuiltinFn::kSaturate:
+        case wgsl::BuiltinFn::kSin:
+        case wgsl::BuiltinFn::kSinh:
+        case wgsl::BuiltinFn::kSqrt:
+        case wgsl::BuiltinFn::kStep:
+        case wgsl::BuiltinFn::kTan:
+        case wgsl::BuiltinFn::kTanh:
+        case wgsl::BuiltinFn::kTranspose:
             return builtin->str();
-        case core::BuiltinFn::kCountOneBits:  // uint
+        case wgsl::BuiltinFn::kCountOneBits:  // uint
             return "countbits";
-        case core::BuiltinFn::kDpdx:
+        case wgsl::BuiltinFn::kDpdx:
             return "ddx";
-        case core::BuiltinFn::kDpdxCoarse:
+        case wgsl::BuiltinFn::kDpdxCoarse:
             return "ddx_coarse";
-        case core::BuiltinFn::kDpdxFine:
+        case wgsl::BuiltinFn::kDpdxFine:
             return "ddx_fine";
-        case core::BuiltinFn::kDpdy:
+        case wgsl::BuiltinFn::kDpdy:
             return "ddy";
-        case core::BuiltinFn::kDpdyCoarse:
+        case wgsl::BuiltinFn::kDpdyCoarse:
             return "ddy_coarse";
-        case core::BuiltinFn::kDpdyFine:
+        case wgsl::BuiltinFn::kDpdyFine:
             return "ddy_fine";
-        case core::BuiltinFn::kFaceForward:
+        case wgsl::BuiltinFn::kFaceForward:
             return "faceforward";
-        case core::BuiltinFn::kFract:
+        case wgsl::BuiltinFn::kFract:
             return "frac";
-        case core::BuiltinFn::kFma:
+        case wgsl::BuiltinFn::kFma:
             return "mad";
-        case core::BuiltinFn::kFwidth:
-        case core::BuiltinFn::kFwidthCoarse:
-        case core::BuiltinFn::kFwidthFine:
+        case wgsl::BuiltinFn::kFwidth:
+        case wgsl::BuiltinFn::kFwidthCoarse:
+        case wgsl::BuiltinFn::kFwidthFine:
             return "fwidth";
-        case core::BuiltinFn::kInverseSqrt:
+        case wgsl::BuiltinFn::kInverseSqrt:
             return "rsqrt";
-        case core::BuiltinFn::kMix:
+        case wgsl::BuiltinFn::kMix:
             return "lerp";
-        case core::BuiltinFn::kReverseBits:  // uint
+        case wgsl::BuiltinFn::kReverseBits:  // uint
             return "reversebits";
-        case core::BuiltinFn::kSmoothstep:
+        case wgsl::BuiltinFn::kSmoothstep:
             return "smoothstep";
-        case core::BuiltinFn::kSubgroupBroadcast:
+        case wgsl::BuiltinFn::kSubgroupBroadcast:
             return "WaveReadLaneAt";
         default:
             diagnostics_.add_error(diag::System::Writer,
@@ -4591,7 +4590,7 @@
         TextBuffer b;
         TINT_DEFER(helpers_.Append(b));
 
-        auto fn_name = UniqueIdentifier(std::string("tint_") + core::str(builtin->Fn()));
+        auto fn_name = UniqueIdentifier(std::string("tint_") + wgsl::str(builtin->Fn()));
         std::vector<std::string> parameter_names;
         {
             auto decl = Line(&b);
diff --git a/src/tint/lang/hlsl/writer/ast_printer/ast_printer_test.cc b/src/tint/lang/hlsl/writer/ast_printer/ast_printer_test.cc
index d6cdd1b..f9c0147 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer_test.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/ast_printer_test.cc
@@ -28,7 +28,7 @@
     ASSERT_FALSE(program.IsValid());
     auto result = Generate(program, Options{});
     EXPECT_FALSE(result);
-    EXPECT_EQ(result.Failure(), "input program is not valid");
+    EXPECT_EQ(result.Failure().reason.str(), "error: make the program invalid");
 }
 
 TEST_F(HlslASTPrinterTest, UnsupportedExtension) {
diff --git a/src/tint/lang/hlsl/writer/ast_printer/builtin_test.cc b/src/tint/lang/hlsl/writer/ast_printer/builtin_test.cc
index 9445273..d29ce50 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/builtin_test.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/builtin_test.cc
@@ -36,7 +36,7 @@
 };
 
 struct BuiltinData {
-    core::BuiltinFn builtin;
+    wgsl::BuiltinFn builtin;
     CallParamType type;
     const char* hlsl_name;
 };
@@ -60,84 +60,84 @@
     return out;
 }
 
-const ast::CallExpression* GenerateCall(core::BuiltinFn builtin,
+const ast::CallExpression* GenerateCall(wgsl::BuiltinFn builtin,
                                         CallParamType type,
                                         ProgramBuilder* builder) {
     std::string name;
     StringStream str;
     str << name << builtin;
     switch (builtin) {
-        case core::BuiltinFn::kAcos:
-        case core::BuiltinFn::kAsin:
-        case core::BuiltinFn::kAtan:
-        case core::BuiltinFn::kCeil:
-        case core::BuiltinFn::kCos:
-        case core::BuiltinFn::kCosh:
-        case core::BuiltinFn::kDpdx:
-        case core::BuiltinFn::kDpdxCoarse:
-        case core::BuiltinFn::kDpdxFine:
-        case core::BuiltinFn::kDpdy:
-        case core::BuiltinFn::kDpdyCoarse:
-        case core::BuiltinFn::kDpdyFine:
-        case core::BuiltinFn::kExp:
-        case core::BuiltinFn::kExp2:
-        case core::BuiltinFn::kFloor:
-        case core::BuiltinFn::kFract:
-        case core::BuiltinFn::kFwidth:
-        case core::BuiltinFn::kFwidthCoarse:
-        case core::BuiltinFn::kFwidthFine:
-        case core::BuiltinFn::kInverseSqrt:
-        case core::BuiltinFn::kLength:
-        case core::BuiltinFn::kLog:
-        case core::BuiltinFn::kLog2:
-        case core::BuiltinFn::kNormalize:
-        case core::BuiltinFn::kRound:
-        case core::BuiltinFn::kSin:
-        case core::BuiltinFn::kSinh:
-        case core::BuiltinFn::kSqrt:
-        case core::BuiltinFn::kTan:
-        case core::BuiltinFn::kTanh:
+        case wgsl::BuiltinFn::kAcos:
+        case wgsl::BuiltinFn::kAsin:
+        case wgsl::BuiltinFn::kAtan:
+        case wgsl::BuiltinFn::kCeil:
+        case wgsl::BuiltinFn::kCos:
+        case wgsl::BuiltinFn::kCosh:
+        case wgsl::BuiltinFn::kDpdx:
+        case wgsl::BuiltinFn::kDpdxCoarse:
+        case wgsl::BuiltinFn::kDpdxFine:
+        case wgsl::BuiltinFn::kDpdy:
+        case wgsl::BuiltinFn::kDpdyCoarse:
+        case wgsl::BuiltinFn::kDpdyFine:
+        case wgsl::BuiltinFn::kExp:
+        case wgsl::BuiltinFn::kExp2:
+        case wgsl::BuiltinFn::kFloor:
+        case wgsl::BuiltinFn::kFract:
+        case wgsl::BuiltinFn::kFwidth:
+        case wgsl::BuiltinFn::kFwidthCoarse:
+        case wgsl::BuiltinFn::kFwidthFine:
+        case wgsl::BuiltinFn::kInverseSqrt:
+        case wgsl::BuiltinFn::kLength:
+        case wgsl::BuiltinFn::kLog:
+        case wgsl::BuiltinFn::kLog2:
+        case wgsl::BuiltinFn::kNormalize:
+        case wgsl::BuiltinFn::kRound:
+        case wgsl::BuiltinFn::kSin:
+        case wgsl::BuiltinFn::kSinh:
+        case wgsl::BuiltinFn::kSqrt:
+        case wgsl::BuiltinFn::kTan:
+        case wgsl::BuiltinFn::kTanh:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2");
             } else {
                 return builder->Call(str.str(), "f2");
             }
-        case core::BuiltinFn::kLdexp:
+        case wgsl::BuiltinFn::kLdexp:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "i2");
             } else {
                 return builder->Call(str.str(), "f2", "i2");
             }
-        case core::BuiltinFn::kAtan2:
-        case core::BuiltinFn::kDot:
-        case core::BuiltinFn::kDistance:
-        case core::BuiltinFn::kPow:
-        case core::BuiltinFn::kReflect:
-        case core::BuiltinFn::kStep:
+        case wgsl::BuiltinFn::kAtan2:
+        case wgsl::BuiltinFn::kDot:
+        case wgsl::BuiltinFn::kDistance:
+        case wgsl::BuiltinFn::kPow:
+        case wgsl::BuiltinFn::kReflect:
+        case wgsl::BuiltinFn::kStep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2");
             }
-        case core::BuiltinFn::kCross:
+        case wgsl::BuiltinFn::kCross:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h3", "h3");
             } else {
                 return builder->Call(str.str(), "f3", "f3");
             }
-        case core::BuiltinFn::kFma:
-        case core::BuiltinFn::kMix:
-        case core::BuiltinFn::kFaceForward:
-        case core::BuiltinFn::kSmoothstep:
+        case wgsl::BuiltinFn::kFma:
+        case wgsl::BuiltinFn::kMix:
+        case wgsl::BuiltinFn::kFaceForward:
+        case wgsl::BuiltinFn::kSmoothstep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             }
-        case core::BuiltinFn::kAll:
-        case core::BuiltinFn::kAny:
+        case wgsl::BuiltinFn::kAll:
+        case wgsl::BuiltinFn::kAny:
             return builder->Call(str.str(), "b2");
-        case core::BuiltinFn::kAbs:
+        case wgsl::BuiltinFn::kAbs:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2");
             } else if (type == CallParamType::kF16) {
@@ -145,11 +145,11 @@
             } else {
                 return builder->Call(str.str(), "u2");
             }
-        case core::BuiltinFn::kCountOneBits:
-        case core::BuiltinFn::kReverseBits:
+        case wgsl::BuiltinFn::kCountOneBits:
+        case wgsl::BuiltinFn::kReverseBits:
             return builder->Call(str.str(), "u2");
-        case core::BuiltinFn::kMax:
-        case core::BuiltinFn::kMin:
+        case wgsl::BuiltinFn::kMax:
+        case wgsl::BuiltinFn::kMin:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -157,7 +157,7 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2");
             }
-        case core::BuiltinFn::kClamp:
+        case wgsl::BuiltinFn::kClamp:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -165,19 +165,19 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2", "u2");
             }
-        case core::BuiltinFn::kSelect:
+        case wgsl::BuiltinFn::kSelect:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "b2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "b2");
             }
-        case core::BuiltinFn::kDeterminant:
+        case wgsl::BuiltinFn::kDeterminant:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm2x2");
             } else {
                 return builder->Call(str.str(), "m2x2");
             }
-        case core::BuiltinFn::kTranspose:
+        case wgsl::BuiltinFn::kTranspose:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm3x2");
             } else {
@@ -233,105 +233,105 @@
     HlslASTPrinterTest_Builtin,
     HlslBuiltinTest,
     testing::Values(/* Logical built-in */
-                    BuiltinData{core::BuiltinFn::kAll, CallParamType::kBool, "all"},
-                    BuiltinData{core::BuiltinFn::kAny, CallParamType::kBool, "any"},
+                    BuiltinData{wgsl::BuiltinFn::kAll, CallParamType::kBool, "all"},
+                    BuiltinData{wgsl::BuiltinFn::kAny, CallParamType::kBool, "any"},
                     /* Float built-in */
-                    BuiltinData{core::BuiltinFn::kAbs, CallParamType::kF32, "abs"},
-                    BuiltinData{core::BuiltinFn::kAbs, CallParamType::kF16, "abs"},
-                    BuiltinData{core::BuiltinFn::kAcos, CallParamType::kF32, "acos"},
-                    BuiltinData{core::BuiltinFn::kAcos, CallParamType::kF16, "acos"},
-                    BuiltinData{core::BuiltinFn::kAsin, CallParamType::kF32, "asin"},
-                    BuiltinData{core::BuiltinFn::kAsin, CallParamType::kF16, "asin"},
-                    BuiltinData{core::BuiltinFn::kAtan, CallParamType::kF32, "atan"},
-                    BuiltinData{core::BuiltinFn::kAtan, CallParamType::kF16, "atan"},
-                    BuiltinData{core::BuiltinFn::kAtan2, CallParamType::kF32, "atan2"},
-                    BuiltinData{core::BuiltinFn::kAtan2, CallParamType::kF16, "atan2"},
-                    BuiltinData{core::BuiltinFn::kCeil, CallParamType::kF32, "ceil"},
-                    BuiltinData{core::BuiltinFn::kCeil, CallParamType::kF16, "ceil"},
-                    BuiltinData{core::BuiltinFn::kClamp, CallParamType::kF32, "clamp"},
-                    BuiltinData{core::BuiltinFn::kClamp, CallParamType::kF16, "clamp"},
-                    BuiltinData{core::BuiltinFn::kCos, CallParamType::kF32, "cos"},
-                    BuiltinData{core::BuiltinFn::kCos, CallParamType::kF16, "cos"},
-                    BuiltinData{core::BuiltinFn::kCosh, CallParamType::kF32, "cosh"},
-                    BuiltinData{core::BuiltinFn::kCosh, CallParamType::kF16, "cosh"},
-                    BuiltinData{core::BuiltinFn::kCross, CallParamType::kF32, "cross"},
-                    BuiltinData{core::BuiltinFn::kCross, CallParamType::kF16, "cross"},
-                    BuiltinData{core::BuiltinFn::kDistance, CallParamType::kF32, "distance"},
-                    BuiltinData{core::BuiltinFn::kDistance, CallParamType::kF16, "distance"},
-                    BuiltinData{core::BuiltinFn::kExp, CallParamType::kF32, "exp"},
-                    BuiltinData{core::BuiltinFn::kExp, CallParamType::kF16, "exp"},
-                    BuiltinData{core::BuiltinFn::kExp2, CallParamType::kF32, "exp2"},
-                    BuiltinData{core::BuiltinFn::kExp2, CallParamType::kF16, "exp2"},
-                    BuiltinData{core::BuiltinFn::kFaceForward, CallParamType::kF32, "faceforward"},
-                    BuiltinData{core::BuiltinFn::kFaceForward, CallParamType::kF16, "faceforward"},
-                    BuiltinData{core::BuiltinFn::kFloor, CallParamType::kF32, "floor"},
-                    BuiltinData{core::BuiltinFn::kFloor, CallParamType::kF16, "floor"},
-                    BuiltinData{core::BuiltinFn::kFma, CallParamType::kF32, "mad"},
-                    BuiltinData{core::BuiltinFn::kFma, CallParamType::kF16, "mad"},
-                    BuiltinData{core::BuiltinFn::kFract, CallParamType::kF32, "frac"},
-                    BuiltinData{core::BuiltinFn::kFract, CallParamType::kF16, "frac"},
-                    BuiltinData{core::BuiltinFn::kInverseSqrt, CallParamType::kF32, "rsqrt"},
-                    BuiltinData{core::BuiltinFn::kInverseSqrt, CallParamType::kF16, "rsqrt"},
-                    BuiltinData{core::BuiltinFn::kLdexp, CallParamType::kF32, "ldexp"},
-                    BuiltinData{core::BuiltinFn::kLdexp, CallParamType::kF16, "ldexp"},
-                    BuiltinData{core::BuiltinFn::kLength, CallParamType::kF32, "length"},
-                    BuiltinData{core::BuiltinFn::kLength, CallParamType::kF16, "length"},
-                    BuiltinData{core::BuiltinFn::kLog, CallParamType::kF32, "log"},
-                    BuiltinData{core::BuiltinFn::kLog, CallParamType::kF16, "log"},
-                    BuiltinData{core::BuiltinFn::kLog2, CallParamType::kF32, "log2"},
-                    BuiltinData{core::BuiltinFn::kLog2, CallParamType::kF16, "log2"},
-                    BuiltinData{core::BuiltinFn::kMax, CallParamType::kF32, "max"},
-                    BuiltinData{core::BuiltinFn::kMax, CallParamType::kF16, "max"},
-                    BuiltinData{core::BuiltinFn::kMin, CallParamType::kF32, "min"},
-                    BuiltinData{core::BuiltinFn::kMin, CallParamType::kF16, "min"},
-                    BuiltinData{core::BuiltinFn::kMix, CallParamType::kF32, "lerp"},
-                    BuiltinData{core::BuiltinFn::kMix, CallParamType::kF16, "lerp"},
-                    BuiltinData{core::BuiltinFn::kNormalize, CallParamType::kF32, "normalize"},
-                    BuiltinData{core::BuiltinFn::kNormalize, CallParamType::kF16, "normalize"},
-                    BuiltinData{core::BuiltinFn::kPow, CallParamType::kF32, "pow"},
-                    BuiltinData{core::BuiltinFn::kPow, CallParamType::kF16, "pow"},
-                    BuiltinData{core::BuiltinFn::kReflect, CallParamType::kF32, "reflect"},
-                    BuiltinData{core::BuiltinFn::kReflect, CallParamType::kF16, "reflect"},
-                    BuiltinData{core::BuiltinFn::kSin, CallParamType::kF32, "sin"},
-                    BuiltinData{core::BuiltinFn::kSin, CallParamType::kF16, "sin"},
-                    BuiltinData{core::BuiltinFn::kSinh, CallParamType::kF32, "sinh"},
-                    BuiltinData{core::BuiltinFn::kSinh, CallParamType::kF16, "sinh"},
-                    BuiltinData{core::BuiltinFn::kSmoothstep, CallParamType::kF32, "smoothstep"},
-                    BuiltinData{core::BuiltinFn::kSmoothstep, CallParamType::kF16, "smoothstep"},
-                    BuiltinData{core::BuiltinFn::kSqrt, CallParamType::kF32, "sqrt"},
-                    BuiltinData{core::BuiltinFn::kSqrt, CallParamType::kF16, "sqrt"},
-                    BuiltinData{core::BuiltinFn::kStep, CallParamType::kF32, "step"},
-                    BuiltinData{core::BuiltinFn::kStep, CallParamType::kF16, "step"},
-                    BuiltinData{core::BuiltinFn::kTan, CallParamType::kF32, "tan"},
-                    BuiltinData{core::BuiltinFn::kTan, CallParamType::kF16, "tan"},
-                    BuiltinData{core::BuiltinFn::kTanh, CallParamType::kF32, "tanh"},
-                    BuiltinData{core::BuiltinFn::kTanh, CallParamType::kF16, "tanh"},
+                    BuiltinData{wgsl::BuiltinFn::kAbs, CallParamType::kF32, "abs"},
+                    BuiltinData{wgsl::BuiltinFn::kAbs, CallParamType::kF16, "abs"},
+                    BuiltinData{wgsl::BuiltinFn::kAcos, CallParamType::kF32, "acos"},
+                    BuiltinData{wgsl::BuiltinFn::kAcos, CallParamType::kF16, "acos"},
+                    BuiltinData{wgsl::BuiltinFn::kAsin, CallParamType::kF32, "asin"},
+                    BuiltinData{wgsl::BuiltinFn::kAsin, CallParamType::kF16, "asin"},
+                    BuiltinData{wgsl::BuiltinFn::kAtan, CallParamType::kF32, "atan"},
+                    BuiltinData{wgsl::BuiltinFn::kAtan, CallParamType::kF16, "atan"},
+                    BuiltinData{wgsl::BuiltinFn::kAtan2, CallParamType::kF32, "atan2"},
+                    BuiltinData{wgsl::BuiltinFn::kAtan2, CallParamType::kF16, "atan2"},
+                    BuiltinData{wgsl::BuiltinFn::kCeil, CallParamType::kF32, "ceil"},
+                    BuiltinData{wgsl::BuiltinFn::kCeil, CallParamType::kF16, "ceil"},
+                    BuiltinData{wgsl::BuiltinFn::kClamp, CallParamType::kF32, "clamp"},
+                    BuiltinData{wgsl::BuiltinFn::kClamp, CallParamType::kF16, "clamp"},
+                    BuiltinData{wgsl::BuiltinFn::kCos, CallParamType::kF32, "cos"},
+                    BuiltinData{wgsl::BuiltinFn::kCos, CallParamType::kF16, "cos"},
+                    BuiltinData{wgsl::BuiltinFn::kCosh, CallParamType::kF32, "cosh"},
+                    BuiltinData{wgsl::BuiltinFn::kCosh, CallParamType::kF16, "cosh"},
+                    BuiltinData{wgsl::BuiltinFn::kCross, CallParamType::kF32, "cross"},
+                    BuiltinData{wgsl::BuiltinFn::kCross, CallParamType::kF16, "cross"},
+                    BuiltinData{wgsl::BuiltinFn::kDistance, CallParamType::kF32, "distance"},
+                    BuiltinData{wgsl::BuiltinFn::kDistance, CallParamType::kF16, "distance"},
+                    BuiltinData{wgsl::BuiltinFn::kExp, CallParamType::kF32, "exp"},
+                    BuiltinData{wgsl::BuiltinFn::kExp, CallParamType::kF16, "exp"},
+                    BuiltinData{wgsl::BuiltinFn::kExp2, CallParamType::kF32, "exp2"},
+                    BuiltinData{wgsl::BuiltinFn::kExp2, CallParamType::kF16, "exp2"},
+                    BuiltinData{wgsl::BuiltinFn::kFaceForward, CallParamType::kF32, "faceforward"},
+                    BuiltinData{wgsl::BuiltinFn::kFaceForward, CallParamType::kF16, "faceforward"},
+                    BuiltinData{wgsl::BuiltinFn::kFloor, CallParamType::kF32, "floor"},
+                    BuiltinData{wgsl::BuiltinFn::kFloor, CallParamType::kF16, "floor"},
+                    BuiltinData{wgsl::BuiltinFn::kFma, CallParamType::kF32, "mad"},
+                    BuiltinData{wgsl::BuiltinFn::kFma, CallParamType::kF16, "mad"},
+                    BuiltinData{wgsl::BuiltinFn::kFract, CallParamType::kF32, "frac"},
+                    BuiltinData{wgsl::BuiltinFn::kFract, CallParamType::kF16, "frac"},
+                    BuiltinData{wgsl::BuiltinFn::kInverseSqrt, CallParamType::kF32, "rsqrt"},
+                    BuiltinData{wgsl::BuiltinFn::kInverseSqrt, CallParamType::kF16, "rsqrt"},
+                    BuiltinData{wgsl::BuiltinFn::kLdexp, CallParamType::kF32, "ldexp"},
+                    BuiltinData{wgsl::BuiltinFn::kLdexp, CallParamType::kF16, "ldexp"},
+                    BuiltinData{wgsl::BuiltinFn::kLength, CallParamType::kF32, "length"},
+                    BuiltinData{wgsl::BuiltinFn::kLength, CallParamType::kF16, "length"},
+                    BuiltinData{wgsl::BuiltinFn::kLog, CallParamType::kF32, "log"},
+                    BuiltinData{wgsl::BuiltinFn::kLog, CallParamType::kF16, "log"},
+                    BuiltinData{wgsl::BuiltinFn::kLog2, CallParamType::kF32, "log2"},
+                    BuiltinData{wgsl::BuiltinFn::kLog2, CallParamType::kF16, "log2"},
+                    BuiltinData{wgsl::BuiltinFn::kMax, CallParamType::kF32, "max"},
+                    BuiltinData{wgsl::BuiltinFn::kMax, CallParamType::kF16, "max"},
+                    BuiltinData{wgsl::BuiltinFn::kMin, CallParamType::kF32, "min"},
+                    BuiltinData{wgsl::BuiltinFn::kMin, CallParamType::kF16, "min"},
+                    BuiltinData{wgsl::BuiltinFn::kMix, CallParamType::kF32, "lerp"},
+                    BuiltinData{wgsl::BuiltinFn::kMix, CallParamType::kF16, "lerp"},
+                    BuiltinData{wgsl::BuiltinFn::kNormalize, CallParamType::kF32, "normalize"},
+                    BuiltinData{wgsl::BuiltinFn::kNormalize, CallParamType::kF16, "normalize"},
+                    BuiltinData{wgsl::BuiltinFn::kPow, CallParamType::kF32, "pow"},
+                    BuiltinData{wgsl::BuiltinFn::kPow, CallParamType::kF16, "pow"},
+                    BuiltinData{wgsl::BuiltinFn::kReflect, CallParamType::kF32, "reflect"},
+                    BuiltinData{wgsl::BuiltinFn::kReflect, CallParamType::kF16, "reflect"},
+                    BuiltinData{wgsl::BuiltinFn::kSin, CallParamType::kF32, "sin"},
+                    BuiltinData{wgsl::BuiltinFn::kSin, CallParamType::kF16, "sin"},
+                    BuiltinData{wgsl::BuiltinFn::kSinh, CallParamType::kF32, "sinh"},
+                    BuiltinData{wgsl::BuiltinFn::kSinh, CallParamType::kF16, "sinh"},
+                    BuiltinData{wgsl::BuiltinFn::kSmoothstep, CallParamType::kF32, "smoothstep"},
+                    BuiltinData{wgsl::BuiltinFn::kSmoothstep, CallParamType::kF16, "smoothstep"},
+                    BuiltinData{wgsl::BuiltinFn::kSqrt, CallParamType::kF32, "sqrt"},
+                    BuiltinData{wgsl::BuiltinFn::kSqrt, CallParamType::kF16, "sqrt"},
+                    BuiltinData{wgsl::BuiltinFn::kStep, CallParamType::kF32, "step"},
+                    BuiltinData{wgsl::BuiltinFn::kStep, CallParamType::kF16, "step"},
+                    BuiltinData{wgsl::BuiltinFn::kTan, CallParamType::kF32, "tan"},
+                    BuiltinData{wgsl::BuiltinFn::kTan, CallParamType::kF16, "tan"},
+                    BuiltinData{wgsl::BuiltinFn::kTanh, CallParamType::kF32, "tanh"},
+                    BuiltinData{wgsl::BuiltinFn::kTanh, CallParamType::kF16, "tanh"},
                     /* Integer built-in */
-                    BuiltinData{core::BuiltinFn::kAbs, CallParamType::kU32, "abs"},
-                    BuiltinData{core::BuiltinFn::kClamp, CallParamType::kU32, "clamp"},
-                    BuiltinData{core::BuiltinFn::kCountOneBits, CallParamType::kU32, "countbits"},
-                    BuiltinData{core::BuiltinFn::kMax, CallParamType::kU32, "max"},
-                    BuiltinData{core::BuiltinFn::kMin, CallParamType::kU32, "min"},
-                    BuiltinData{core::BuiltinFn::kReverseBits, CallParamType::kU32, "reversebits"},
-                    BuiltinData{core::BuiltinFn::kRound, CallParamType::kU32, "round"},
+                    BuiltinData{wgsl::BuiltinFn::kAbs, CallParamType::kU32, "abs"},
+                    BuiltinData{wgsl::BuiltinFn::kClamp, CallParamType::kU32, "clamp"},
+                    BuiltinData{wgsl::BuiltinFn::kCountOneBits, CallParamType::kU32, "countbits"},
+                    BuiltinData{wgsl::BuiltinFn::kMax, CallParamType::kU32, "max"},
+                    BuiltinData{wgsl::BuiltinFn::kMin, CallParamType::kU32, "min"},
+                    BuiltinData{wgsl::BuiltinFn::kReverseBits, CallParamType::kU32, "reversebits"},
+                    BuiltinData{wgsl::BuiltinFn::kRound, CallParamType::kU32, "round"},
                     /* Matrix built-in */
-                    BuiltinData{core::BuiltinFn::kDeterminant, CallParamType::kF32, "determinant"},
-                    BuiltinData{core::BuiltinFn::kDeterminant, CallParamType::kF16, "determinant"},
-                    BuiltinData{core::BuiltinFn::kTranspose, CallParamType::kF32, "transpose"},
-                    BuiltinData{core::BuiltinFn::kTranspose, CallParamType::kF16, "transpose"},
+                    BuiltinData{wgsl::BuiltinFn::kDeterminant, CallParamType::kF32, "determinant"},
+                    BuiltinData{wgsl::BuiltinFn::kDeterminant, CallParamType::kF16, "determinant"},
+                    BuiltinData{wgsl::BuiltinFn::kTranspose, CallParamType::kF32, "transpose"},
+                    BuiltinData{wgsl::BuiltinFn::kTranspose, CallParamType::kF16, "transpose"},
                     /* Vector built-in */
-                    BuiltinData{core::BuiltinFn::kDot, CallParamType::kF32, "dot"},
-                    BuiltinData{core::BuiltinFn::kDot, CallParamType::kF16, "dot"},
+                    BuiltinData{wgsl::BuiltinFn::kDot, CallParamType::kF32, "dot"},
+                    BuiltinData{wgsl::BuiltinFn::kDot, CallParamType::kF16, "dot"},
                     /* Derivate built-in */
-                    BuiltinData{core::BuiltinFn::kDpdx, CallParamType::kF32, "ddx"},
-                    BuiltinData{core::BuiltinFn::kDpdxCoarse, CallParamType::kF32, "ddx_coarse"},
-                    BuiltinData{core::BuiltinFn::kDpdxFine, CallParamType::kF32, "ddx_fine"},
-                    BuiltinData{core::BuiltinFn::kDpdy, CallParamType::kF32, "ddy"},
-                    BuiltinData{core::BuiltinFn::kDpdyCoarse, CallParamType::kF32, "ddy_coarse"},
-                    BuiltinData{core::BuiltinFn::kDpdyFine, CallParamType::kF32, "ddy_fine"},
-                    BuiltinData{core::BuiltinFn::kFwidth, CallParamType::kF32, "fwidth"},
-                    BuiltinData{core::BuiltinFn::kFwidthCoarse, CallParamType::kF32, "fwidth"},
-                    BuiltinData{core::BuiltinFn::kFwidthFine, CallParamType::kF32, "fwidth"}));
+                    BuiltinData{wgsl::BuiltinFn::kDpdx, CallParamType::kF32, "ddx"},
+                    BuiltinData{wgsl::BuiltinFn::kDpdxCoarse, CallParamType::kF32, "ddx_coarse"},
+                    BuiltinData{wgsl::BuiltinFn::kDpdxFine, CallParamType::kF32, "ddx_fine"},
+                    BuiltinData{wgsl::BuiltinFn::kDpdy, CallParamType::kF32, "ddy"},
+                    BuiltinData{wgsl::BuiltinFn::kDpdyCoarse, CallParamType::kF32, "ddy_coarse"},
+                    BuiltinData{wgsl::BuiltinFn::kDpdyFine, CallParamType::kF32, "ddy_fine"},
+                    BuiltinData{wgsl::BuiltinFn::kFwidth, CallParamType::kF32, "fwidth"},
+                    BuiltinData{wgsl::BuiltinFn::kFwidthCoarse, CallParamType::kF32, "fwidth"},
+                    BuiltinData{wgsl::BuiltinFn::kFwidthFine, CallParamType::kF32, "fwidth"}));
 
 TEST_F(HlslASTPrinterTest_Builtin, Builtin_Call) {
     auto* call = Call("dot", "param1", "param2");
diff --git a/src/tint/lang/hlsl/writer/ast_raise/BUILD.bazel b/src/tint/lang/hlsl/writer/ast_raise/BUILD.bazel
index f6333e6..fd49ad8 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/ast_raise/BUILD.bazel
@@ -84,6 +84,7 @@
     "//src/tint/api/common",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
diff --git a/src/tint/lang/hlsl/writer/ast_raise/BUILD.cmake b/src/tint/lang/hlsl/writer/ast_raise/BUILD.cmake
index d7b7107..97916d3 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/ast_raise/BUILD.cmake
@@ -88,6 +88,7 @@
   tint_api_common
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
diff --git a/src/tint/lang/hlsl/writer/ast_raise/BUILD.gn b/src/tint/lang/hlsl/writer/ast_raise/BUILD.gn
index b7e2eef..24b8ca4 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/ast_raise/BUILD.gn
@@ -88,6 +88,7 @@
         "${tint_src_dir}/api/common",
         "${tint_src_dir}/lang/core",
         "${tint_src_dir}/lang/core/constant",
+        "${tint_src_dir}/lang/core/ir",
         "${tint_src_dir}/lang/core/type",
         "${tint_src_dir}/lang/wgsl",
         "${tint_src_dir}/lang/wgsl/ast",
diff --git a/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.cc b/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.cc
index 5aa810e..57c338e 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.cc
@@ -47,7 +47,7 @@
     for (auto* fn : program.AST().Functions()) {
         if (auto* sem_fn = program.Sem().Get(fn)) {
             for (auto* builtin : sem_fn->DirectlyCalledBuiltins()) {
-                if (builtin->Fn() == core::BuiltinFn::kArrayLength) {
+                if (builtin->Fn() == wgsl::BuiltinFn::kArrayLength) {
                     return true;
                 }
             }
@@ -130,7 +130,7 @@
         if (auto* call_expr = node->As<ast::CallExpression>()) {
             auto* call = sem.Get(call_expr)->UnwrapMaterialize()->As<sem::Call>();
             if (auto* builtin = call->Target()->As<sem::BuiltinFn>()) {
-                if (builtin->Fn() == core::BuiltinFn::kArrayLength) {
+                if (builtin->Fn() == wgsl::BuiltinFn::kArrayLength) {
                     // We're dealing with an arrayLength() call
 
                     if (auto* call_stmt = call->Stmt()->Declaration()->As<ast::CallStatement>()) {
diff --git a/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.cc b/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.cc
index ab0bfca..18c9936 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.cc
@@ -129,7 +129,7 @@
 /// AtomicKey is the unordered map key to an atomic intrinsic.
 struct AtomicKey {
     core::type::Type const* el_ty = nullptr;  // element type
-    core::BuiltinFn const op;                 // atomic op
+    wgsl::BuiltinFn const op;                 // atomic op
     Symbol const buffer;                      // buffer name
     bool operator==(const AtomicKey& rhs) const {
         return el_ty == rhs.el_ty && op == rhs.op && buffer == rhs.buffer;
@@ -254,42 +254,42 @@
 /// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied to a stub function for
 /// the atomic op and the type @p ty.
 DecomposeMemoryAccess::Intrinsic* IntrinsicAtomicFor(ast::Builder* builder,
-                                                     core::BuiltinFn ity,
+                                                     wgsl::BuiltinFn ity,
                                                      const core::type::Type* ty,
                                                      const Symbol& buffer) {
     auto op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicLoad;
     switch (ity) {
-        case core::BuiltinFn::kAtomicLoad:
+        case wgsl::BuiltinFn::kAtomicLoad:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicLoad;
             break;
-        case core::BuiltinFn::kAtomicStore:
+        case wgsl::BuiltinFn::kAtomicStore:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicStore;
             break;
-        case core::BuiltinFn::kAtomicAdd:
+        case wgsl::BuiltinFn::kAtomicAdd:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicAdd;
             break;
-        case core::BuiltinFn::kAtomicSub:
+        case wgsl::BuiltinFn::kAtomicSub:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicSub;
             break;
-        case core::BuiltinFn::kAtomicMax:
+        case wgsl::BuiltinFn::kAtomicMax:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicMax;
             break;
-        case core::BuiltinFn::kAtomicMin:
+        case wgsl::BuiltinFn::kAtomicMin:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicMin;
             break;
-        case core::BuiltinFn::kAtomicAnd:
+        case wgsl::BuiltinFn::kAtomicAnd:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicAnd;
             break;
-        case core::BuiltinFn::kAtomicOr:
+        case wgsl::BuiltinFn::kAtomicOr:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicOr;
             break;
-        case core::BuiltinFn::kAtomicXor:
+        case wgsl::BuiltinFn::kAtomicXor:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicXor;
             break;
-        case core::BuiltinFn::kAtomicExchange:
+        case wgsl::BuiltinFn::kAtomicExchange:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicExchange;
             break;
-        case core::BuiltinFn::kAtomicCompareExchangeWeak:
+        case wgsl::BuiltinFn::kAtomicCompareExchangeWeak:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicCompareExchangeWeak;
             break;
         default:
@@ -922,7 +922,7 @@
         if (auto* call_expr = node->As<ast::CallExpression>()) {
             auto* call = sem.Get(call_expr)->UnwrapMaterialize()->As<sem::Call>();
             if (auto* builtin = call->Target()->As<sem::BuiltinFn>()) {
-                if (builtin->Fn() == core::BuiltinFn::kArrayLength) {
+                if (builtin->Fn() == wgsl::BuiltinFn::kArrayLength) {
                     // arrayLength(X)
                     // Don't convert X into a load, this builtin actually requires the real pointer.
                     state.TakeAccess(call_expr->args[0]);
diff --git a/src/tint/lang/hlsl/writer/common/options.h b/src/tint/lang/hlsl/writer/common/options.h
index e35e8bd..bca3db6 100644
--- a/src/tint/lang/hlsl/writer/common/options.h
+++ b/src/tint/lang/hlsl/writer/common/options.h
@@ -17,6 +17,7 @@
 
 #include <bitset>
 #include <optional>
+#include <unordered_map>
 #include <vector>
 
 #include "src/tint/api/common/binding_point.h"
@@ -42,46 +43,50 @@
     /// Set to `true` to disable software robustness that prevents out-of-bounds accesses.
     bool disable_robustness = false;
 
-    /// The binding point to use for information passed via root constants.
-    std::optional<BindingPoint> root_constant_binding_point;
-
     /// Set to `true` to disable workgroup memory zero initialization
     bool disable_workgroup_init = false;
 
-    /// Options used in the binding mappings for external textures
-    ExternalTextureOptions external_texture_options = {};
-
-    /// Options used to specify a mapping of binding points to indices into a UBO
-    /// from which to load buffer sizes.
-    ArrayLengthFromUniformOptions array_length_from_uniform = {};
-
-    /// Options used in the bindings remapper
-    BindingRemapperOptions binding_remapper_options = {};
-
-    /// Interstage locations actually used as inputs in the next stage of the pipeline.
-    /// This is potentially used for truncating unused interstage outputs at current shader stage.
-    std::bitset<16> interstage_locations;
-
     /// Set to `true` to run the TruncateInterstageVariables transform.
     bool truncate_interstage_variables = false;
 
     /// Set to `true` to generate polyfill for `reflect` builtin for vec2<f32>
     bool polyfill_reflect_vec2_f32 = false;
 
+    /// Options used to specify a mapping of binding points to indices into a UBO
+    /// from which to load buffer sizes.
+    ArrayLengthFromUniformOptions array_length_from_uniform = {};
+
+    /// Interstage locations actually used as inputs in the next stage of the pipeline.
+    /// This is potentially used for truncating unused interstage outputs at current shader stage.
+    std::bitset<16> interstage_locations;
+
+    /// The binding point to use for information passed via root constants.
+    std::optional<BindingPoint> root_constant_binding_point;
+
+    /// Options used in the binding mappings for external textures
+    ExternalTextureOptions external_texture_options = {};
+
+    /// Options used in the bindings remapper
+    BindingRemapperOptions binding_remapper_options = {};
+
     /// The binding points that will be ignored in the rebustness transform.
     std::vector<BindingPoint> binding_points_ignored_in_robustness_transform;
 
+    /// AccessControls is a map of old binding point to new access control
+    std::unordered_map<BindingPoint, core::Access> access_controls;
+
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
     TINT_REFLECT(disable_robustness,
-                 root_constant_binding_point,
                  disable_workgroup_init,
-                 external_texture_options,
-                 array_length_from_uniform,
-                 binding_remapper_options,
-                 interstage_locations,
                  truncate_interstage_variables,
                  polyfill_reflect_vec2_f32,
-                 binding_points_ignored_in_robustness_transform);
+                 array_length_from_uniform,
+                 interstage_locations,
+                 root_constant_binding_point,
+                 external_texture_options,
+                 binding_remapper_options,
+                 binding_points_ignored_in_robustness_transform,
+                 access_controls);
 };
 
 }  // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/writer.cc b/src/tint/lang/hlsl/writer/writer.cc
index 67493be..2c1acc8 100644
--- a/src/tint/lang/hlsl/writer/writer.cc
+++ b/src/tint/lang/hlsl/writer/writer.cc
@@ -21,21 +21,21 @@
 
 namespace tint::hlsl::writer {
 
-Result<Output, std::string> Generate(const Program& program, const Options& options) {
+Result<Output> Generate(const Program& program, const Options& options) {
     if (!program.IsValid()) {
-        return std::string("input program is not valid");
+        return Failure{program.Diagnostics()};
     }
 
     // Sanitize the program.
     auto sanitized_result = Sanitize(program, options);
     if (!sanitized_result.program.IsValid()) {
-        return sanitized_result.program.Diagnostics().str();
+        return Failure{sanitized_result.program.Diagnostics()};
     }
 
     // Generate the HLSL code.
     auto impl = std::make_unique<ASTPrinter>(sanitized_result.program);
     if (!impl->Generate()) {
-        return impl->Diagnostics().str();
+        return Failure{impl->Diagnostics()};
     }
 
     Output output;
diff --git a/src/tint/lang/hlsl/writer/writer.h b/src/tint/lang/hlsl/writer/writer.h
index 68b5c3c..658e68c 100644
--- a/src/tint/lang/hlsl/writer/writer.h
+++ b/src/tint/lang/hlsl/writer/writer.h
@@ -19,6 +19,7 @@
 
 #include "src/tint/lang/hlsl/writer/common/options.h"
 #include "src/tint/lang/hlsl/writer/output.h"
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward declarations
@@ -29,11 +30,11 @@
 namespace tint::hlsl::writer {
 
 /// Generate HLSL for a program, according to a set of configuration options.
-/// The result will contain the HLSL and supplementary information, or an error string.
+/// The result will contain the HLSL and supplementary information, or failure.
 /// @param program the program to translate to HLSL
 /// @param options the configuration options to use when generating HLSL
-/// @returns the resulting HLSL and supplementary information, or an error string
-Result<Output, std::string> Generate(const Program& program, const Options& options);
+/// @returns the resulting HLSL and supplementary information, or failure
+Result<Output> Generate(const Program& program, const Options& options);
 
 }  // namespace tint::hlsl::writer
 
diff --git a/src/tint/lang/hlsl/writer/writer_bench.cc b/src/tint/lang/hlsl/writer/writer_bench.cc
index 6250e0f..00c5d39 100644
--- a/src/tint/lang/hlsl/writer/writer_bench.cc
+++ b/src/tint/lang/hlsl/writer/writer_bench.cc
@@ -30,7 +30,7 @@
     for (auto _ : state) {
         auto res = Generate(program, {});
         if (!res) {
-            state.SkipWithError(res.Failure().c_str());
+            state.SkipWithError(res.Failure().reason.str());
         }
     }
 }
diff --git a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
index 2db793f..796f53f 100644
--- a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
@@ -187,7 +187,7 @@
     manager.Add<ast::transform::BindingRemapper>();
     data.Add<ast::transform::BindingRemapper::Remappings>(
         options.binding_remapper_options.binding_points,
-        options.binding_remapper_options.access_controls,
+        std::unordered_map<BindingPoint, core::Access>{},
         options.binding_remapper_options.allow_collisions);
 
     if (!options.disable_workgroup_init) {
@@ -680,24 +680,24 @@
     auto name = generate_builtin_name(builtin);
 
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kDot:
+        case wgsl::BuiltinFn::kDot:
             return EmitDotCall(out, expr, builtin);
-        case core::BuiltinFn::kModf:
+        case wgsl::BuiltinFn::kModf:
             return EmitModfCall(out, expr, builtin);
-        case core::BuiltinFn::kFrexp:
+        case wgsl::BuiltinFn::kFrexp:
             return EmitFrexpCall(out, expr, builtin);
-        case core::BuiltinFn::kDegrees:
+        case wgsl::BuiltinFn::kDegrees:
             return EmitDegreesCall(out, expr, builtin);
-        case core::BuiltinFn::kRadians:
+        case wgsl::BuiltinFn::kRadians:
             return EmitRadiansCall(out, expr, builtin);
-        case core::BuiltinFn::kDot4I8Packed:
+        case wgsl::BuiltinFn::kDot4I8Packed:
             return EmitDot4I8PackedCall(out, expr, builtin);
-        case core::BuiltinFn::kDot4U8Packed:
+        case wgsl::BuiltinFn::kDot4U8Packed:
             return EmitDot4U8PackedCall(out, expr, builtin);
 
-        case core::BuiltinFn::kPack2X16Float:
-        case core::BuiltinFn::kUnpack2X16Float: {
-            if (builtin->Fn() == core::BuiltinFn::kPack2X16Float) {
+        case wgsl::BuiltinFn::kPack2X16Float:
+        case wgsl::BuiltinFn::kUnpack2X16Float: {
+            if (builtin->Fn() == wgsl::BuiltinFn::kPack2X16Float) {
                 out << "as_type<uint>(half2(";
             } else {
                 out << "float2(as_type<half2>(";
@@ -708,7 +708,7 @@
             out << "))";
             return true;
         }
-        case core::BuiltinFn::kQuantizeToF16: {
+        case wgsl::BuiltinFn::kQuantizeToF16: {
             std::string width = "";
             if (auto* vec = builtin->ReturnType()->As<core::type::Vector>()) {
                 width = std::to_string(vec->Width());
@@ -722,20 +722,20 @@
         }
         // TODO(crbug.com/tint/661): Combine sequential barriers to a single
         // instruction.
-        case core::BuiltinFn::kStorageBarrier: {
+        case wgsl::BuiltinFn::kStorageBarrier: {
             out << "threadgroup_barrier(mem_flags::mem_device)";
             return true;
         }
-        case core::BuiltinFn::kWorkgroupBarrier: {
+        case wgsl::BuiltinFn::kWorkgroupBarrier: {
             out << "threadgroup_barrier(mem_flags::mem_threadgroup)";
             return true;
         }
-        case core::BuiltinFn::kTextureBarrier: {
+        case wgsl::BuiltinFn::kTextureBarrier: {
             out << "threadgroup_barrier(mem_flags::mem_texture)";
             return true;
         }
 
-        case core::BuiltinFn::kLength: {
+        case wgsl::BuiltinFn::kLength: {
             auto* sem = builder_.Sem().GetVal(expr->args[0]);
             if (sem->Type()->UnwrapRef()->Is<core::type::Scalar>()) {
                 // Emulate scalar overload using fabs(x).
@@ -744,7 +744,7 @@
             break;
         }
 
-        case core::BuiltinFn::kDistance: {
+        case wgsl::BuiltinFn::kDistance: {
             auto* sem = builder_.Sem().GetVal(expr->args[0]);
             if (sem->Type()->UnwrapRef()->Is<core::type::Scalar>()) {
                 // Emulate scalar overload using fabs(x - y);
@@ -762,7 +762,7 @@
             break;
         }
 
-        case core::BuiltinFn::kSubgroupBroadcast: {
+        case wgsl::BuiltinFn::kSubgroupBroadcast: {
             // The lane argument is ushort.
             out << "simd_broadcast(";
             if (!EmitExpression(out, expr->args[0])) {
@@ -898,37 +898,37 @@
     };
 
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kAtomicLoad:
+        case wgsl::BuiltinFn::kAtomicLoad:
             return call("atomic_load_explicit", true);
 
-        case core::BuiltinFn::kAtomicStore:
+        case wgsl::BuiltinFn::kAtomicStore:
             return call("atomic_store_explicit", true);
 
-        case core::BuiltinFn::kAtomicAdd:
+        case wgsl::BuiltinFn::kAtomicAdd:
             return call("atomic_fetch_add_explicit", true);
 
-        case core::BuiltinFn::kAtomicSub:
+        case wgsl::BuiltinFn::kAtomicSub:
             return call("atomic_fetch_sub_explicit", true);
 
-        case core::BuiltinFn::kAtomicMax:
+        case wgsl::BuiltinFn::kAtomicMax:
             return call("atomic_fetch_max_explicit", true);
 
-        case core::BuiltinFn::kAtomicMin:
+        case wgsl::BuiltinFn::kAtomicMin:
             return call("atomic_fetch_min_explicit", true);
 
-        case core::BuiltinFn::kAtomicAnd:
+        case wgsl::BuiltinFn::kAtomicAnd:
             return call("atomic_fetch_and_explicit", true);
 
-        case core::BuiltinFn::kAtomicOr:
+        case wgsl::BuiltinFn::kAtomicOr:
             return call("atomic_fetch_or_explicit", true);
 
-        case core::BuiltinFn::kAtomicXor:
+        case wgsl::BuiltinFn::kAtomicXor:
             return call("atomic_fetch_xor_explicit", true);
 
-        case core::BuiltinFn::kAtomicExchange:
+        case wgsl::BuiltinFn::kAtomicExchange:
             return call("atomic_exchange_explicit", true);
 
-        case core::BuiltinFn::kAtomicCompareExchangeWeak: {
+        case wgsl::BuiltinFn::kAtomicCompareExchangeWeak: {
             auto* ptr_ty = TypeOf(expr->args[0])->UnwrapRef()->As<core::type::Pointer>();
             auto sc = ptr_ty->AddressSpace();
             auto* str = builtin->ReturnType()->As<core::type::Struct>();
@@ -1044,7 +1044,7 @@
     bool level_is_constant_zero = texture_type->dim() == core::type::TextureDimension::k1d;
 
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kTextureDimensions: {
+        case wgsl::BuiltinFn::kTextureDimensions: {
             std::vector<const char*> dims;
             switch (texture_type->dim()) {
                 case core::type::TextureDimension::kNone:
@@ -1097,21 +1097,21 @@
             }
             return true;
         }
-        case core::BuiltinFn::kTextureNumLayers: {
+        case wgsl::BuiltinFn::kTextureNumLayers: {
             if (!texture_expr()) {
                 return false;
             }
             out << ".get_array_size()";
             return true;
         }
-        case core::BuiltinFn::kTextureNumLevels: {
+        case wgsl::BuiltinFn::kTextureNumLevels: {
             if (!texture_expr()) {
                 return false;
             }
             out << ".get_num_mip_levels()";
             return true;
         }
-        case core::BuiltinFn::kTextureNumSamples: {
+        case wgsl::BuiltinFn::kTextureNumSamples: {
             if (!texture_expr()) {
                 return false;
             }
@@ -1129,27 +1129,27 @@
     bool lod_param_is_named = true;
 
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kTextureSample:
-        case core::BuiltinFn::kTextureSampleBias:
-        case core::BuiltinFn::kTextureSampleLevel:
-        case core::BuiltinFn::kTextureSampleGrad:
+        case wgsl::BuiltinFn::kTextureSample:
+        case wgsl::BuiltinFn::kTextureSampleBias:
+        case wgsl::BuiltinFn::kTextureSampleLevel:
+        case wgsl::BuiltinFn::kTextureSampleGrad:
             out << ".sample(";
             break;
-        case core::BuiltinFn::kTextureSampleCompare:
-        case core::BuiltinFn::kTextureSampleCompareLevel:
+        case wgsl::BuiltinFn::kTextureSampleCompare:
+        case wgsl::BuiltinFn::kTextureSampleCompareLevel:
             out << ".sample_compare(";
             break;
-        case core::BuiltinFn::kTextureGather:
+        case wgsl::BuiltinFn::kTextureGather:
             out << ".gather(";
             break;
-        case core::BuiltinFn::kTextureGatherCompare:
+        case wgsl::BuiltinFn::kTextureGatherCompare:
             out << ".gather_compare(";
             break;
-        case core::BuiltinFn::kTextureLoad:
+        case wgsl::BuiltinFn::kTextureLoad:
             out << ".read(";
             lod_param_is_named = false;
             break;
-        case core::BuiltinFn::kTextureStore:
+        case wgsl::BuiltinFn::kTextureStore:
             out << ".write(";
             break;
         default:
@@ -1225,7 +1225,7 @@
             out << ")";
         }
     }
-    if (builtin->Fn() == core::BuiltinFn::kTextureSampleCompareLevel) {
+    if (builtin->Fn() == wgsl::BuiltinFn::kTextureSampleCompareLevel) {
         maybe_write_comma();
         out << "level(0)";
     }
@@ -1310,7 +1310,7 @@
     // If this is a `textureStore()` for a read-write texture, add a fence to ensure that the
     // written values are visible to subsequent reads from the same thread.
     if (auto* storage = texture_type->As<core::type::StorageTexture>();
-        builtin->Fn() == core::BuiltinFn::kTextureStore &&
+        builtin->Fn() == wgsl::BuiltinFn::kTextureStore &&
         storage->access() == core::Access::kReadWrite) {
         out << "; ";
         texture_expr();
@@ -1468,143 +1468,143 @@
 std::string ASTPrinter::generate_builtin_name(const sem::BuiltinFn* builtin) {
     std::string out = "";
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kAcos:
-        case core::BuiltinFn::kAcosh:
-        case core::BuiltinFn::kAll:
-        case core::BuiltinFn::kAny:
-        case core::BuiltinFn::kAsin:
-        case core::BuiltinFn::kAsinh:
-        case core::BuiltinFn::kAtanh:
-        case core::BuiltinFn::kAtan:
-        case core::BuiltinFn::kAtan2:
-        case core::BuiltinFn::kCeil:
-        case core::BuiltinFn::kCos:
-        case core::BuiltinFn::kCosh:
-        case core::BuiltinFn::kCross:
-        case core::BuiltinFn::kDeterminant:
-        case core::BuiltinFn::kDistance:
-        case core::BuiltinFn::kDot:
-        case core::BuiltinFn::kExp:
-        case core::BuiltinFn::kExp2:
-        case core::BuiltinFn::kFloor:
-        case core::BuiltinFn::kFma:
-        case core::BuiltinFn::kFract:
-        case core::BuiltinFn::kFrexp:
-        case core::BuiltinFn::kLength:
-        case core::BuiltinFn::kLdexp:
-        case core::BuiltinFn::kLog:
-        case core::BuiltinFn::kLog2:
-        case core::BuiltinFn::kMix:
-        case core::BuiltinFn::kModf:
-        case core::BuiltinFn::kNormalize:
-        case core::BuiltinFn::kPow:
-        case core::BuiltinFn::kReflect:
-        case core::BuiltinFn::kRefract:
-        case core::BuiltinFn::kSaturate:
-        case core::BuiltinFn::kSelect:
-        case core::BuiltinFn::kSin:
-        case core::BuiltinFn::kSinh:
-        case core::BuiltinFn::kSqrt:
-        case core::BuiltinFn::kStep:
-        case core::BuiltinFn::kTan:
-        case core::BuiltinFn::kTanh:
-        case core::BuiltinFn::kTranspose:
-        case core::BuiltinFn::kTrunc:
-        case core::BuiltinFn::kSign:
-        case core::BuiltinFn::kClamp:
+        case wgsl::BuiltinFn::kAcos:
+        case wgsl::BuiltinFn::kAcosh:
+        case wgsl::BuiltinFn::kAll:
+        case wgsl::BuiltinFn::kAny:
+        case wgsl::BuiltinFn::kAsin:
+        case wgsl::BuiltinFn::kAsinh:
+        case wgsl::BuiltinFn::kAtanh:
+        case wgsl::BuiltinFn::kAtan:
+        case wgsl::BuiltinFn::kAtan2:
+        case wgsl::BuiltinFn::kCeil:
+        case wgsl::BuiltinFn::kCos:
+        case wgsl::BuiltinFn::kCosh:
+        case wgsl::BuiltinFn::kCross:
+        case wgsl::BuiltinFn::kDeterminant:
+        case wgsl::BuiltinFn::kDistance:
+        case wgsl::BuiltinFn::kDot:
+        case wgsl::BuiltinFn::kExp:
+        case wgsl::BuiltinFn::kExp2:
+        case wgsl::BuiltinFn::kFloor:
+        case wgsl::BuiltinFn::kFma:
+        case wgsl::BuiltinFn::kFract:
+        case wgsl::BuiltinFn::kFrexp:
+        case wgsl::BuiltinFn::kLength:
+        case wgsl::BuiltinFn::kLdexp:
+        case wgsl::BuiltinFn::kLog:
+        case wgsl::BuiltinFn::kLog2:
+        case wgsl::BuiltinFn::kMix:
+        case wgsl::BuiltinFn::kModf:
+        case wgsl::BuiltinFn::kNormalize:
+        case wgsl::BuiltinFn::kPow:
+        case wgsl::BuiltinFn::kReflect:
+        case wgsl::BuiltinFn::kRefract:
+        case wgsl::BuiltinFn::kSaturate:
+        case wgsl::BuiltinFn::kSelect:
+        case wgsl::BuiltinFn::kSin:
+        case wgsl::BuiltinFn::kSinh:
+        case wgsl::BuiltinFn::kSqrt:
+        case wgsl::BuiltinFn::kStep:
+        case wgsl::BuiltinFn::kTan:
+        case wgsl::BuiltinFn::kTanh:
+        case wgsl::BuiltinFn::kTranspose:
+        case wgsl::BuiltinFn::kTrunc:
+        case wgsl::BuiltinFn::kSign:
+        case wgsl::BuiltinFn::kClamp:
             out += builtin->str();
             break;
-        case core::BuiltinFn::kAbs:
+        case wgsl::BuiltinFn::kAbs:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 out += "fabs";
             } else {
                 out += "abs";
             }
             break;
-        case core::BuiltinFn::kCountLeadingZeros:
+        case wgsl::BuiltinFn::kCountLeadingZeros:
             out += "clz";
             break;
-        case core::BuiltinFn::kCountOneBits:
+        case wgsl::BuiltinFn::kCountOneBits:
             out += "popcount";
             break;
-        case core::BuiltinFn::kCountTrailingZeros:
+        case wgsl::BuiltinFn::kCountTrailingZeros:
             out += "ctz";
             break;
-        case core::BuiltinFn::kDpdx:
-        case core::BuiltinFn::kDpdxCoarse:
-        case core::BuiltinFn::kDpdxFine:
+        case wgsl::BuiltinFn::kDpdx:
+        case wgsl::BuiltinFn::kDpdxCoarse:
+        case wgsl::BuiltinFn::kDpdxFine:
             out += "dfdx";
             break;
-        case core::BuiltinFn::kDpdy:
-        case core::BuiltinFn::kDpdyCoarse:
-        case core::BuiltinFn::kDpdyFine:
+        case wgsl::BuiltinFn::kDpdy:
+        case wgsl::BuiltinFn::kDpdyCoarse:
+        case wgsl::BuiltinFn::kDpdyFine:
             out += "dfdy";
             break;
-        case core::BuiltinFn::kExtractBits:
+        case wgsl::BuiltinFn::kExtractBits:
             out += "extract_bits";
             break;
-        case core::BuiltinFn::kInsertBits:
+        case wgsl::BuiltinFn::kInsertBits:
             out += "insert_bits";
             break;
-        case core::BuiltinFn::kFwidth:
-        case core::BuiltinFn::kFwidthCoarse:
-        case core::BuiltinFn::kFwidthFine:
+        case wgsl::BuiltinFn::kFwidth:
+        case wgsl::BuiltinFn::kFwidthCoarse:
+        case wgsl::BuiltinFn::kFwidthFine:
             out += "fwidth";
             break;
-        case core::BuiltinFn::kMax:
+        case wgsl::BuiltinFn::kMax:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 out += "fmax";
             } else {
                 out += "max";
             }
             break;
-        case core::BuiltinFn::kMin:
+        case wgsl::BuiltinFn::kMin:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 out += "fmin";
             } else {
                 out += "min";
             }
             break;
-        case core::BuiltinFn::kFaceForward:
+        case wgsl::BuiltinFn::kFaceForward:
             out += "faceforward";
             break;
-        case core::BuiltinFn::kPack4X8Snorm:
+        case wgsl::BuiltinFn::kPack4X8Snorm:
             out += "pack_float_to_snorm4x8";
             break;
-        case core::BuiltinFn::kPack4X8Unorm:
+        case wgsl::BuiltinFn::kPack4X8Unorm:
             out += "pack_float_to_unorm4x8";
             break;
-        case core::BuiltinFn::kPack2X16Snorm:
+        case wgsl::BuiltinFn::kPack2X16Snorm:
             out += "pack_float_to_snorm2x16";
             break;
-        case core::BuiltinFn::kPack2X16Unorm:
+        case wgsl::BuiltinFn::kPack2X16Unorm:
             out += "pack_float_to_unorm2x16";
             break;
-        case core::BuiltinFn::kReverseBits:
+        case wgsl::BuiltinFn::kReverseBits:
             out += "reverse_bits";
             break;
-        case core::BuiltinFn::kRound:
+        case wgsl::BuiltinFn::kRound:
             out += "rint";
             break;
-        case core::BuiltinFn::kSmoothstep:
+        case wgsl::BuiltinFn::kSmoothstep:
             out += "smoothstep";
             break;
-        case core::BuiltinFn::kInverseSqrt:
+        case wgsl::BuiltinFn::kInverseSqrt:
             out += "rsqrt";
             break;
-        case core::BuiltinFn::kUnpack4X8Snorm:
+        case wgsl::BuiltinFn::kUnpack4X8Snorm:
             out += "unpack_snorm4x8_to_float";
             break;
-        case core::BuiltinFn::kUnpack4X8Unorm:
+        case wgsl::BuiltinFn::kUnpack4X8Unorm:
             out += "unpack_unorm4x8_to_float";
             break;
-        case core::BuiltinFn::kUnpack2X16Snorm:
+        case wgsl::BuiltinFn::kUnpack2X16Snorm:
             out += "unpack_snorm2x16_to_float";
             break;
-        case core::BuiltinFn::kUnpack2X16Unorm:
+        case wgsl::BuiltinFn::kUnpack2X16Unorm:
             out += "unpack_unorm2x16_to_float";
             break;
-        case core::BuiltinFn::kArrayLength:
+        case wgsl::BuiltinFn::kArrayLength:
             diagnostics_.add_error(
                 diag::System::Writer,
                 "Unable to translate builtin: " + std::string(builtin->str()) +
@@ -3070,7 +3070,7 @@
         TextBuffer b;
         TINT_DEFER(helpers_.Append(b));
 
-        auto fn_name = UniqueIdentifier(std::string("tint_") + core::str(builtin->Fn()));
+        auto fn_name = UniqueIdentifier(std::string("tint_") + wgsl::str(builtin->Fn()));
         std::vector<std::string> parameter_names;
         {
             auto decl = Line(&b);
diff --git a/src/tint/lang/msl/writer/ast_printer/ast_printer_test.cc b/src/tint/lang/msl/writer/ast_printer/ast_printer_test.cc
index 7087797..abdc1b7 100644
--- a/src/tint/lang/msl/writer/ast_printer/ast_printer_test.cc
+++ b/src/tint/lang/msl/writer/ast_printer/ast_printer_test.cc
@@ -32,7 +32,7 @@
     ASSERT_FALSE(program.IsValid());
     auto result = Generate(program, Options{});
     EXPECT_FALSE(result);
-    EXPECT_EQ(result.Failure(), "input program is not valid");
+    EXPECT_EQ(result.Failure().reason.str(), "error: make the program invalid");
 }
 
 TEST_F(MslASTPrinterTest, UnsupportedExtension) {
diff --git a/src/tint/lang/msl/writer/ast_printer/builtin_test.cc b/src/tint/lang/msl/writer/ast_printer/builtin_test.cc
index a137075..f2d4f69 100644
--- a/src/tint/lang/msl/writer/ast_printer/builtin_test.cc
+++ b/src/tint/lang/msl/writer/ast_printer/builtin_test.cc
@@ -33,7 +33,7 @@
 };
 
 struct BuiltinData {
-    core::BuiltinFn builtin;
+    wgsl::BuiltinFn builtin;
     CallParamType type;
     const char* msl_name;
 };
@@ -57,88 +57,88 @@
     return out;
 }
 
-const ast::CallExpression* GenerateCall(core::BuiltinFn builtin,
+const ast::CallExpression* GenerateCall(wgsl::BuiltinFn builtin,
                                         CallParamType type,
                                         ProgramBuilder* builder) {
     std::string name;
     StringStream str;
     str << name << builtin;
     switch (builtin) {
-        case core::BuiltinFn::kAcos:
-        case core::BuiltinFn::kAsin:
-        case core::BuiltinFn::kAtan:
-        case core::BuiltinFn::kCeil:
-        case core::BuiltinFn::kCos:
-        case core::BuiltinFn::kCosh:
-        case core::BuiltinFn::kDpdx:
-        case core::BuiltinFn::kDpdxCoarse:
-        case core::BuiltinFn::kDpdxFine:
-        case core::BuiltinFn::kDpdy:
-        case core::BuiltinFn::kDpdyCoarse:
-        case core::BuiltinFn::kDpdyFine:
-        case core::BuiltinFn::kExp:
-        case core::BuiltinFn::kExp2:
-        case core::BuiltinFn::kFloor:
-        case core::BuiltinFn::kFract:
-        case core::BuiltinFn::kFwidth:
-        case core::BuiltinFn::kFwidthCoarse:
-        case core::BuiltinFn::kFwidthFine:
-        case core::BuiltinFn::kInverseSqrt:
-        case core::BuiltinFn::kLength:
-        case core::BuiltinFn::kLog:
-        case core::BuiltinFn::kLog2:
-        case core::BuiltinFn::kNormalize:
-        case core::BuiltinFn::kRound:
-        case core::BuiltinFn::kSin:
-        case core::BuiltinFn::kSinh:
-        case core::BuiltinFn::kSqrt:
-        case core::BuiltinFn::kTan:
-        case core::BuiltinFn::kTanh:
-        case core::BuiltinFn::kTrunc:
-        case core::BuiltinFn::kSign:
+        case wgsl::BuiltinFn::kAcos:
+        case wgsl::BuiltinFn::kAsin:
+        case wgsl::BuiltinFn::kAtan:
+        case wgsl::BuiltinFn::kCeil:
+        case wgsl::BuiltinFn::kCos:
+        case wgsl::BuiltinFn::kCosh:
+        case wgsl::BuiltinFn::kDpdx:
+        case wgsl::BuiltinFn::kDpdxCoarse:
+        case wgsl::BuiltinFn::kDpdxFine:
+        case wgsl::BuiltinFn::kDpdy:
+        case wgsl::BuiltinFn::kDpdyCoarse:
+        case wgsl::BuiltinFn::kDpdyFine:
+        case wgsl::BuiltinFn::kExp:
+        case wgsl::BuiltinFn::kExp2:
+        case wgsl::BuiltinFn::kFloor:
+        case wgsl::BuiltinFn::kFract:
+        case wgsl::BuiltinFn::kFwidth:
+        case wgsl::BuiltinFn::kFwidthCoarse:
+        case wgsl::BuiltinFn::kFwidthFine:
+        case wgsl::BuiltinFn::kInverseSqrt:
+        case wgsl::BuiltinFn::kLength:
+        case wgsl::BuiltinFn::kLog:
+        case wgsl::BuiltinFn::kLog2:
+        case wgsl::BuiltinFn::kNormalize:
+        case wgsl::BuiltinFn::kRound:
+        case wgsl::BuiltinFn::kSin:
+        case wgsl::BuiltinFn::kSinh:
+        case wgsl::BuiltinFn::kSqrt:
+        case wgsl::BuiltinFn::kTan:
+        case wgsl::BuiltinFn::kTanh:
+        case wgsl::BuiltinFn::kTrunc:
+        case wgsl::BuiltinFn::kSign:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2");
             } else {
                 return builder->Call(str.str(), "f2");
             }
-        case core::BuiltinFn::kLdexp:
+        case wgsl::BuiltinFn::kLdexp:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "i2");
             } else {
                 return builder->Call(str.str(), "f2", "i2");
             }
-        case core::BuiltinFn::kAtan2:
-        case core::BuiltinFn::kDot:
-        case core::BuiltinFn::kDistance:
-        case core::BuiltinFn::kPow:
-        case core::BuiltinFn::kReflect:
-        case core::BuiltinFn::kStep:
+        case wgsl::BuiltinFn::kAtan2:
+        case wgsl::BuiltinFn::kDot:
+        case wgsl::BuiltinFn::kDistance:
+        case wgsl::BuiltinFn::kPow:
+        case wgsl::BuiltinFn::kReflect:
+        case wgsl::BuiltinFn::kStep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2");
             }
-        case core::BuiltinFn::kStorageBarrier:
+        case wgsl::BuiltinFn::kStorageBarrier:
             return builder->Call(str.str());
-        case core::BuiltinFn::kCross:
+        case wgsl::BuiltinFn::kCross:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h3", "h3");
             } else {
                 return builder->Call(str.str(), "f3", "f3");
             }
-        case core::BuiltinFn::kFma:
-        case core::BuiltinFn::kMix:
-        case core::BuiltinFn::kFaceForward:
-        case core::BuiltinFn::kSmoothstep:
+        case wgsl::BuiltinFn::kFma:
+        case wgsl::BuiltinFn::kMix:
+        case wgsl::BuiltinFn::kFaceForward:
+        case wgsl::BuiltinFn::kSmoothstep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             }
-        case core::BuiltinFn::kAll:
-        case core::BuiltinFn::kAny:
+        case wgsl::BuiltinFn::kAll:
+        case wgsl::BuiltinFn::kAny:
             return builder->Call(str.str(), "b2");
-        case core::BuiltinFn::kAbs:
+        case wgsl::BuiltinFn::kAbs:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2");
             } else if (type == CallParamType::kF16) {
@@ -146,17 +146,17 @@
             } else {
                 return builder->Call(str.str(), "u2");
             }
-        case core::BuiltinFn::kCountLeadingZeros:
-        case core::BuiltinFn::kCountOneBits:
-        case core::BuiltinFn::kCountTrailingZeros:
-        case core::BuiltinFn::kReverseBits:
+        case wgsl::BuiltinFn::kCountLeadingZeros:
+        case wgsl::BuiltinFn::kCountOneBits:
+        case wgsl::BuiltinFn::kCountTrailingZeros:
+        case wgsl::BuiltinFn::kReverseBits:
             return builder->Call(str.str(), "u2");
-        case core::BuiltinFn::kExtractBits:
+        case wgsl::BuiltinFn::kExtractBits:
             return builder->Call(str.str(), "u2", "u1", "u1");
-        case core::BuiltinFn::kInsertBits:
+        case wgsl::BuiltinFn::kInsertBits:
             return builder->Call(str.str(), "u2", "u2", "u1", "u1");
-        case core::BuiltinFn::kMax:
-        case core::BuiltinFn::kMin:
+        case wgsl::BuiltinFn::kMax:
+        case wgsl::BuiltinFn::kMin:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -164,7 +164,7 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2");
             }
-        case core::BuiltinFn::kClamp:
+        case wgsl::BuiltinFn::kClamp:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -172,32 +172,32 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2", "u2");
             }
-        case core::BuiltinFn::kSelect:
+        case wgsl::BuiltinFn::kSelect:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "b2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "b2");
             }
-        case core::BuiltinFn::kDeterminant:
+        case wgsl::BuiltinFn::kDeterminant:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm2x2");
             } else {
                 return builder->Call(str.str(), "m2x2");
             }
-        case core::BuiltinFn::kPack2X16Snorm:
-        case core::BuiltinFn::kPack2X16Unorm:
+        case wgsl::BuiltinFn::kPack2X16Snorm:
+        case wgsl::BuiltinFn::kPack2X16Unorm:
             return builder->Call(str.str(), "f2");
-        case core::BuiltinFn::kPack4X8Snorm:
-        case core::BuiltinFn::kPack4X8Unorm:
+        case wgsl::BuiltinFn::kPack4X8Snorm:
+        case wgsl::BuiltinFn::kPack4X8Unorm:
             return builder->Call(str.str(), "f4");
-        case core::BuiltinFn::kUnpack4X8Snorm:
-        case core::BuiltinFn::kUnpack4X8Unorm:
-        case core::BuiltinFn::kUnpack2X16Snorm:
-        case core::BuiltinFn::kUnpack2X16Unorm:
+        case wgsl::BuiltinFn::kUnpack4X8Snorm:
+        case wgsl::BuiltinFn::kUnpack4X8Unorm:
+        case wgsl::BuiltinFn::kUnpack2X16Snorm:
+        case wgsl::BuiltinFn::kUnpack2X16Unorm:
             return builder->Call(str.str(), "u1");
-        case core::BuiltinFn::kWorkgroupBarrier:
+        case wgsl::BuiltinFn::kWorkgroupBarrier:
             return builder->Call(str.str());
-        case core::BuiltinFn::kTranspose:
+        case wgsl::BuiltinFn::kTranspose:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm3x2");
             } else {
@@ -253,124 +253,124 @@
     MslBuiltinTest,
     testing::Values(
         /* Logical built-in */
-        BuiltinData{core::BuiltinFn::kAll, CallParamType::kBool, "all"},
-        BuiltinData{core::BuiltinFn::kAny, CallParamType::kBool, "any"},
-        BuiltinData{core::BuiltinFn::kSelect, CallParamType::kF32, "select"},
+        BuiltinData{wgsl::BuiltinFn::kAll, CallParamType::kBool, "all"},
+        BuiltinData{wgsl::BuiltinFn::kAny, CallParamType::kBool, "any"},
+        BuiltinData{wgsl::BuiltinFn::kSelect, CallParamType::kF32, "select"},
         /* Float built-in */
-        BuiltinData{core::BuiltinFn::kAbs, CallParamType::kF32, "fabs"},
-        BuiltinData{core::BuiltinFn::kAbs, CallParamType::kF16, "fabs"},
-        BuiltinData{core::BuiltinFn::kAcos, CallParamType::kF32, "acos"},
-        BuiltinData{core::BuiltinFn::kAcos, CallParamType::kF16, "acos"},
-        BuiltinData{core::BuiltinFn::kAsin, CallParamType::kF32, "asin"},
-        BuiltinData{core::BuiltinFn::kAsin, CallParamType::kF16, "asin"},
-        BuiltinData{core::BuiltinFn::kAtan, CallParamType::kF32, "atan"},
-        BuiltinData{core::BuiltinFn::kAtan, CallParamType::kF16, "atan"},
-        BuiltinData{core::BuiltinFn::kAtan2, CallParamType::kF32, "atan2"},
-        BuiltinData{core::BuiltinFn::kAtan2, CallParamType::kF16, "atan2"},
-        BuiltinData{core::BuiltinFn::kCeil, CallParamType::kF32, "ceil"},
-        BuiltinData{core::BuiltinFn::kCeil, CallParamType::kF16, "ceil"},
-        BuiltinData{core::BuiltinFn::kClamp, CallParamType::kF32, "clamp"},
-        BuiltinData{core::BuiltinFn::kClamp, CallParamType::kF16, "clamp"},
-        BuiltinData{core::BuiltinFn::kCos, CallParamType::kF32, "cos"},
-        BuiltinData{core::BuiltinFn::kCos, CallParamType::kF16, "cos"},
-        BuiltinData{core::BuiltinFn::kCosh, CallParamType::kF32, "cosh"},
-        BuiltinData{core::BuiltinFn::kCosh, CallParamType::kF16, "cosh"},
-        BuiltinData{core::BuiltinFn::kCross, CallParamType::kF32, "cross"},
-        BuiltinData{core::BuiltinFn::kCross, CallParamType::kF16, "cross"},
-        BuiltinData{core::BuiltinFn::kDistance, CallParamType::kF32, "distance"},
-        BuiltinData{core::BuiltinFn::kDistance, CallParamType::kF16, "distance"},
-        BuiltinData{core::BuiltinFn::kExp, CallParamType::kF32, "exp"},
-        BuiltinData{core::BuiltinFn::kExp, CallParamType::kF16, "exp"},
-        BuiltinData{core::BuiltinFn::kExp2, CallParamType::kF32, "exp2"},
-        BuiltinData{core::BuiltinFn::kExp2, CallParamType::kF16, "exp2"},
-        BuiltinData{core::BuiltinFn::kFaceForward, CallParamType::kF32, "faceforward"},
-        BuiltinData{core::BuiltinFn::kFaceForward, CallParamType::kF16, "faceforward"},
-        BuiltinData{core::BuiltinFn::kFloor, CallParamType::kF32, "floor"},
-        BuiltinData{core::BuiltinFn::kFloor, CallParamType::kF16, "floor"},
-        BuiltinData{core::BuiltinFn::kFma, CallParamType::kF32, "fma"},
-        BuiltinData{core::BuiltinFn::kFma, CallParamType::kF16, "fma"},
-        BuiltinData{core::BuiltinFn::kFract, CallParamType::kF32, "fract"},
-        BuiltinData{core::BuiltinFn::kFract, CallParamType::kF16, "fract"},
-        BuiltinData{core::BuiltinFn::kInverseSqrt, CallParamType::kF32, "rsqrt"},
-        BuiltinData{core::BuiltinFn::kInverseSqrt, CallParamType::kF16, "rsqrt"},
-        BuiltinData{core::BuiltinFn::kLdexp, CallParamType::kF32, "ldexp"},
-        BuiltinData{core::BuiltinFn::kLdexp, CallParamType::kF16, "ldexp"},
-        BuiltinData{core::BuiltinFn::kLength, CallParamType::kF32, "length"},
-        BuiltinData{core::BuiltinFn::kLength, CallParamType::kF16, "length"},
-        BuiltinData{core::BuiltinFn::kLog, CallParamType::kF32, "log"},
-        BuiltinData{core::BuiltinFn::kLog, CallParamType::kF16, "log"},
-        BuiltinData{core::BuiltinFn::kLog2, CallParamType::kF32, "log2"},
-        BuiltinData{core::BuiltinFn::kLog2, CallParamType::kF16, "log2"},
-        BuiltinData{core::BuiltinFn::kMax, CallParamType::kF32, "fmax"},
-        BuiltinData{core::BuiltinFn::kMax, CallParamType::kF16, "fmax"},
-        BuiltinData{core::BuiltinFn::kMin, CallParamType::kF32, "fmin"},
-        BuiltinData{core::BuiltinFn::kMin, CallParamType::kF16, "fmin"},
-        BuiltinData{core::BuiltinFn::kNormalize, CallParamType::kF32, "normalize"},
-        BuiltinData{core::BuiltinFn::kNormalize, CallParamType::kF16, "normalize"},
-        BuiltinData{core::BuiltinFn::kPow, CallParamType::kF32, "pow"},
-        BuiltinData{core::BuiltinFn::kPow, CallParamType::kF16, "pow"},
-        BuiltinData{core::BuiltinFn::kReflect, CallParamType::kF32, "reflect"},
-        BuiltinData{core::BuiltinFn::kReflect, CallParamType::kF16, "reflect"},
-        BuiltinData{core::BuiltinFn::kSign, CallParamType::kF32, "sign"},
-        BuiltinData{core::BuiltinFn::kSign, CallParamType::kF16, "sign"},
-        BuiltinData{core::BuiltinFn::kSin, CallParamType::kF32, "sin"},
-        BuiltinData{core::BuiltinFn::kSin, CallParamType::kF16, "sin"},
-        BuiltinData{core::BuiltinFn::kSinh, CallParamType::kF32, "sinh"},
-        BuiltinData{core::BuiltinFn::kSinh, CallParamType::kF16, "sinh"},
-        BuiltinData{core::BuiltinFn::kSmoothstep, CallParamType::kF32, "smoothstep"},
-        BuiltinData{core::BuiltinFn::kSmoothstep, CallParamType::kF16, "smoothstep"},
-        BuiltinData{core::BuiltinFn::kSqrt, CallParamType::kF32, "sqrt"},
-        BuiltinData{core::BuiltinFn::kSqrt, CallParamType::kF16, "sqrt"},
-        BuiltinData{core::BuiltinFn::kStep, CallParamType::kF32, "step"},
-        BuiltinData{core::BuiltinFn::kStep, CallParamType::kF16, "step"},
-        BuiltinData{core::BuiltinFn::kTan, CallParamType::kF32, "tan"},
-        BuiltinData{core::BuiltinFn::kTan, CallParamType::kF16, "tan"},
-        BuiltinData{core::BuiltinFn::kTanh, CallParamType::kF32, "tanh"},
-        BuiltinData{core::BuiltinFn::kTanh, CallParamType::kF16, "tanh"},
-        BuiltinData{core::BuiltinFn::kTrunc, CallParamType::kF32, "trunc"},
-        BuiltinData{core::BuiltinFn::kTrunc, CallParamType::kF16, "trunc"},
+        BuiltinData{wgsl::BuiltinFn::kAbs, CallParamType::kF32, "fabs"},
+        BuiltinData{wgsl::BuiltinFn::kAbs, CallParamType::kF16, "fabs"},
+        BuiltinData{wgsl::BuiltinFn::kAcos, CallParamType::kF32, "acos"},
+        BuiltinData{wgsl::BuiltinFn::kAcos, CallParamType::kF16, "acos"},
+        BuiltinData{wgsl::BuiltinFn::kAsin, CallParamType::kF32, "asin"},
+        BuiltinData{wgsl::BuiltinFn::kAsin, CallParamType::kF16, "asin"},
+        BuiltinData{wgsl::BuiltinFn::kAtan, CallParamType::kF32, "atan"},
+        BuiltinData{wgsl::BuiltinFn::kAtan, CallParamType::kF16, "atan"},
+        BuiltinData{wgsl::BuiltinFn::kAtan2, CallParamType::kF32, "atan2"},
+        BuiltinData{wgsl::BuiltinFn::kAtan2, CallParamType::kF16, "atan2"},
+        BuiltinData{wgsl::BuiltinFn::kCeil, CallParamType::kF32, "ceil"},
+        BuiltinData{wgsl::BuiltinFn::kCeil, CallParamType::kF16, "ceil"},
+        BuiltinData{wgsl::BuiltinFn::kClamp, CallParamType::kF32, "clamp"},
+        BuiltinData{wgsl::BuiltinFn::kClamp, CallParamType::kF16, "clamp"},
+        BuiltinData{wgsl::BuiltinFn::kCos, CallParamType::kF32, "cos"},
+        BuiltinData{wgsl::BuiltinFn::kCos, CallParamType::kF16, "cos"},
+        BuiltinData{wgsl::BuiltinFn::kCosh, CallParamType::kF32, "cosh"},
+        BuiltinData{wgsl::BuiltinFn::kCosh, CallParamType::kF16, "cosh"},
+        BuiltinData{wgsl::BuiltinFn::kCross, CallParamType::kF32, "cross"},
+        BuiltinData{wgsl::BuiltinFn::kCross, CallParamType::kF16, "cross"},
+        BuiltinData{wgsl::BuiltinFn::kDistance, CallParamType::kF32, "distance"},
+        BuiltinData{wgsl::BuiltinFn::kDistance, CallParamType::kF16, "distance"},
+        BuiltinData{wgsl::BuiltinFn::kExp, CallParamType::kF32, "exp"},
+        BuiltinData{wgsl::BuiltinFn::kExp, CallParamType::kF16, "exp"},
+        BuiltinData{wgsl::BuiltinFn::kExp2, CallParamType::kF32, "exp2"},
+        BuiltinData{wgsl::BuiltinFn::kExp2, CallParamType::kF16, "exp2"},
+        BuiltinData{wgsl::BuiltinFn::kFaceForward, CallParamType::kF32, "faceforward"},
+        BuiltinData{wgsl::BuiltinFn::kFaceForward, CallParamType::kF16, "faceforward"},
+        BuiltinData{wgsl::BuiltinFn::kFloor, CallParamType::kF32, "floor"},
+        BuiltinData{wgsl::BuiltinFn::kFloor, CallParamType::kF16, "floor"},
+        BuiltinData{wgsl::BuiltinFn::kFma, CallParamType::kF32, "fma"},
+        BuiltinData{wgsl::BuiltinFn::kFma, CallParamType::kF16, "fma"},
+        BuiltinData{wgsl::BuiltinFn::kFract, CallParamType::kF32, "fract"},
+        BuiltinData{wgsl::BuiltinFn::kFract, CallParamType::kF16, "fract"},
+        BuiltinData{wgsl::BuiltinFn::kInverseSqrt, CallParamType::kF32, "rsqrt"},
+        BuiltinData{wgsl::BuiltinFn::kInverseSqrt, CallParamType::kF16, "rsqrt"},
+        BuiltinData{wgsl::BuiltinFn::kLdexp, CallParamType::kF32, "ldexp"},
+        BuiltinData{wgsl::BuiltinFn::kLdexp, CallParamType::kF16, "ldexp"},
+        BuiltinData{wgsl::BuiltinFn::kLength, CallParamType::kF32, "length"},
+        BuiltinData{wgsl::BuiltinFn::kLength, CallParamType::kF16, "length"},
+        BuiltinData{wgsl::BuiltinFn::kLog, CallParamType::kF32, "log"},
+        BuiltinData{wgsl::BuiltinFn::kLog, CallParamType::kF16, "log"},
+        BuiltinData{wgsl::BuiltinFn::kLog2, CallParamType::kF32, "log2"},
+        BuiltinData{wgsl::BuiltinFn::kLog2, CallParamType::kF16, "log2"},
+        BuiltinData{wgsl::BuiltinFn::kMax, CallParamType::kF32, "fmax"},
+        BuiltinData{wgsl::BuiltinFn::kMax, CallParamType::kF16, "fmax"},
+        BuiltinData{wgsl::BuiltinFn::kMin, CallParamType::kF32, "fmin"},
+        BuiltinData{wgsl::BuiltinFn::kMin, CallParamType::kF16, "fmin"},
+        BuiltinData{wgsl::BuiltinFn::kNormalize, CallParamType::kF32, "normalize"},
+        BuiltinData{wgsl::BuiltinFn::kNormalize, CallParamType::kF16, "normalize"},
+        BuiltinData{wgsl::BuiltinFn::kPow, CallParamType::kF32, "pow"},
+        BuiltinData{wgsl::BuiltinFn::kPow, CallParamType::kF16, "pow"},
+        BuiltinData{wgsl::BuiltinFn::kReflect, CallParamType::kF32, "reflect"},
+        BuiltinData{wgsl::BuiltinFn::kReflect, CallParamType::kF16, "reflect"},
+        BuiltinData{wgsl::BuiltinFn::kSign, CallParamType::kF32, "sign"},
+        BuiltinData{wgsl::BuiltinFn::kSign, CallParamType::kF16, "sign"},
+        BuiltinData{wgsl::BuiltinFn::kSin, CallParamType::kF32, "sin"},
+        BuiltinData{wgsl::BuiltinFn::kSin, CallParamType::kF16, "sin"},
+        BuiltinData{wgsl::BuiltinFn::kSinh, CallParamType::kF32, "sinh"},
+        BuiltinData{wgsl::BuiltinFn::kSinh, CallParamType::kF16, "sinh"},
+        BuiltinData{wgsl::BuiltinFn::kSmoothstep, CallParamType::kF32, "smoothstep"},
+        BuiltinData{wgsl::BuiltinFn::kSmoothstep, CallParamType::kF16, "smoothstep"},
+        BuiltinData{wgsl::BuiltinFn::kSqrt, CallParamType::kF32, "sqrt"},
+        BuiltinData{wgsl::BuiltinFn::kSqrt, CallParamType::kF16, "sqrt"},
+        BuiltinData{wgsl::BuiltinFn::kStep, CallParamType::kF32, "step"},
+        BuiltinData{wgsl::BuiltinFn::kStep, CallParamType::kF16, "step"},
+        BuiltinData{wgsl::BuiltinFn::kTan, CallParamType::kF32, "tan"},
+        BuiltinData{wgsl::BuiltinFn::kTan, CallParamType::kF16, "tan"},
+        BuiltinData{wgsl::BuiltinFn::kTanh, CallParamType::kF32, "tanh"},
+        BuiltinData{wgsl::BuiltinFn::kTanh, CallParamType::kF16, "tanh"},
+        BuiltinData{wgsl::BuiltinFn::kTrunc, CallParamType::kF32, "trunc"},
+        BuiltinData{wgsl::BuiltinFn::kTrunc, CallParamType::kF16, "trunc"},
         /* Integer built-in */
-        BuiltinData{core::BuiltinFn::kAbs, CallParamType::kU32, "abs"},
-        BuiltinData{core::BuiltinFn::kClamp, CallParamType::kU32, "clamp"},
-        BuiltinData{core::BuiltinFn::kCountLeadingZeros, CallParamType::kU32, "clz"},
-        BuiltinData{core::BuiltinFn::kCountOneBits, CallParamType::kU32, "popcount"},
-        BuiltinData{core::BuiltinFn::kCountTrailingZeros, CallParamType::kU32, "ctz"},
-        BuiltinData{core::BuiltinFn::kExtractBits, CallParamType::kU32, "extract_bits"},
-        BuiltinData{core::BuiltinFn::kInsertBits, CallParamType::kU32, "insert_bits"},
-        BuiltinData{core::BuiltinFn::kMax, CallParamType::kU32, "max"},
-        BuiltinData{core::BuiltinFn::kMin, CallParamType::kU32, "min"},
-        BuiltinData{core::BuiltinFn::kReverseBits, CallParamType::kU32, "reverse_bits"},
-        BuiltinData{core::BuiltinFn::kRound, CallParamType::kU32, "rint"},
+        BuiltinData{wgsl::BuiltinFn::kAbs, CallParamType::kU32, "abs"},
+        BuiltinData{wgsl::BuiltinFn::kClamp, CallParamType::kU32, "clamp"},
+        BuiltinData{wgsl::BuiltinFn::kCountLeadingZeros, CallParamType::kU32, "clz"},
+        BuiltinData{wgsl::BuiltinFn::kCountOneBits, CallParamType::kU32, "popcount"},
+        BuiltinData{wgsl::BuiltinFn::kCountTrailingZeros, CallParamType::kU32, "ctz"},
+        BuiltinData{wgsl::BuiltinFn::kExtractBits, CallParamType::kU32, "extract_bits"},
+        BuiltinData{wgsl::BuiltinFn::kInsertBits, CallParamType::kU32, "insert_bits"},
+        BuiltinData{wgsl::BuiltinFn::kMax, CallParamType::kU32, "max"},
+        BuiltinData{wgsl::BuiltinFn::kMin, CallParamType::kU32, "min"},
+        BuiltinData{wgsl::BuiltinFn::kReverseBits, CallParamType::kU32, "reverse_bits"},
+        BuiltinData{wgsl::BuiltinFn::kRound, CallParamType::kU32, "rint"},
         /* Matrix built-in */
-        BuiltinData{core::BuiltinFn::kDeterminant, CallParamType::kF32, "determinant"},
-        BuiltinData{core::BuiltinFn::kTranspose, CallParamType::kF32, "transpose"},
+        BuiltinData{wgsl::BuiltinFn::kDeterminant, CallParamType::kF32, "determinant"},
+        BuiltinData{wgsl::BuiltinFn::kTranspose, CallParamType::kF32, "transpose"},
         /* Vector built-in */
-        BuiltinData{core::BuiltinFn::kDot, CallParamType::kF32, "dot"},
+        BuiltinData{wgsl::BuiltinFn::kDot, CallParamType::kF32, "dot"},
         /* Derivate built-in */
-        BuiltinData{core::BuiltinFn::kDpdx, CallParamType::kF32, "dfdx"},
-        BuiltinData{core::BuiltinFn::kDpdxCoarse, CallParamType::kF32, "dfdx"},
-        BuiltinData{core::BuiltinFn::kDpdxFine, CallParamType::kF32, "dfdx"},
-        BuiltinData{core::BuiltinFn::kDpdy, CallParamType::kF32, "dfdy"},
-        BuiltinData{core::BuiltinFn::kDpdyCoarse, CallParamType::kF32, "dfdy"},
-        BuiltinData{core::BuiltinFn::kDpdyFine, CallParamType::kF32, "dfdy"},
-        BuiltinData{core::BuiltinFn::kFwidth, CallParamType::kF32, "fwidth"},
-        BuiltinData{core::BuiltinFn::kFwidthCoarse, CallParamType::kF32, "fwidth"},
-        BuiltinData{core::BuiltinFn::kFwidthFine, CallParamType::kF32, "fwidth"},
+        BuiltinData{wgsl::BuiltinFn::kDpdx, CallParamType::kF32, "dfdx"},
+        BuiltinData{wgsl::BuiltinFn::kDpdxCoarse, CallParamType::kF32, "dfdx"},
+        BuiltinData{wgsl::BuiltinFn::kDpdxFine, CallParamType::kF32, "dfdx"},
+        BuiltinData{wgsl::BuiltinFn::kDpdy, CallParamType::kF32, "dfdy"},
+        BuiltinData{wgsl::BuiltinFn::kDpdyCoarse, CallParamType::kF32, "dfdy"},
+        BuiltinData{wgsl::BuiltinFn::kDpdyFine, CallParamType::kF32, "dfdy"},
+        BuiltinData{wgsl::BuiltinFn::kFwidth, CallParamType::kF32, "fwidth"},
+        BuiltinData{wgsl::BuiltinFn::kFwidthCoarse, CallParamType::kF32, "fwidth"},
+        BuiltinData{wgsl::BuiltinFn::kFwidthFine, CallParamType::kF32, "fwidth"},
         /* Data packing builtin */
-        BuiltinData{core::BuiltinFn::kPack4X8Snorm, CallParamType::kF32, "pack_float_to_snorm4x8"},
-        BuiltinData{core::BuiltinFn::kPack4X8Unorm, CallParamType::kF32, "pack_float_to_unorm4x8"},
-        BuiltinData{core::BuiltinFn::kPack2X16Snorm, CallParamType::kF32,
+        BuiltinData{wgsl::BuiltinFn::kPack4X8Snorm, CallParamType::kF32, "pack_float_to_snorm4x8"},
+        BuiltinData{wgsl::BuiltinFn::kPack4X8Unorm, CallParamType::kF32, "pack_float_to_unorm4x8"},
+        BuiltinData{wgsl::BuiltinFn::kPack2X16Snorm, CallParamType::kF32,
                     "pack_float_to_snorm2x16"},
-        BuiltinData{core::BuiltinFn::kPack2X16Unorm, CallParamType::kF32,
+        BuiltinData{wgsl::BuiltinFn::kPack2X16Unorm, CallParamType::kF32,
                     "pack_float_to_unorm2x16"},
         /* Data unpacking builtin */
-        BuiltinData{core::BuiltinFn::kUnpack4X8Snorm, CallParamType::kU32,
+        BuiltinData{wgsl::BuiltinFn::kUnpack4X8Snorm, CallParamType::kU32,
                     "unpack_snorm4x8_to_float"},
-        BuiltinData{core::BuiltinFn::kUnpack4X8Unorm, CallParamType::kU32,
+        BuiltinData{wgsl::BuiltinFn::kUnpack4X8Unorm, CallParamType::kU32,
                     "unpack_unorm4x8_to_float"},
-        BuiltinData{core::BuiltinFn::kUnpack2X16Snorm, CallParamType::kU32,
+        BuiltinData{wgsl::BuiltinFn::kUnpack2X16Snorm, CallParamType::kU32,
                     "unpack_snorm2x16_to_float"},
-        BuiltinData{core::BuiltinFn::kUnpack2X16Unorm, CallParamType::kU32,
+        BuiltinData{wgsl::BuiltinFn::kUnpack2X16Unorm, CallParamType::kU32,
                     "unpack_unorm2x16_to_float"}));
 
 TEST_F(MslASTPrinterTest, Builtin_Call) {
diff --git a/src/tint/lang/msl/writer/ast_raise/BUILD.bazel b/src/tint/lang/msl/writer/ast_raise/BUILD.bazel
index e2b25c8..5a68d70 100644
--- a/src/tint/lang/msl/writer/ast_raise/BUILD.bazel
+++ b/src/tint/lang/msl/writer/ast_raise/BUILD.bazel
@@ -78,6 +78,7 @@
     "//src/tint/api/common",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
diff --git a/src/tint/lang/msl/writer/ast_raise/BUILD.cmake b/src/tint/lang/msl/writer/ast_raise/BUILD.cmake
index 54b8337..386768b 100644
--- a/src/tint/lang/msl/writer/ast_raise/BUILD.cmake
+++ b/src/tint/lang/msl/writer/ast_raise/BUILD.cmake
@@ -82,6 +82,7 @@
   tint_api_common
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
diff --git a/src/tint/lang/msl/writer/ast_raise/BUILD.gn b/src/tint/lang/msl/writer/ast_raise/BUILD.gn
index bb16eaa..cf231b6 100644
--- a/src/tint/lang/msl/writer/ast_raise/BUILD.gn
+++ b/src/tint/lang/msl/writer/ast_raise/BUILD.gn
@@ -82,6 +82,7 @@
         "${tint_src_dir}/api/common",
         "${tint_src_dir}/lang/core",
         "${tint_src_dir}/lang/core/constant",
+        "${tint_src_dir}/lang/core/ir",
         "${tint_src_dir}/lang/core/type",
         "${tint_src_dir}/lang/wgsl",
         "${tint_src_dir}/lang/wgsl/ast",
diff --git a/src/tint/lang/msl/writer/ast_raise/subgroup_ballot.cc b/src/tint/lang/msl/writer/ast_raise/subgroup_ballot.cc
index f977803..32f8b51 100644
--- a/src/tint/lang/msl/writer/ast_raise/subgroup_ballot.cc
+++ b/src/tint/lang/msl/writer/ast_raise/subgroup_ballot.cc
@@ -66,7 +66,7 @@
                 // If this is a call to a `subgroupBallot()` builtin, replace it with a call to the
                 // helper function and make a note of the function that we are in.
                 auto* builtin = call->Target()->As<sem::BuiltinFn>();
-                if (builtin && builtin->Fn() == core::BuiltinFn::kSubgroupBallot) {
+                if (builtin && builtin->Fn() == wgsl::BuiltinFn::kSubgroupBallot) {
                     ctx.Replace(call->Declaration(), b.Call(GetHelper()));
                     ballot_callers.Add(call->Stmt()->Function());
                     made_changes = true;
diff --git a/src/tint/lang/msl/writer/common/options.h b/src/tint/lang/msl/writer/common/options.h
index 763b1d3..597e5c7 100644
--- a/src/tint/lang/msl/writer/common/options.h
+++ b/src/tint/lang/msl/writer/common/options.h
@@ -38,6 +38,16 @@
     /// Set to `true` to disable software robustness that prevents out-of-bounds accesses.
     bool disable_robustness = false;
 
+    /// Set to `true` to disable workgroup memory zero initialization
+    bool disable_workgroup_init = false;
+
+    /// Set to `true` to generate a [[point_size]] attribute which is set to 1.0
+    /// for all vertex shaders in the module.
+    bool emit_vertex_point_size = false;
+
+    /// Set to `true` to generate MSL via the Tint IR instead of from the AST.
+    bool use_tint_ir = false;
+
     /// The index to use when generating a UBO to receive storage buffer sizes.
     /// Defaults to 30, which is the last valid buffer slot.
     uint32_t buffer_size_ubo_index = 30;
@@ -46,39 +56,30 @@
     /// Defaults to 0xFFFFFFFF.
     uint32_t fixed_sample_mask = 0xFFFFFFFF;
 
-    /// Set to `true` to generate a [[point_size]] attribute which is set to 1.0
-    /// for all vertex shaders in the module.
-    bool emit_vertex_point_size = false;
-
-    /// Set to `true` to disable workgroup memory zero initialization
-    bool disable_workgroup_init = false;
-
     /// Options used for dealing with pixel local storage
     PixelLocalOptions pixel_local_options = {};
 
-    /// Options used in the binding mappings for external textures
-    ExternalTextureOptions external_texture_options = {};
-
     /// Options used to specify a mapping of binding points to indices into a UBO
     /// from which to load buffer sizes.
     ArrayLengthFromUniformOptions array_length_from_uniform = {};
 
+    /// Options used in the binding mappings for external textures
+    ExternalTextureOptions external_texture_options = {};
+
     /// Options used in the bindings remapper
     BindingRemapperOptions binding_remapper_options = {};
 
-    /// Set to `true` to generate MSL via the Tint IR instead of from the AST.
-    bool use_tint_ir = false;
-
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
     TINT_REFLECT(disable_robustness,
+                 disable_workgroup_init,
+                 emit_vertex_point_size,
+                 use_tint_ir,
                  buffer_size_ubo_index,
                  fixed_sample_mask,
-                 emit_vertex_point_size,
-                 disable_workgroup_init,
-                 external_texture_options,
+                 pixel_local_options,
                  array_length_from_uniform,
-                 binding_remapper_options,
-                 use_tint_ir);
+                 external_texture_options,
+                 binding_remapper_options);
 };
 
 }  // namespace tint::msl::writer
diff --git a/src/tint/lang/msl/writer/printer/helper_test.h b/src/tint/lang/msl/writer/printer/helper_test.h
index 00d1d85..0214845 100644
--- a/src/tint/lang/msl/writer/printer/helper_test.h
+++ b/src/tint/lang/msl/writer/printer/helper_test.h
@@ -48,7 +48,7 @@
 template <typename BASE>
 class MslPrinterTestHelperBase : public BASE {
   public:
-    MslPrinterTestHelperBase() : writer_(&mod) {}
+    MslPrinterTestHelperBase() : writer_(mod) {}
 
     /// The test module.
     core::ir::Module mod;
@@ -70,15 +70,15 @@
     /// Run the writer on the IR module and validate the result.
     /// @returns true if generation and validation succeeded
     bool Generate() {
-        auto raised = raise::Raise(&mod);
+        auto raised = raise::Raise(mod);
         if (!raised) {
-            err_ = raised.Failure();
+            err_ = raised.Failure().reason.str();
             return false;
         }
 
         auto result = writer_.Generate();
         if (!result) {
-            err_ = result.Failure();
+            err_ = result.Failure().reason.str();
             return false;
         }
         output_ = writer_.Result();
diff --git a/src/tint/lang/msl/writer/printer/printer.cc b/src/tint/lang/msl/writer/printer/printer.cc
index 77f12e3..46d02c5 100644
--- a/src/tint/lang/msl/writer/printer/printer.cc
+++ b/src/tint/lang/msl/writer/printer/printer.cc
@@ -63,12 +63,12 @@
     TINT_UNIMPLEMENTED() << "unhandled case in Switch(): " \
                          << (object_ptr ? object_ptr->TypeInfo().name : "<null>")
 
-Printer::Printer(core::ir::Module* module) : ir_(module) {}
+Printer::Printer(core::ir::Module& module) : ir_(module) {}
 
 Printer::~Printer() = default;
 
-tint::Result<SuccessType, std::string> Printer::Generate() {
-    auto valid = core::ir::ValidateAndDumpIfNeeded(*ir_, "MSL writer");
+tint::Result<SuccessType> Printer::Generate() {
+    auto valid = core::ir::ValidateAndDumpIfNeeded(ir_, "MSL writer");
     if (!valid) {
         return std::move(valid.Failure());
     }
@@ -80,12 +80,10 @@
     }
 
     // Emit module-scope declarations.
-    if (ir_->root_block) {
-        EmitBlockInstructions(ir_->root_block);
-    }
+    EmitBlockInstructions(ir_.root_block);
 
     // Emit functions.
-    for (auto* func : ir_->functions) {
+    for (auto* func : ir_.functions) {
         EmitFunction(func);
     }
 
@@ -135,7 +133,7 @@
         // TODO(dsinclair): Handle return type attributes
 
         EmitType(out, func->ReturnType());
-        out << " " << ir_->NameOf(func).Name() << "() {";
+        out << " " << ir_.NameOf(func).Name() << "() {";
 
         // TODO(dsinclair): Emit Function parameters
     }
@@ -252,7 +250,7 @@
             return;
     }
 
-    auto name = ir_->NameOf(v);
+    auto name = ir_.NameOf(v);
 
     EmitType(out, ptr->UnwrapPtr());
     out << " " << name.Name();
@@ -276,11 +274,11 @@
 void Printer::EmitIf(core::ir::If* if_) {
     // Emit any nodes that need to be used as PHI nodes
     for (auto* phi : if_->Results()) {
-        if (!ir_->NameOf(phi).IsValid()) {
-            ir_->SetName(phi, ir_->symbols.New());
+        if (!ir_.NameOf(phi).IsValid()) {
+            ir_.SetName(phi, ir_.symbols.New());
         }
 
-        auto name = ir_->NameOf(phi);
+        auto name = ir_.NameOf(phi);
 
         auto out = Line();
         EmitType(out, phi->Type());
@@ -313,7 +311,7 @@
         auto* phi = results[i];
         auto* val = args[i];
 
-        Line() << ir_->NameOf(phi).Name() << " = " << Expr(val) << ";";
+        Line() << ir_.NameOf(phi).Name() << " = " << Expr(val) << ";";
     }
 }
 
@@ -531,7 +529,7 @@
         std::string name;
         do {
             name = UniqueIdentifier("tint_pad");
-        } while (str->FindMember(ir_->symbols.Get(name)));
+        } while (str->FindMember(ir_.symbols.Get(name)));
 
         auto out = Line(&str_buf);
         add_byte_offset_comment(out, msl_offset);
@@ -743,7 +741,7 @@
 }
 
 std::string Printer::UniqueIdentifier(const std::string& prefix /* = "" */) {
-    return ir_->symbols.New(prefix).Name();
+    return ir_.symbols.New(prefix).Name();
 }
 
 TINT_BEGIN_DISABLE_WARNING(UNREACHABLE_CODE);
@@ -825,12 +823,12 @@
             return;
         }
     } else {
-        auto mod_name = ir_->NameOf(value);
+        auto mod_name = ir_.NameOf(value);
         if (value->Usages().IsEmpty() && !mod_name.IsValid()) {
             // Drop phonies.
         } else {
             if (mod_name.Name().empty()) {
-                mod_name = ir_->symbols.New("v");
+                mod_name = ir_.symbols.New("v");
             }
 
             auto out = Line();
@@ -879,7 +877,7 @@
         auto* result = inst->Result();
         // Only values with a single usage can be inlined.
         // Named values are not inlined, as we want to emit the name for a let.
-        if (result->Usages().Count() == 1 && !ir_->NameOf(result).IsValid()) {
+        if (result->Usages().Count() == 1 && !ir_.NameOf(result).IsValid()) {
             if (sequenced) {
                 // The value comes from a sequenced instruction.  Don't inline.
             } else {
diff --git a/src/tint/lang/msl/writer/printer/printer.h b/src/tint/lang/msl/writer/printer/printer.h
index 6b395cf..5b6d2e4 100644
--- a/src/tint/lang/msl/writer/printer/printer.h
+++ b/src/tint/lang/msl/writer/printer/printer.h
@@ -44,11 +44,11 @@
   public:
     /// Constructor
     /// @param module the Tint IR module to generate
-    explicit Printer(core::ir::Module* module);
+    explicit Printer(core::ir::Module& module);
     ~Printer() override;
 
-    /// @returns true on successful generation; false otherwise
-    tint::Result<SuccessType, std::string> Generate();
+    /// @returns success or failure
+    tint::Result<SuccessType> Generate();
 
     /// @copydoc tint::TextGenerator::Result
     std::string Result() const override;
@@ -162,7 +162,7 @@
     /// Map of builtin structure to unique generated name
     std::unordered_map<const core::type::Struct*, std::string> builtin_struct_names_;
 
-    core::ir::Module* const ir_;
+    core::ir::Module& ir_;
 
     /// The buffer holding preamble text
     TextBuffer preamble_buffer_;
diff --git a/src/tint/lang/msl/writer/printer/var_test.cc b/src/tint/lang/msl/writer/printer/var_test.cc
index ce8b498..d6af346 100644
--- a/src/tint/lang/msl/writer/printer/var_test.cc
+++ b/src/tint/lang/msl/writer/printer/var_test.cc
@@ -237,7 +237,7 @@
 // TODO(dsinclair): Requires ModuleScopeVarToEntryPointParam transform
 TEST_F(MslPrinterTest, DISABLED_VarGlobalPrivate) {
     core::ir::Var* v = nullptr;
-    b.Append(b.RootBlock(), [&] { v = b.Var("v", ty.ptr<core::AddressSpace::kPrivate, f32>()); });
+    b.Append(mod.root_block, [&] { v = b.Var("v", ty.ptr<core::AddressSpace::kPrivate, f32>()); });
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
@@ -263,7 +263,8 @@
 
 TEST_F(MslPrinterTest, VarGlobalWorkgroup) {
     core::ir::Var* v = nullptr;
-    b.Append(b.RootBlock(), [&] { v = b.Var("v", ty.ptr<core::AddressSpace::kWorkgroup, f32>()); });
+    b.Append(mod.root_block,
+             [&] { v = b.Var("v", ty.ptr<core::AddressSpace::kWorkgroup, f32>()); });
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
diff --git a/src/tint/lang/msl/writer/raise/BUILD.bazel b/src/tint/lang/msl/writer/raise/BUILD.bazel
index ca4cf5b..aca5d79 100644
--- a/src/tint/lang/msl/writer/raise/BUILD.bazel
+++ b/src/tint/lang/msl/writer/raise/BUILD.bazel
@@ -32,9 +32,14 @@
     "raise.h",
   ],
   deps = [
+    "//src/tint/utils/containers",
+    "//src/tint/utils/diagnostic",
     "//src/tint/utils/ice",
     "//src/tint/utils/macros",
+    "//src/tint/utils/math",
+    "//src/tint/utils/memory",
     "//src/tint/utils/result",
+    "//src/tint/utils/rtti",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
   ],
diff --git a/src/tint/lang/msl/writer/raise/BUILD.cmake b/src/tint/lang/msl/writer/raise/BUILD.cmake
index 86f9826..6d3ab0e 100644
--- a/src/tint/lang/msl/writer/raise/BUILD.cmake
+++ b/src/tint/lang/msl/writer/raise/BUILD.cmake
@@ -31,9 +31,14 @@
 )
 
 tint_target_add_dependencies(tint_lang_msl_writer_raise lib
+  tint_utils_containers
+  tint_utils_diagnostic
   tint_utils_ice
   tint_utils_macros
+  tint_utils_math
+  tint_utils_memory
   tint_utils_result
+  tint_utils_rtti
   tint_utils_text
   tint_utils_traits
 )
diff --git a/src/tint/lang/msl/writer/raise/BUILD.gn b/src/tint/lang/msl/writer/raise/BUILD.gn
index c2bcce9..b03edf1 100644
--- a/src/tint/lang/msl/writer/raise/BUILD.gn
+++ b/src/tint/lang/msl/writer/raise/BUILD.gn
@@ -31,9 +31,14 @@
     "raise.h",
   ]
   deps = [
+    "${tint_src_dir}/utils/containers",
+    "${tint_src_dir}/utils/diagnostic",
     "${tint_src_dir}/utils/ice",
     "${tint_src_dir}/utils/macros",
+    "${tint_src_dir}/utils/math",
+    "${tint_src_dir}/utils/memory",
     "${tint_src_dir}/utils/result",
+    "${tint_src_dir}/utils/rtti",
     "${tint_src_dir}/utils/text",
     "${tint_src_dir}/utils/traits",
   ]
diff --git a/src/tint/lang/msl/writer/raise/raise.cc b/src/tint/lang/msl/writer/raise/raise.cc
index efd0332..9190f0d 100644
--- a/src/tint/lang/msl/writer/raise/raise.cc
+++ b/src/tint/lang/msl/writer/raise/raise.cc
@@ -18,7 +18,7 @@
 
 namespace tint::msl::raise {
 
-Result<SuccessType, std::string> Raise(core::ir::Module*) {
+Result<SuccessType> Raise(core::ir::Module&) {
     // #define RUN_TRANSFORM(name)
     //     do {
     //         auto result = core::ir::transform::name(module);
diff --git a/src/tint/lang/msl/writer/raise/raise.h b/src/tint/lang/msl/writer/raise/raise.h
index bb668e7..0da1f45 100644
--- a/src/tint/lang/msl/writer/raise/raise.h
+++ b/src/tint/lang/msl/writer/raise/raise.h
@@ -17,6 +17,7 @@
 
 #include <string>
 
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward declarations
@@ -28,8 +29,8 @@
 
 /// Raise a core IR module to the MSL dialect of the IR.
 /// @param mod the core IR module to raise to MSL dialect
-/// @returns success or an error string
-Result<SuccessType, std::string> Raise(core::ir::Module* mod);
+/// @returns success or failure
+Result<SuccessType> Raise(core::ir::Module& mod);
 
 }  // namespace tint::msl::raise
 
diff --git a/src/tint/lang/msl/writer/writer.cc b/src/tint/lang/msl/writer/writer.cc
index 088d81d..aa69687 100644
--- a/src/tint/lang/msl/writer/writer.cc
+++ b/src/tint/lang/msl/writer/writer.cc
@@ -24,9 +24,9 @@
 
 namespace tint::msl::writer {
 
-Result<Output, std::string> Generate(const Program& program, const Options& options) {
+Result<Output> Generate(const Program& program, const Options& options) {
     if (!program.IsValid()) {
-        return std::string("input program is not valid");
+        return Failure{program.Diagnostics()};
     }
 
     Output output;
@@ -35,19 +35,19 @@
         // Convert the AST program to an IR module.
         auto converted = wgsl::reader::ProgramToIR(program);
         if (!converted) {
-            return std::string("IR converter: " + converted.Failure());
+            return converted.Failure();
         }
 
         auto ir = converted.Move();
 
         // Raise the IR to the MSL dialect.
-        auto raised = raise::Raise(&ir);
+        auto raised = raise::Raise(ir);
         if (!raised) {
-            return std::move(raised.Failure());
+            return raised.Failure();
         }
 
         // Generate the MSL code.
-        auto impl = std::make_unique<Printer>(&ir);
+        auto impl = std::make_unique<Printer>(ir);
         auto result = impl->Generate();
         if (!result) {
             return result.Failure();
@@ -57,7 +57,7 @@
         // Sanitize the program.
         auto sanitized_result = Sanitize(program, options);
         if (!sanitized_result.program.IsValid()) {
-            return sanitized_result.program.Diagnostics().str();
+            return Failure{sanitized_result.program.Diagnostics()};
         }
         output.needs_storage_buffer_sizes = sanitized_result.needs_storage_buffer_sizes;
         output.used_array_length_from_uniform_indices =
@@ -66,7 +66,7 @@
         // Generate the MSL code.
         auto impl = std::make_unique<ASTPrinter>(sanitized_result.program);
         if (!impl->Generate()) {
-            return impl->Diagnostics().str();
+            return Failure{impl->Diagnostics()};
         }
         output.msl = impl->Result();
         output.has_invariant_attribute = impl->HasInvariant();
diff --git a/src/tint/lang/msl/writer/writer.h b/src/tint/lang/msl/writer/writer.h
index c0ada69..28457c1 100644
--- a/src/tint/lang/msl/writer/writer.h
+++ b/src/tint/lang/msl/writer/writer.h
@@ -19,6 +19,7 @@
 
 #include "src/tint/lang/msl/writer/common/options.h"
 #include "src/tint/lang/msl/writer/output.h"
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward declarations
@@ -29,11 +30,11 @@
 namespace tint::msl::writer {
 
 /// Generate MSL for a program, according to a set of configuration options.
-/// The result will contain the MSL and supplementary information, or an error string.
+/// The result will contain the MSL and supplementary information, or failure.
 /// @param program the program to translate to MSL
 /// @param options the configuration options to use when generating MSL
-/// @returns the resulting MSL and supplementary information, or an error string
-Result<Output, std::string> Generate(const Program& program, const Options& options);
+/// @returns the resulting MSL and supplementary information, or failure
+Result<Output> Generate(const Program& program, const Options& options);
 
 }  // namespace tint::msl::writer
 
diff --git a/src/tint/lang/msl/writer/writer_bench.cc b/src/tint/lang/msl/writer/writer_bench.cc
index beeec4d..aa04473 100644
--- a/src/tint/lang/msl/writer/writer_bench.cc
+++ b/src/tint/lang/msl/writer/writer_bench.cc
@@ -63,7 +63,7 @@
     for (auto _ : state) {
         auto res = Generate(program, gen_options);
         if (!res) {
-            state.SkipWithError(res.Failure().c_str());
+            state.SkipWithError(res.Failure().reason.str());
         }
     }
 }
diff --git a/src/tint/lang/spirv/builtin_fn.cc b/src/tint/lang/spirv/builtin_fn.cc
index dbf99a9..602d0aa 100644
--- a/src/tint/lang/spirv/builtin_fn.cc
+++ b/src/tint/lang/spirv/builtin_fn.cc
@@ -30,71 +30,71 @@
         case BuiltinFn::kNone:
             return "<none>";
         case BuiltinFn::kArrayLength:
-            return "spirv.array_length";
+            return "array_length";
         case BuiltinFn::kAtomicAnd:
-            return "spirv.atomic_and";
+            return "atomic_and";
         case BuiltinFn::kAtomicCompareExchange:
-            return "spirv.atomic_compare_exchange";
+            return "atomic_compare_exchange";
         case BuiltinFn::kAtomicExchange:
-            return "spirv.atomic_exchange";
+            return "atomic_exchange";
         case BuiltinFn::kAtomicIadd:
-            return "spirv.atomic_iadd";
+            return "atomic_iadd";
         case BuiltinFn::kAtomicIsub:
-            return "spirv.atomic_isub";
+            return "atomic_isub";
         case BuiltinFn::kAtomicLoad:
-            return "spirv.atomic_load";
+            return "atomic_load";
         case BuiltinFn::kAtomicOr:
-            return "spirv.atomic_or";
+            return "atomic_or";
         case BuiltinFn::kAtomicSmax:
-            return "spirv.atomic_smax";
+            return "atomic_smax";
         case BuiltinFn::kAtomicSmin:
-            return "spirv.atomic_smin";
+            return "atomic_smin";
         case BuiltinFn::kAtomicStore:
-            return "spirv.atomic_store";
+            return "atomic_store";
         case BuiltinFn::kAtomicUmax:
-            return "spirv.atomic_umax";
+            return "atomic_umax";
         case BuiltinFn::kAtomicUmin:
-            return "spirv.atomic_umin";
+            return "atomic_umin";
         case BuiltinFn::kAtomicXor:
-            return "spirv.atomic_xor";
+            return "atomic_xor";
         case BuiltinFn::kDot:
-            return "spirv.dot";
+            return "dot";
         case BuiltinFn::kImageDrefGather:
-            return "spirv.image_dref_gather";
+            return "image_dref_gather";
         case BuiltinFn::kImageFetch:
-            return "spirv.image_fetch";
+            return "image_fetch";
         case BuiltinFn::kImageGather:
-            return "spirv.image_gather";
+            return "image_gather";
         case BuiltinFn::kImageQuerySize:
-            return "spirv.image_query_size";
+            return "image_query_size";
         case BuiltinFn::kImageQuerySizeLod:
-            return "spirv.image_query_size_lod";
+            return "image_query_size_lod";
         case BuiltinFn::kImageRead:
-            return "spirv.image_read";
+            return "image_read";
         case BuiltinFn::kImageSampleImplicitLod:
-            return "spirv.image_sample_implicit_lod";
+            return "image_sample_implicit_lod";
         case BuiltinFn::kImageSampleExplicitLod:
-            return "spirv.image_sample_explicit_lod";
+            return "image_sample_explicit_lod";
         case BuiltinFn::kImageSampleDrefImplicitLod:
-            return "spirv.image_sample_dref_implicit_lod";
+            return "image_sample_dref_implicit_lod";
         case BuiltinFn::kImageSampleDrefExplicitLod:
-            return "spirv.image_sample_dref_explicit_lod";
+            return "image_sample_dref_explicit_lod";
         case BuiltinFn::kImageWrite:
-            return "spirv.image_write";
+            return "image_write";
         case BuiltinFn::kMatrixTimesMatrix:
-            return "spirv.matrix_times_matrix";
+            return "matrix_times_matrix";
         case BuiltinFn::kMatrixTimesScalar:
-            return "spirv.matrix_times_scalar";
+            return "matrix_times_scalar";
         case BuiltinFn::kMatrixTimesVector:
-            return "spirv.matrix_times_vector";
+            return "matrix_times_vector";
         case BuiltinFn::kSampledImage:
-            return "spirv.sampled_image";
+            return "sampled_image";
         case BuiltinFn::kSelect:
-            return "spirv.select";
+            return "select";
         case BuiltinFn::kVectorTimesMatrix:
-            return "spirv.vector_times_matrix";
+            return "vector_times_matrix";
         case BuiltinFn::kVectorTimesScalar:
-            return "spirv.vector_times_scalar";
+            return "vector_times_scalar";
     }
     return "<unknown>";
 }
diff --git a/src/tint/lang/spirv/builtin_fn.cc.tmpl b/src/tint/lang/spirv/builtin_fn.cc.tmpl
index 220d19e..9e20878 100644
--- a/src/tint/lang/spirv/builtin_fn.cc.tmpl
+++ b/src/tint/lang/spirv/builtin_fn.cc.tmpl
@@ -22,7 +22,7 @@
             return "<none>";
 {{- range $I.Sem.Builtins  }}
         case BuiltinFn::k{{PascalCase .Name}}:
-            return "spirv.{{.Name}}";
+            return "{{.Name}}";
 {{- end  }}
     }
     return "<unknown>";
diff --git a/src/tint/lang/spirv/intrinsic/data/BUILD.bazel b/src/tint/lang/spirv/intrinsic/data/BUILD.bazel
index 8239db0..3a2673d 100644
--- a/src/tint/lang/spirv/intrinsic/data/BUILD.bazel
+++ b/src/tint/lang/spirv/intrinsic/data/BUILD.bazel
@@ -41,6 +41,7 @@
     "//src/tint/lang/core/type",
     "//src/tint/lang/spirv/type",
     "//src/tint/utils/containers",
+    "//src/tint/utils/diagnostic",
     "//src/tint/utils/ice",
     "//src/tint/utils/id",
     "//src/tint/utils/macros",
diff --git a/src/tint/lang/spirv/intrinsic/data/BUILD.cmake b/src/tint/lang/spirv/intrinsic/data/BUILD.cmake
index bfa57c3..dc7d4da 100644
--- a/src/tint/lang/spirv/intrinsic/data/BUILD.cmake
+++ b/src/tint/lang/spirv/intrinsic/data/BUILD.cmake
@@ -40,6 +40,7 @@
   tint_lang_core_type
   tint_lang_spirv_type
   tint_utils_containers
+  tint_utils_diagnostic
   tint_utils_ice
   tint_utils_id
   tint_utils_macros
diff --git a/src/tint/lang/spirv/intrinsic/data/BUILD.gn b/src/tint/lang/spirv/intrinsic/data/BUILD.gn
index 642a14a..17a0d59 100644
--- a/src/tint/lang/spirv/intrinsic/data/BUILD.gn
+++ b/src/tint/lang/spirv/intrinsic/data/BUILD.gn
@@ -40,6 +40,7 @@
     "${tint_src_dir}/lang/core/type",
     "${tint_src_dir}/lang/spirv/type",
     "${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",
diff --git a/src/tint/lang/spirv/ir/builtin_call.h b/src/tint/lang/spirv/ir/builtin_call.h
index 4ae0ee6..5eeefb9 100644
--- a/src/tint/lang/spirv/ir/builtin_call.h
+++ b/src/tint/lang/spirv/ir/builtin_call.h
@@ -47,10 +47,7 @@
     size_t FuncId() override { return static_cast<size_t>(func_); }
 
     /// @returns the friendly name for the instruction
-    std::string FriendlyName() override { return str(func_); }
-
-    /// @returns the intrinsic name
-    const char* IntrinsicName() override { return str(func_); }
+    std::string FriendlyName() override { return std::string("spirv.") + str(func_); }
 
     /// @returns the table data to validate this builtin
     const core::intrinsic::TableData& TableData() override { return spirv::intrinsic::data::kData; }
diff --git a/src/tint/lang/spirv/reader/ast_lower/BUILD.bazel b/src/tint/lang/spirv/reader/ast_lower/BUILD.bazel
index 0a5204d..37651a6 100644
--- a/src/tint/lang/spirv/reader/ast_lower/BUILD.bazel
+++ b/src/tint/lang/spirv/reader/ast_lower/BUILD.bazel
@@ -78,6 +78,7 @@
     "//src/tint/api/common",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
diff --git a/src/tint/lang/spirv/reader/ast_lower/BUILD.cmake b/src/tint/lang/spirv/reader/ast_lower/BUILD.cmake
index 034a369..f7a4893 100644
--- a/src/tint/lang/spirv/reader/ast_lower/BUILD.cmake
+++ b/src/tint/lang/spirv/reader/ast_lower/BUILD.cmake
@@ -82,6 +82,7 @@
   tint_api_common
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
diff --git a/src/tint/lang/spirv/reader/ast_lower/BUILD.gn b/src/tint/lang/spirv/reader/ast_lower/BUILD.gn
index fee420d..12924c2 100644
--- a/src/tint/lang/spirv/reader/ast_lower/BUILD.gn
+++ b/src/tint/lang/spirv/reader/ast_lower/BUILD.gn
@@ -82,6 +82,7 @@
         "${tint_src_dir}/api/common",
         "${tint_src_dir}/lang/core",
         "${tint_src_dir}/lang/core/constant",
+        "${tint_src_dir}/lang/core/ir",
         "${tint_src_dir}/lang/core/type",
         "${tint_src_dir}/lang/wgsl",
         "${tint_src_dir}/lang/wgsl/ast",
diff --git a/src/tint/lang/spirv/reader/ast_lower/atomics.cc b/src/tint/lang/spirv/reader/ast_lower/atomics.cc
index 17ad8a2..efab3d3 100644
--- a/src/tint/lang/spirv/reader/ast_lower/atomics.cc
+++ b/src/tint/lang/spirv/reader/ast_lower/atomics.cc
@@ -87,7 +87,7 @@
                     out_args[0] = b.AddressOf(out_args[0]);
 
                     // Replace all callsites of this stub to a call to the real builtin
-                    if (stub->builtin == core::BuiltinFn::kAtomicCompareExchangeWeak) {
+                    if (stub->builtin == wgsl::BuiltinFn::kAtomicCompareExchangeWeak) {
                         // atomicCompareExchangeWeak returns a struct, so insert a call to it above
                         // the current statement, and replace the current call with the struct's
                         // `old_value` member.
@@ -95,14 +95,14 @@
                         auto old_value = b.Symbols().New("old_value");
                         auto old_value_decl = b.Decl(b.Let(
                             old_value,
-                            b.MemberAccessor(b.Call(core::str(stub->builtin), std::move(out_args)),
+                            b.MemberAccessor(b.Call(wgsl::str(stub->builtin), std::move(out_args)),
                                              "old_value")));
                         ctx.InsertBefore(block->statements, call->Stmt()->Declaration(),
                                          old_value_decl);
                         ctx.Replace(call->Declaration(), b.Expr(old_value));
                     } else {
                         ctx.Replace(call->Declaration(),
-                                    b.Call(core::str(stub->builtin), std::move(out_args)));
+                                    b.Call(wgsl::str(stub->builtin), std::move(out_args)));
                     }
 
                     // Keep track of this expression. We'll need to modify the root identifier /
@@ -255,7 +255,7 @@
                 if (is_ref_to_atomic_var(load->Reference())) {
                     ctx.Replace(load->Reference()->Declaration(), [=] {
                         auto* expr = ctx.CloneWithoutTransform(load->Reference()->Declaration());
-                        return b.Call(core::str(core::BuiltinFn::kAtomicLoad), b.AddressOf(expr));
+                        return b.Call(wgsl::BuiltinFn::kAtomicLoad, b.AddressOf(expr));
                     });
                 }
             } else if (auto* assign = node->As<ast::AssignmentStatement>()) {
@@ -264,8 +264,7 @@
                     ctx.Replace(assign, [=] {
                         auto* lhs = ctx.CloneWithoutTransform(assign->lhs);
                         auto* rhs = ctx.CloneWithoutTransform(assign->rhs);
-                        auto* call =
-                            b.Call(core::str(core::BuiltinFn::kAtomicStore), b.AddressOf(lhs), rhs);
+                        auto* call = b.Call(wgsl::BuiltinFn::kAtomicStore, b.AddressOf(lhs), rhs);
                         return b.CallStmt(call);
                     });
                 }
@@ -277,11 +276,11 @@
 Atomics::Atomics() = default;
 Atomics::~Atomics() = default;
 
-Atomics::Stub::Stub(GenerationID pid, ast::NodeID nid, core::BuiltinFn b)
+Atomics::Stub::Stub(GenerationID pid, ast::NodeID nid, wgsl::BuiltinFn b)
     : Base(pid, nid, tint::Empty), builtin(b) {}
 Atomics::Stub::~Stub() = default;
 std::string Atomics::Stub::InternalName() const {
-    return "@internal(spirv-atomic " + std::string(core::str(builtin)) + ")";
+    return "@internal(spirv-atomic " + std::string(wgsl::str(builtin)) + ")";
 }
 
 const Atomics::Stub* Atomics::Stub::Clone(ast::CloneContext& ctx) const {
diff --git a/src/tint/lang/spirv/reader/ast_lower/atomics.h b/src/tint/lang/spirv/reader/ast_lower/atomics.h
index c74d16d..efc510b 100644
--- a/src/tint/lang/spirv/reader/ast_lower/atomics.h
+++ b/src/tint/lang/spirv/reader/ast_lower/atomics.h
@@ -17,9 +17,9 @@
 
 #include <string>
 
-#include "src/tint/lang/core/builtin_fn.h"
 #include "src/tint/lang/wgsl/ast/internal_attribute.h"
 #include "src/tint/lang/wgsl/ast/transform/transform.h"
+#include "src/tint/lang/wgsl/builtin_fn.h"
 
 namespace tint::spirv::reader {
 
@@ -41,7 +41,7 @@
         /// @param pid the identifier of the program that owns this node
         /// @param nid the unique node identifier
         /// @param builtin the atomic builtin this stub represents
-        Stub(GenerationID pid, ast::NodeID nid, core::BuiltinFn builtin);
+        Stub(GenerationID pid, ast::NodeID nid, wgsl::BuiltinFn builtin);
         /// Destructor
         ~Stub() override;
 
@@ -55,7 +55,7 @@
         const Stub* Clone(ast::CloneContext& ctx) const override;
 
         /// The type of the intrinsic
-        const core::BuiltinFn builtin;
+        const wgsl::BuiltinFn builtin;
     };
 
     /// @copydoc ast::transform::Transform::Apply
diff --git a/src/tint/lang/spirv/reader/ast_lower/atomics_test.cc b/src/tint/lang/spirv/reader/ast_lower/atomics_test.cc
index 6f67a21..bfe1414 100644
--- a/src/tint/lang/spirv/reader/ast_lower/atomics_test.cc
+++ b/src/tint/lang/spirv/reader/ast_lower/atomics_test.cc
@@ -37,14 +37,14 @@
 
         auto& b = parser.builder();
 
-        core::BuiltinFn two_params[] = {
-            core::BuiltinFn::kAtomicExchange, core::BuiltinFn::kAtomicAdd,
-            core::BuiltinFn::kAtomicSub,      core::BuiltinFn::kAtomicMin,
-            core::BuiltinFn::kAtomicMax,      core::BuiltinFn::kAtomicAnd,
-            core::BuiltinFn::kAtomicOr,       core::BuiltinFn::kAtomicXor,
+        wgsl::BuiltinFn two_params[] = {
+            wgsl::BuiltinFn::kAtomicExchange, wgsl::BuiltinFn::kAtomicAdd,
+            wgsl::BuiltinFn::kAtomicSub,      wgsl::BuiltinFn::kAtomicMin,
+            wgsl::BuiltinFn::kAtomicMax,      wgsl::BuiltinFn::kAtomicAnd,
+            wgsl::BuiltinFn::kAtomicOr,       wgsl::BuiltinFn::kAtomicXor,
         };
         for (auto& a : two_params) {
-            b.Func(std::string{"stub_"} + core::str(a) + "_u32",
+            b.Func(std::string{"stub_"} + wgsl::str(a) + "_u32",
                    tint::Vector{
                        b.Param("p0", b.ty.u32()),
                        b.Param("p1", b.ty.u32()),
@@ -56,7 +56,7 @@
                    tint::Vector{
                        b.ASTNodes().Create<Atomics::Stub>(b.ID(), b.AllocateNodeID(), a),
                    });
-            b.Func(std::string{"stub_"} + core::str(a) + "_i32",
+            b.Func(std::string{"stub_"} + wgsl::str(a) + "_i32",
                    tint::Vector{
                        b.Param("p0", b.ty.i32()),
                        b.Param("p1", b.ty.i32()),
@@ -80,7 +80,7 @@
                },
                tint::Vector{
                    b.ASTNodes().Create<Atomics::Stub>(b.ID(), b.AllocateNodeID(),
-                                                      core::BuiltinFn::kAtomicLoad),
+                                                      wgsl::BuiltinFn::kAtomicLoad),
                });
         b.Func("stub_atomicLoad_i32",
                tint::Vector{
@@ -92,7 +92,7 @@
                },
                tint::Vector{
                    b.ASTNodes().Create<Atomics::Stub>(b.ID(), b.AllocateNodeID(),
-                                                      core::BuiltinFn::kAtomicLoad),
+                                                      wgsl::BuiltinFn::kAtomicLoad),
                });
 
         b.Func("stub_atomicStore_u32",
@@ -103,7 +103,7 @@
                b.ty.void_(), tint::Empty,
                tint::Vector{
                    b.ASTNodes().Create<Atomics::Stub>(b.ID(), b.AllocateNodeID(),
-                                                      core::BuiltinFn::kAtomicStore),
+                                                      wgsl::BuiltinFn::kAtomicStore),
                });
         b.Func("stub_atomicStore_i32",
                tint::Vector{
@@ -113,7 +113,7 @@
                b.ty.void_(), tint::Empty,
                tint::Vector{
                    b.ASTNodes().Create<Atomics::Stub>(b.ID(), b.AllocateNodeID(),
-                                                      core::BuiltinFn::kAtomicStore),
+                                                      wgsl::BuiltinFn::kAtomicStore),
                });
 
         b.Func("stub_atomic_compare_exchange_weak_u32",
@@ -128,7 +128,7 @@
                },
                tint::Vector{
                    b.ASTNodes().Create<Atomics::Stub>(b.ID(), b.AllocateNodeID(),
-                                                      core::BuiltinFn::kAtomicCompareExchangeWeak),
+                                                      wgsl::BuiltinFn::kAtomicCompareExchangeWeak),
                });
         b.Func("stub_atomic_compare_exchange_weak_i32",
                tint::Vector{b.Param("p0", b.ty.i32()), b.Param("p1", b.ty.i32()),
@@ -139,7 +139,7 @@
                },
                tint::Vector{
                    b.ASTNodes().Create<Atomics::Stub>(b.ID(), b.AllocateNodeID(),
-                                                      core::BuiltinFn::kAtomicCompareExchangeWeak),
+                                                      wgsl::BuiltinFn::kAtomicCompareExchangeWeak),
                });
 
         // Keep this pointer alive after Transform() returns
diff --git a/src/tint/lang/spirv/reader/ast_parser/barrier_test.cc b/src/tint/lang/spirv/reader/ast_parser/barrier_test.cc
index 502d2ba..76d1d61 100644
--- a/src/tint/lang/spirv/reader/ast_parser/barrier_test.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/barrier_test.cc
@@ -73,7 +73,7 @@
     ASSERT_NE(sem_call, nullptr);
     auto* builtin = sem_call->Target()->As<sem::BuiltinFn>();
     ASSERT_NE(builtin, nullptr);
-    EXPECT_EQ(builtin->Fn(), core::BuiltinFn::kWorkgroupBarrier);
+    EXPECT_EQ(builtin->Fn(), wgsl::BuiltinFn::kWorkgroupBarrier);
 }
 
 TEST_F(SpirvASTParserTest, StorageBarrier) {
@@ -106,7 +106,7 @@
     ASSERT_NE(sem_call, nullptr);
     auto* builtin = sem_call->Target()->As<sem::BuiltinFn>();
     ASSERT_NE(builtin, nullptr);
-    EXPECT_EQ(builtin->Fn(), core::BuiltinFn::kStorageBarrier);
+    EXPECT_EQ(builtin->Fn(), wgsl::BuiltinFn::kStorageBarrier);
 }
 
 TEST_F(SpirvASTParserTest, TextureBarrier) {
@@ -139,7 +139,7 @@
     ASSERT_NE(sem_call, nullptr);
     auto* builtin = sem_call->Target()->As<sem::BuiltinFn>();
     ASSERT_NE(builtin, nullptr);
-    EXPECT_EQ(builtin->Fn(), core::BuiltinFn::kTextureBarrier);
+    EXPECT_EQ(builtin->Fn(), wgsl::BuiltinFn::kTextureBarrier);
 }
 
 TEST_F(SpirvASTParserTest, WorkgroupAndTextureAndStorageBarrier) {
@@ -175,7 +175,7 @@
         ASSERT_NE(sem_call, nullptr);
         auto* builtin = sem_call->Target()->As<sem::BuiltinFn>();
         ASSERT_NE(builtin, nullptr);
-        EXPECT_EQ(builtin->Fn(), core::BuiltinFn::kWorkgroupBarrier);
+        EXPECT_EQ(builtin->Fn(), wgsl::BuiltinFn::kWorkgroupBarrier);
     }
     {
         auto* call = helper->body->statements[1]->As<ast::CallStatement>();
@@ -185,7 +185,7 @@
         ASSERT_NE(sem_call, nullptr);
         auto* builtin = sem_call->Target()->As<sem::BuiltinFn>();
         ASSERT_NE(builtin, nullptr);
-        EXPECT_EQ(builtin->Fn(), core::BuiltinFn::kStorageBarrier);
+        EXPECT_EQ(builtin->Fn(), wgsl::BuiltinFn::kStorageBarrier);
     }
     {
         auto* call = helper->body->statements[2]->As<ast::CallStatement>();
@@ -195,7 +195,7 @@
         ASSERT_NE(sem_call, nullptr);
         auto* builtin = sem_call->Target()->As<sem::BuiltinFn>();
         ASSERT_NE(builtin, nullptr);
-        EXPECT_EQ(builtin->Fn(), core::BuiltinFn::kTextureBarrier);
+        EXPECT_EQ(builtin->Fn(), wgsl::BuiltinFn::kTextureBarrier);
     }
 }
 
diff --git a/src/tint/lang/spirv/reader/ast_parser/function.cc b/src/tint/lang/spirv/reader/ast_parser/function.cc
index 311f9b2..0c627bc 100644
--- a/src/tint/lang/spirv/reader/ast_parser/function.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/function.cc
@@ -456,42 +456,42 @@
 }
 
 // Returns the WGSL standard library function builtin for the
-// given instruction, or core::BuiltinFn::kNone
-core::BuiltinFn GetBuiltin(spv::Op opcode) {
+// given instruction, or wgsl::BuiltinFn::kNone
+wgsl::BuiltinFn GetBuiltin(spv::Op opcode) {
     switch (opcode) {
         case spv::Op::OpBitCount:
-            return core::BuiltinFn::kCountOneBits;
+            return wgsl::BuiltinFn::kCountOneBits;
         case spv::Op::OpBitFieldInsert:
-            return core::BuiltinFn::kInsertBits;
+            return wgsl::BuiltinFn::kInsertBits;
         case spv::Op::OpBitFieldSExtract:
         case spv::Op::OpBitFieldUExtract:
-            return core::BuiltinFn::kExtractBits;
+            return wgsl::BuiltinFn::kExtractBits;
         case spv::Op::OpBitReverse:
-            return core::BuiltinFn::kReverseBits;
+            return wgsl::BuiltinFn::kReverseBits;
         case spv::Op::OpDot:
-            return core::BuiltinFn::kDot;
+            return wgsl::BuiltinFn::kDot;
         case spv::Op::OpDPdx:
-            return core::BuiltinFn::kDpdx;
+            return wgsl::BuiltinFn::kDpdx;
         case spv::Op::OpDPdy:
-            return core::BuiltinFn::kDpdy;
+            return wgsl::BuiltinFn::kDpdy;
         case spv::Op::OpFwidth:
-            return core::BuiltinFn::kFwidth;
+            return wgsl::BuiltinFn::kFwidth;
         case spv::Op::OpDPdxFine:
-            return core::BuiltinFn::kDpdxFine;
+            return wgsl::BuiltinFn::kDpdxFine;
         case spv::Op::OpDPdyFine:
-            return core::BuiltinFn::kDpdyFine;
+            return wgsl::BuiltinFn::kDpdyFine;
         case spv::Op::OpFwidthFine:
-            return core::BuiltinFn::kFwidthFine;
+            return wgsl::BuiltinFn::kFwidthFine;
         case spv::Op::OpDPdxCoarse:
-            return core::BuiltinFn::kDpdxCoarse;
+            return wgsl::BuiltinFn::kDpdxCoarse;
         case spv::Op::OpDPdyCoarse:
-            return core::BuiltinFn::kDpdyCoarse;
+            return wgsl::BuiltinFn::kDpdyCoarse;
         case spv::Op::OpFwidthCoarse:
-            return core::BuiltinFn::kFwidthCoarse;
+            return wgsl::BuiltinFn::kFwidthCoarse;
         default:
             break;
     }
-    return core::BuiltinFn::kNone;
+    return wgsl::BuiltinFn::kNone;
 }
 
 // @param opcode a SPIR-V opcode
@@ -3819,11 +3819,11 @@
     }
 
     const auto builtin = GetBuiltin(op);
-    if (builtin != core::BuiltinFn::kNone) {
+    if (builtin != wgsl::BuiltinFn::kNone) {
         switch (builtin) {
-            case core::BuiltinFn::kExtractBits:
+            case wgsl::BuiltinFn::kExtractBits:
                 return MakeExtractBitsCall(inst);
-            case core::BuiltinFn::kInsertBits:
+            case wgsl::BuiltinFn::kInsertBits:
                 return MakeInsertBitsCall(inst);
             default:
                 return MakeBuiltinCall(inst);
@@ -5324,7 +5324,7 @@
 
 TypedExpression FunctionEmitter::MakeBuiltinCall(const spvtools::opt::Instruction& inst) {
     const auto builtin = GetBuiltin(opcode(inst));
-    auto* name = core::str(builtin);
+    auto* name = wgsl::str(builtin);
     auto* ident = create<ast::Identifier>(Source{}, builder_.Symbols().Register(name));
 
     ExpressionList params;
@@ -5348,7 +5348,7 @@
 
 TypedExpression FunctionEmitter::MakeExtractBitsCall(const spvtools::opt::Instruction& inst) {
     const auto builtin = GetBuiltin(opcode(inst));
-    auto* name = core::str(builtin);
+    auto* name = wgsl::str(builtin);
     auto* ident = create<ast::Identifier>(Source{}, builder_.Symbols().Register(name));
     auto e = MakeOperand(inst, 0);
     auto offset = ToU32(MakeOperand(inst, 1));
@@ -5365,7 +5365,7 @@
 
 TypedExpression FunctionEmitter::MakeInsertBitsCall(const spvtools::opt::Instruction& inst) {
     const auto builtin = GetBuiltin(opcode(inst));
-    auto* name = core::str(builtin);
+    auto* name = wgsl::str(builtin);
     auto* ident = create<ast::Identifier>(Source{}, builder_.Symbols().Register(name));
     auto e = MakeOperand(inst, 0);
     auto newbits = MakeOperand(inst, 1);
@@ -5852,7 +5852,7 @@
 }
 
 bool FunctionEmitter::EmitAtomicOp(const spvtools::opt::Instruction& inst) {
-    auto emit_atomic = [&](core::BuiltinFn builtin, std::initializer_list<TypedExpression> args) {
+    auto emit_atomic = [&](wgsl::BuiltinFn builtin, std::initializer_list<TypedExpression> args) {
         // Split args into params and expressions
         ParameterList params;
         params.Reserve(args.size());
@@ -5874,7 +5874,7 @@
 
         // Emit stub, will be removed by transform::SpirvAtomic
         auto* stub = builder_.Func(
-            Source{}, builder_.Symbols().New(std::string("stub_") + core::str(builtin)),
+            Source{}, builder_.Symbols().New(std::string("stub_") + wgsl::str(builtin)),
             std::move(params), ret_type,
             /* body */ nullptr,
             tint::Vector{
@@ -5911,38 +5911,38 @@
 
     switch (opcode(inst)) {
         case spv::Op::OpAtomicLoad:
-            return emit_atomic(core::BuiltinFn::kAtomicLoad, {oper(/*ptr*/ 0)});
+            return emit_atomic(wgsl::BuiltinFn::kAtomicLoad, {oper(/*ptr*/ 0)});
         case spv::Op::OpAtomicStore:
-            return emit_atomic(core::BuiltinFn::kAtomicStore, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(wgsl::BuiltinFn::kAtomicStore, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicExchange:
-            return emit_atomic(core::BuiltinFn::kAtomicExchange,
+            return emit_atomic(wgsl::BuiltinFn::kAtomicExchange,
                                {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicCompareExchange:
         case spv::Op::OpAtomicCompareExchangeWeak:
-            return emit_atomic(core::BuiltinFn::kAtomicCompareExchangeWeak,
+            return emit_atomic(wgsl::BuiltinFn::kAtomicCompareExchangeWeak,
                                {oper(/*ptr*/ 0), /*value*/ oper(5), /*comparator*/ oper(4)});
         case spv::Op::OpAtomicIIncrement:
-            return emit_atomic(core::BuiltinFn::kAtomicAdd, {oper(/*ptr*/ 0), lit(1)});
+            return emit_atomic(wgsl::BuiltinFn::kAtomicAdd, {oper(/*ptr*/ 0), lit(1)});
         case spv::Op::OpAtomicIDecrement:
-            return emit_atomic(core::BuiltinFn::kAtomicSub, {oper(/*ptr*/ 0), lit(1)});
+            return emit_atomic(wgsl::BuiltinFn::kAtomicSub, {oper(/*ptr*/ 0), lit(1)});
         case spv::Op::OpAtomicIAdd:
-            return emit_atomic(core::BuiltinFn::kAtomicAdd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(wgsl::BuiltinFn::kAtomicAdd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicISub:
-            return emit_atomic(core::BuiltinFn::kAtomicSub, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(wgsl::BuiltinFn::kAtomicSub, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicSMin:
-            return emit_atomic(core::BuiltinFn::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(wgsl::BuiltinFn::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicUMin:
-            return emit_atomic(core::BuiltinFn::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(wgsl::BuiltinFn::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicSMax:
-            return emit_atomic(core::BuiltinFn::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(wgsl::BuiltinFn::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicUMax:
-            return emit_atomic(core::BuiltinFn::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(wgsl::BuiltinFn::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicAnd:
-            return emit_atomic(core::BuiltinFn::kAtomicAnd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(wgsl::BuiltinFn::kAtomicAnd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicOr:
-            return emit_atomic(core::BuiltinFn::kAtomicOr, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(wgsl::BuiltinFn::kAtomicOr, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicXor:
-            return emit_atomic(core::BuiltinFn::kAtomicXor, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(wgsl::BuiltinFn::kAtomicXor, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicFlagTestAndSet:
         case spv::Op::OpAtomicFlagClear:
         case spv::Op::OpAtomicFMinEXT:
diff --git a/src/tint/lang/spirv/type/BUILD.bazel b/src/tint/lang/spirv/type/BUILD.bazel
index 4337199..32ef7f6 100644
--- a/src/tint/lang/spirv/type/BUILD.bazel
+++ b/src/tint/lang/spirv/type/BUILD.bazel
@@ -37,6 +37,7 @@
     "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/utils/containers",
+    "//src/tint/utils/diagnostic",
     "//src/tint/utils/ice",
     "//src/tint/utils/id",
     "//src/tint/utils/macros",
diff --git a/src/tint/lang/spirv/type/BUILD.cmake b/src/tint/lang/spirv/type/BUILD.cmake
index 1e2546a..7fce4e2 100644
--- a/src/tint/lang/spirv/type/BUILD.cmake
+++ b/src/tint/lang/spirv/type/BUILD.cmake
@@ -36,6 +36,7 @@
   tint_lang_core_ir
   tint_lang_core_type
   tint_utils_containers
+  tint_utils_diagnostic
   tint_utils_ice
   tint_utils_id
   tint_utils_macros
diff --git a/src/tint/lang/spirv/type/BUILD.gn b/src/tint/lang/spirv/type/BUILD.gn
index 41c6378..85fdf35 100644
--- a/src/tint/lang/spirv/type/BUILD.gn
+++ b/src/tint/lang/spirv/type/BUILD.gn
@@ -36,6 +36,7 @@
     "${tint_src_dir}/lang/core/ir",
     "${tint_src_dir}/lang/core/type",
     "${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",
diff --git a/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc b/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc
index 1affcf3..be77357 100644
--- a/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc
@@ -14,6 +14,7 @@
 
 #include "src/tint/lang/spirv/writer/ast_printer/ast_printer.h"
 
+#include <unordered_map>
 #include <utility>
 #include <vector>
 
@@ -97,7 +98,7 @@
     manager.Add<ast::transform::BindingRemapper>();
     data.Add<ast::transform::BindingRemapper::Remappings>(
         options.binding_remapper_options.binding_points,
-        options.binding_remapper_options.access_controls,
+        std::unordered_map<BindingPoint, core::Access>{},
         options.binding_remapper_options.allow_collisions);
 
     // Note: it is more efficient for MultiplanarExternalTexture to come after Robustness
@@ -190,7 +191,7 @@
     if (builder_.Build()) {
         auto& module = builder_.Module();
         writer_.WriteHeader(module.IdBound());
-        writer_.WriteModule(&module);
+        writer_.WriteModule(module);
         return true;
     }
     return false;
diff --git a/src/tint/lang/spirv/writer/ast_printer/ast_printer_test.cc b/src/tint/lang/spirv/writer/ast_printer/ast_printer_test.cc
index da60198..43c18f9 100644
--- a/src/tint/lang/spirv/writer/ast_printer/ast_printer_test.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/ast_printer_test.cc
@@ -27,7 +27,7 @@
     ASSERT_FALSE(program.IsValid());
     auto result = Generate(program, Options{});
     EXPECT_FALSE(result);
-    EXPECT_EQ(result.Failure(), "input program is not valid");
+    EXPECT_EQ(result.Failure().reason.str(), "error: make the program invalid");
 }
 
 TEST_F(SpirvASTPrinterTest, UnsupportedExtension) {
@@ -36,7 +36,7 @@
     auto program = resolver::Resolve(*this);
     auto result = Generate(program, Options{});
     EXPECT_FALSE(result);
-    EXPECT_EQ(result.Failure(),
+    EXPECT_EQ(result.Failure().reason.str(),
               R"(12:34 error: SPIR-V backend does not support extension 'undefined')");
 }
 
diff --git a/src/tint/lang/spirv/writer/ast_printer/builder.cc b/src/tint/lang/spirv/writer/ast_printer/builder.cc
index 76bfba3..24fca39 100644
--- a/src/tint/lang/spirv/writer/ast_printer/builder.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/builder.cc
@@ -94,23 +94,23 @@
 
 uint32_t builtin_to_glsl_method(const sem::BuiltinFn* builtin) {
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kAcos:
+        case wgsl::BuiltinFn::kAcos:
             return GLSLstd450Acos;
-        case core::BuiltinFn::kAcosh:
+        case wgsl::BuiltinFn::kAcosh:
             return GLSLstd450Acosh;
-        case core::BuiltinFn::kAsin:
+        case wgsl::BuiltinFn::kAsin:
             return GLSLstd450Asin;
-        case core::BuiltinFn::kAsinh:
+        case wgsl::BuiltinFn::kAsinh:
             return GLSLstd450Asinh;
-        case core::BuiltinFn::kAtan:
+        case wgsl::BuiltinFn::kAtan:
             return GLSLstd450Atan;
-        case core::BuiltinFn::kAtan2:
+        case wgsl::BuiltinFn::kAtan2:
             return GLSLstd450Atan2;
-        case core::BuiltinFn::kAtanh:
+        case wgsl::BuiltinFn::kAtanh:
             return GLSLstd450Atanh;
-        case core::BuiltinFn::kCeil:
+        case wgsl::BuiltinFn::kCeil:
             return GLSLstd450Ceil;
-        case core::BuiltinFn::kClamp:
+        case wgsl::BuiltinFn::kClamp:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 return GLSLstd450NClamp;
             } else if (builtin->ReturnType()->is_unsigned_integer_scalar_or_vector()) {
@@ -118,43 +118,43 @@
             } else {
                 return GLSLstd450SClamp;
             }
-        case core::BuiltinFn::kCos:
+        case wgsl::BuiltinFn::kCos:
             return GLSLstd450Cos;
-        case core::BuiltinFn::kCosh:
+        case wgsl::BuiltinFn::kCosh:
             return GLSLstd450Cosh;
-        case core::BuiltinFn::kCross:
+        case wgsl::BuiltinFn::kCross:
             return GLSLstd450Cross;
-        case core::BuiltinFn::kDegrees:
+        case wgsl::BuiltinFn::kDegrees:
             return GLSLstd450Degrees;
-        case core::BuiltinFn::kDeterminant:
+        case wgsl::BuiltinFn::kDeterminant:
             return GLSLstd450Determinant;
-        case core::BuiltinFn::kDistance:
+        case wgsl::BuiltinFn::kDistance:
             return GLSLstd450Distance;
-        case core::BuiltinFn::kExp:
+        case wgsl::BuiltinFn::kExp:
             return GLSLstd450Exp;
-        case core::BuiltinFn::kExp2:
+        case wgsl::BuiltinFn::kExp2:
             return GLSLstd450Exp2;
-        case core::BuiltinFn::kFaceForward:
+        case wgsl::BuiltinFn::kFaceForward:
             return GLSLstd450FaceForward;
-        case core::BuiltinFn::kFloor:
+        case wgsl::BuiltinFn::kFloor:
             return GLSLstd450Floor;
-        case core::BuiltinFn::kFma:
+        case wgsl::BuiltinFn::kFma:
             return GLSLstd450Fma;
-        case core::BuiltinFn::kFract:
+        case wgsl::BuiltinFn::kFract:
             return GLSLstd450Fract;
-        case core::BuiltinFn::kFrexp:
+        case wgsl::BuiltinFn::kFrexp:
             return GLSLstd450FrexpStruct;
-        case core::BuiltinFn::kInverseSqrt:
+        case wgsl::BuiltinFn::kInverseSqrt:
             return GLSLstd450InverseSqrt;
-        case core::BuiltinFn::kLdexp:
+        case wgsl::BuiltinFn::kLdexp:
             return GLSLstd450Ldexp;
-        case core::BuiltinFn::kLength:
+        case wgsl::BuiltinFn::kLength:
             return GLSLstd450Length;
-        case core::BuiltinFn::kLog:
+        case wgsl::BuiltinFn::kLog:
             return GLSLstd450Log;
-        case core::BuiltinFn::kLog2:
+        case wgsl::BuiltinFn::kLog2:
             return GLSLstd450Log2;
-        case core::BuiltinFn::kMax:
+        case wgsl::BuiltinFn::kMax:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 return GLSLstd450NMax;
             } else if (builtin->ReturnType()->is_unsigned_integer_scalar_or_vector()) {
@@ -162,7 +162,7 @@
             } else {
                 return GLSLstd450SMax;
             }
-        case core::BuiltinFn::kMin:
+        case wgsl::BuiltinFn::kMin:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 return GLSLstd450NMin;
             } else if (builtin->ReturnType()->is_unsigned_integer_scalar_or_vector()) {
@@ -170,63 +170,63 @@
             } else {
                 return GLSLstd450SMin;
             }
-        case core::BuiltinFn::kMix:
+        case wgsl::BuiltinFn::kMix:
             return GLSLstd450FMix;
-        case core::BuiltinFn::kModf:
+        case wgsl::BuiltinFn::kModf:
             return GLSLstd450ModfStruct;
-        case core::BuiltinFn::kNormalize:
+        case wgsl::BuiltinFn::kNormalize:
             return GLSLstd450Normalize;
-        case core::BuiltinFn::kPack4X8Snorm:
+        case wgsl::BuiltinFn::kPack4X8Snorm:
             return GLSLstd450PackSnorm4x8;
-        case core::BuiltinFn::kPack4X8Unorm:
+        case wgsl::BuiltinFn::kPack4X8Unorm:
             return GLSLstd450PackUnorm4x8;
-        case core::BuiltinFn::kPack2X16Snorm:
+        case wgsl::BuiltinFn::kPack2X16Snorm:
             return GLSLstd450PackSnorm2x16;
-        case core::BuiltinFn::kPack2X16Unorm:
+        case wgsl::BuiltinFn::kPack2X16Unorm:
             return GLSLstd450PackUnorm2x16;
-        case core::BuiltinFn::kPack2X16Float:
+        case wgsl::BuiltinFn::kPack2X16Float:
             return GLSLstd450PackHalf2x16;
-        case core::BuiltinFn::kPow:
+        case wgsl::BuiltinFn::kPow:
             return GLSLstd450Pow;
-        case core::BuiltinFn::kRadians:
+        case wgsl::BuiltinFn::kRadians:
             return GLSLstd450Radians;
-        case core::BuiltinFn::kReflect:
+        case wgsl::BuiltinFn::kReflect:
             return GLSLstd450Reflect;
-        case core::BuiltinFn::kRefract:
+        case wgsl::BuiltinFn::kRefract:
             return GLSLstd450Refract;
-        case core::BuiltinFn::kRound:
+        case wgsl::BuiltinFn::kRound:
             return GLSLstd450RoundEven;
-        case core::BuiltinFn::kSign:
+        case wgsl::BuiltinFn::kSign:
             if (builtin->ReturnType()->is_signed_integer_scalar_or_vector()) {
                 return GLSLstd450SSign;
             } else {
                 return GLSLstd450FSign;
             }
-        case core::BuiltinFn::kSin:
+        case wgsl::BuiltinFn::kSin:
             return GLSLstd450Sin;
-        case core::BuiltinFn::kSinh:
+        case wgsl::BuiltinFn::kSinh:
             return GLSLstd450Sinh;
-        case core::BuiltinFn::kSmoothstep:
+        case wgsl::BuiltinFn::kSmoothstep:
             return GLSLstd450SmoothStep;
-        case core::BuiltinFn::kSqrt:
+        case wgsl::BuiltinFn::kSqrt:
             return GLSLstd450Sqrt;
-        case core::BuiltinFn::kStep:
+        case wgsl::BuiltinFn::kStep:
             return GLSLstd450Step;
-        case core::BuiltinFn::kTan:
+        case wgsl::BuiltinFn::kTan:
             return GLSLstd450Tan;
-        case core::BuiltinFn::kTanh:
+        case wgsl::BuiltinFn::kTanh:
             return GLSLstd450Tanh;
-        case core::BuiltinFn::kTrunc:
+        case wgsl::BuiltinFn::kTrunc:
             return GLSLstd450Trunc;
-        case core::BuiltinFn::kUnpack4X8Snorm:
+        case wgsl::BuiltinFn::kUnpack4X8Snorm:
             return GLSLstd450UnpackSnorm4x8;
-        case core::BuiltinFn::kUnpack4X8Unorm:
+        case wgsl::BuiltinFn::kUnpack4X8Unorm:
             return GLSLstd450UnpackUnorm4x8;
-        case core::BuiltinFn::kUnpack2X16Snorm:
+        case wgsl::BuiltinFn::kUnpack2X16Snorm:
             return GLSLstd450UnpackSnorm2x16;
-        case core::BuiltinFn::kUnpack2X16Unorm:
+        case wgsl::BuiltinFn::kUnpack2X16Unorm:
             return GLSLstd450UnpackUnorm2x16;
-        case core::BuiltinFn::kUnpack2X16Float:
+        case wgsl::BuiltinFn::kUnpack2X16Float:
             return GLSLstd450UnpackHalf2x16;
         default:
             break;
@@ -2329,21 +2329,21 @@
     };
 
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kAny:
+        case wgsl::BuiltinFn::kAny:
             if (builtin->Parameters()[0]->Type()->Is<core::type::Bool>()) {
                 // any(v: bool) just resolves to v.
                 return get_arg_as_value_id(0);
             }
             op = spv::Op::OpAny;
             break;
-        case core::BuiltinFn::kAll:
+        case wgsl::BuiltinFn::kAll:
             if (builtin->Parameters()[0]->Type()->Is<core::type::Bool>()) {
                 // all(v: bool) just resolves to v.
                 return get_arg_as_value_id(0);
             }
             op = spv::Op::OpAll;
             break;
-        case core::BuiltinFn::kArrayLength: {
+        case wgsl::BuiltinFn::kArrayLength: {
             auto* address_of = call->Arguments()[0]->Declaration()->As<ast::UnaryOpExpression>();
             if (!address_of || address_of->op != core::UnaryOp::kAddressOf) {
                 TINT_ICE() << "arrayLength() expected pointer to member access, got " +
@@ -2380,10 +2380,10 @@
             }
             return result_id;
         }
-        case core::BuiltinFn::kCountOneBits:
+        case wgsl::BuiltinFn::kCountOneBits:
             op = spv::Op::OpBitCount;
             break;
-        case core::BuiltinFn::kDot: {
+        case wgsl::BuiltinFn::kDot: {
             op = spv::Op::OpDot;
             auto* vec_ty = builtin->Parameters()[0]->Type()->As<core::type::Vector>();
             if (vec_ty->type()->is_integer_scalar()) {
@@ -2424,42 +2424,42 @@
             }
             break;
         }
-        case core::BuiltinFn::kDpdx:
+        case wgsl::BuiltinFn::kDpdx:
             op = spv::Op::OpDPdx;
             break;
-        case core::BuiltinFn::kDpdxCoarse:
+        case wgsl::BuiltinFn::kDpdxCoarse:
             op = spv::Op::OpDPdxCoarse;
             break;
-        case core::BuiltinFn::kDpdxFine:
+        case wgsl::BuiltinFn::kDpdxFine:
             op = spv::Op::OpDPdxFine;
             break;
-        case core::BuiltinFn::kDpdy:
+        case wgsl::BuiltinFn::kDpdy:
             op = spv::Op::OpDPdy;
             break;
-        case core::BuiltinFn::kDpdyCoarse:
+        case wgsl::BuiltinFn::kDpdyCoarse:
             op = spv::Op::OpDPdyCoarse;
             break;
-        case core::BuiltinFn::kDpdyFine:
+        case wgsl::BuiltinFn::kDpdyFine:
             op = spv::Op::OpDPdyFine;
             break;
-        case core::BuiltinFn::kExtractBits:
+        case wgsl::BuiltinFn::kExtractBits:
             op = builtin->Parameters()[0]->Type()->is_unsigned_integer_scalar_or_vector()
                      ? spv::Op::OpBitFieldUExtract
                      : spv::Op::OpBitFieldSExtract;
             break;
-        case core::BuiltinFn::kFwidth:
+        case wgsl::BuiltinFn::kFwidth:
             op = spv::Op::OpFwidth;
             break;
-        case core::BuiltinFn::kFwidthCoarse:
+        case wgsl::BuiltinFn::kFwidthCoarse:
             op = spv::Op::OpFwidthCoarse;
             break;
-        case core::BuiltinFn::kFwidthFine:
+        case wgsl::BuiltinFn::kFwidthFine:
             op = spv::Op::OpFwidthFine;
             break;
-        case core::BuiltinFn::kInsertBits:
+        case wgsl::BuiltinFn::kInsertBits:
             op = spv::Op::OpBitFieldInsert;
             break;
-        case core::BuiltinFn::kMix: {
+        case wgsl::BuiltinFn::kMix: {
             auto std450 = Operand(GetGLSLstd450Import());
 
             auto a_id = get_arg_as_value_id(0);
@@ -2486,13 +2486,13 @@
             }
             return result_id;
         }
-        case core::BuiltinFn::kQuantizeToF16:
+        case wgsl::BuiltinFn::kQuantizeToF16:
             op = spv::Op::OpQuantizeToF16;
             break;
-        case core::BuiltinFn::kReverseBits:
+        case wgsl::BuiltinFn::kReverseBits:
             op = spv::Op::OpBitReverse;
             break;
-        case core::BuiltinFn::kSelect: {
+        case wgsl::BuiltinFn::kSelect: {
             // Note: Argument order is different in WGSL and SPIR-V
             auto cond_id = get_arg_as_value_id(2);
             auto true_id = get_arg_as_value_id(1);
@@ -2524,10 +2524,10 @@
             }
             return result_id;
         }
-        case core::BuiltinFn::kTranspose:
+        case wgsl::BuiltinFn::kTranspose:
             op = spv::Op::OpTranspose;
             break;
-        case core::BuiltinFn::kAbs:
+        case wgsl::BuiltinFn::kAbs:
             if (builtin->ReturnType()->is_unsigned_integer_scalar_or_vector()) {
                 // abs() only operates on *signed* integers.
                 // This is a no-op for unsigned integers.
@@ -2539,7 +2539,7 @@
                 glsl_std450(GLSLstd450SAbs);
             }
             break;
-        case core::BuiltinFn::kDot4I8Packed: {
+        case wgsl::BuiltinFn::kDot4I8Packed: {
             auto first_param_id = get_arg_as_value_id(0);
             auto second_param_id = get_arg_as_value_id(1);
             if (!push_function_inst(spv::Op::OpSDotKHR,
@@ -2551,7 +2551,7 @@
             }
             return result_id;
         }
-        case core::BuiltinFn::kDot4U8Packed: {
+        case wgsl::BuiltinFn::kDot4U8Packed: {
             auto first_param_id = get_arg_as_value_id(0);
             auto second_param_id = get_arg_as_value_id(1);
             if (!push_function_inst(spv::Op::OpUDotKHR,
@@ -2563,7 +2563,7 @@
             }
             return result_id;
         }
-        case core::BuiltinFn::kSubgroupBallot: {
+        case wgsl::BuiltinFn::kSubgroupBallot: {
             module_.PushCapability(SpvCapabilityGroupNonUniformBallot);
             if (!push_function_inst(
                     spv::Op::OpGroupNonUniformBallot,
@@ -2574,7 +2574,7 @@
             }
             return result_id;
         }
-        case core::BuiltinFn::kSubgroupBroadcast: {
+        case wgsl::BuiltinFn::kSubgroupBroadcast: {
             module_.PushCapability(SpvCapabilityGroupNonUniformBallot);
             auto first_param_id = get_arg_as_value_id(0);
             auto second_param_id = get_arg_as_value_id(1);
@@ -2778,7 +2778,7 @@
     };
 
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kTextureDimensions: {
+        case wgsl::BuiltinFn::kTextureDimensions: {
             // Number of returned elements from OpImageQuerySize[Lod] may not match
             // those of textureDimensions().
             // This might be due to an extra vector scalar describing the number of
@@ -2823,7 +2823,7 @@
             }
             break;
         }
-        case core::BuiltinFn::kTextureNumLayers: {
+        case wgsl::BuiltinFn::kTextureNumLayers: {
             uint32_t spirv_dims = 0;
             switch (texture_type->dim()) {
                 default:
@@ -2853,19 +2853,19 @@
             }
             break;
         }
-        case core::BuiltinFn::kTextureNumLevels: {
+        case wgsl::BuiltinFn::kTextureNumLevels: {
             op = spv::Op::OpImageQueryLevels;
             append_result_type_and_id_to_spirv_params();
             spirv_params.emplace_back(gen_arg(Usage::kTexture));
             break;
         }
-        case core::BuiltinFn::kTextureNumSamples: {
+        case wgsl::BuiltinFn::kTextureNumSamples: {
             op = spv::Op::OpImageQuerySamples;
             append_result_type_and_id_to_spirv_params();
             spirv_params.emplace_back(gen_arg(Usage::kTexture));
             break;
         }
-        case core::BuiltinFn::kTextureLoad: {
+        case wgsl::BuiltinFn::kTextureLoad: {
             op = texture_type->Is<core::type::StorageTexture>() ? spv::Op::OpImageRead
                                                                 : spv::Op::OpImageFetch;
             append_result_type_and_id_to_spirv_params_for_read();
@@ -2885,7 +2885,7 @@
 
             break;
         }
-        case core::BuiltinFn::kTextureStore: {
+        case wgsl::BuiltinFn::kTextureStore: {
             op = spv::Op::OpImageWrite;
             spirv_params.emplace_back(gen_arg(Usage::kTexture));
             if (!append_coords_to_spirv_params()) {
@@ -2894,7 +2894,7 @@
             spirv_params.emplace_back(gen_arg(Usage::kValue));
             break;
         }
-        case core::BuiltinFn::kTextureGather: {
+        case wgsl::BuiltinFn::kTextureGather: {
             op = spv::Op::OpImageGather;
             append_result_type_and_id_to_spirv_params();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2908,7 +2908,7 @@
             }
             break;
         }
-        case core::BuiltinFn::kTextureGatherCompare: {
+        case wgsl::BuiltinFn::kTextureGatherCompare: {
             op = spv::Op::OpImageDrefGather;
             append_result_type_and_id_to_spirv_params();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2917,7 +2917,7 @@
             spirv_params.emplace_back(gen_arg(Usage::kDepthRef));
             break;
         }
-        case core::BuiltinFn::kTextureSample: {
+        case wgsl::BuiltinFn::kTextureSample: {
             op = spv::Op::OpImageSampleImplicitLod;
             append_result_type_and_id_to_spirv_params_for_read();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2925,7 +2925,7 @@
             }
             break;
         }
-        case core::BuiltinFn::kTextureSampleBias: {
+        case wgsl::BuiltinFn::kTextureSampleBias: {
             op = spv::Op::OpImageSampleImplicitLod;
             append_result_type_and_id_to_spirv_params_for_read();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2935,7 +2935,7 @@
                 ImageOperand{SpvImageOperandsBiasMask, gen_arg(Usage::kBias)});
             break;
         }
-        case core::BuiltinFn::kTextureSampleLevel: {
+        case wgsl::BuiltinFn::kTextureSampleLevel: {
             op = spv::Op::OpImageSampleExplicitLod;
             append_result_type_and_id_to_spirv_params_for_read();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2963,7 +2963,7 @@
             image_operands.emplace_back(ImageOperand{SpvImageOperandsLodMask, level});
             break;
         }
-        case core::BuiltinFn::kTextureSampleGrad: {
+        case wgsl::BuiltinFn::kTextureSampleGrad: {
             op = spv::Op::OpImageSampleExplicitLod;
             append_result_type_and_id_to_spirv_params_for_read();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2975,7 +2975,7 @@
                 ImageOperand{SpvImageOperandsGradMask, gen_arg(Usage::kDdy)});
             break;
         }
-        case core::BuiltinFn::kTextureSampleCompare: {
+        case wgsl::BuiltinFn::kTextureSampleCompare: {
             op = spv::Op::OpImageSampleDrefImplicitLod;
             append_result_type_and_id_to_spirv_params();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2984,7 +2984,7 @@
             spirv_params.emplace_back(gen_arg(Usage::kDepthRef));
             break;
         }
-        case core::BuiltinFn::kTextureSampleCompareLevel: {
+        case wgsl::BuiltinFn::kTextureSampleCompareLevel: {
             op = spv::Op::OpImageSampleDrefExplicitLod;
             append_result_type_and_id_to_spirv_params();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -3039,23 +3039,23 @@
 
     // TODO(crbug.com/tint/661): Combine sequential barriers to a single
     // instruction.
-    if (builtin->Fn() == core::BuiltinFn::kWorkgroupBarrier) {
+    if (builtin->Fn() == wgsl::BuiltinFn::kWorkgroupBarrier) {
         execution = static_cast<uint32_t>(spv::Scope::Workgroup);
         memory = static_cast<uint32_t>(spv::Scope::Workgroup);
         semantics = static_cast<uint32_t>(spv::MemorySemanticsMask::AcquireRelease) |
                     static_cast<uint32_t>(spv::MemorySemanticsMask::WorkgroupMemory);
-    } else if (builtin->Fn() == core::BuiltinFn::kStorageBarrier) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kStorageBarrier) {
         execution = static_cast<uint32_t>(spv::Scope::Workgroup);
         memory = static_cast<uint32_t>(spv::Scope::Workgroup);
         semantics = static_cast<uint32_t>(spv::MemorySemanticsMask::AcquireRelease) |
                     static_cast<uint32_t>(spv::MemorySemanticsMask::UniformMemory);
-    } else if (builtin->Fn() == core::BuiltinFn::kTextureBarrier) {
+    } else if (builtin->Fn() == wgsl::BuiltinFn::kTextureBarrier) {
         execution = static_cast<uint32_t>(spv::Scope::Workgroup);
         memory = static_cast<uint32_t>(spv::Scope::Workgroup);
         semantics = static_cast<uint32_t>(spv::MemorySemanticsMask::AcquireRelease) |
                     static_cast<uint32_t>(spv::MemorySemanticsMask::ImageMemory);
     } else {
-        TINT_ICE() << "unexpected barrier builtin type " << core::str(builtin->Fn());
+        TINT_ICE() << "unexpected barrier builtin type " << builtin->Fn();
         return false;
     }
 
@@ -3125,7 +3125,7 @@
     Operand semantics = Operand(semantics_id);
 
     switch (builtin->Fn()) {
-        case core::BuiltinFn::kAtomicLoad:
+        case wgsl::BuiltinFn::kAtomicLoad:
             return push_function_inst(spv::Op::OpAtomicLoad, {
                                                                  result_type,
                                                                  result_id,
@@ -3133,14 +3133,14 @@
                                                                  memory,
                                                                  semantics,
                                                              });
-        case core::BuiltinFn::kAtomicStore:
+        case wgsl::BuiltinFn::kAtomicStore:
             return push_function_inst(spv::Op::OpAtomicStore, {
                                                                   pointer,
                                                                   memory,
                                                                   semantics,
                                                                   value,
                                                               });
-        case core::BuiltinFn::kAtomicAdd:
+        case wgsl::BuiltinFn::kAtomicAdd:
             return push_function_inst(spv::Op::OpAtomicIAdd, {
                                                                  result_type,
                                                                  result_id,
@@ -3149,7 +3149,7 @@
                                                                  semantics,
                                                                  value,
                                                              });
-        case core::BuiltinFn::kAtomicSub:
+        case wgsl::BuiltinFn::kAtomicSub:
             return push_function_inst(spv::Op::OpAtomicISub, {
                                                                  result_type,
                                                                  result_id,
@@ -3158,7 +3158,7 @@
                                                                  semantics,
                                                                  value,
                                                              });
-        case core::BuiltinFn::kAtomicMax:
+        case wgsl::BuiltinFn::kAtomicMax:
             return push_function_inst(
                 is_value_signed() ? spv::Op::OpAtomicSMax : spv::Op::OpAtomicUMax, {
                                                                                        result_type,
@@ -3168,7 +3168,7 @@
                                                                                        semantics,
                                                                                        value,
                                                                                    });
-        case core::BuiltinFn::kAtomicMin:
+        case wgsl::BuiltinFn::kAtomicMin:
             return push_function_inst(
                 is_value_signed() ? spv::Op::OpAtomicSMin : spv::Op::OpAtomicUMin, {
                                                                                        result_type,
@@ -3178,7 +3178,7 @@
                                                                                        semantics,
                                                                                        value,
                                                                                    });
-        case core::BuiltinFn::kAtomicAnd:
+        case wgsl::BuiltinFn::kAtomicAnd:
             return push_function_inst(spv::Op::OpAtomicAnd, {
                                                                 result_type,
                                                                 result_id,
@@ -3187,7 +3187,7 @@
                                                                 semantics,
                                                                 value,
                                                             });
-        case core::BuiltinFn::kAtomicOr:
+        case wgsl::BuiltinFn::kAtomicOr:
             return push_function_inst(spv::Op::OpAtomicOr, {
                                                                result_type,
                                                                result_id,
@@ -3196,7 +3196,7 @@
                                                                semantics,
                                                                value,
                                                            });
-        case core::BuiltinFn::kAtomicXor:
+        case wgsl::BuiltinFn::kAtomicXor:
             return push_function_inst(spv::Op::OpAtomicXor, {
                                                                 result_type,
                                                                 result_id,
@@ -3205,7 +3205,7 @@
                                                                 semantics,
                                                                 value,
                                                             });
-        case core::BuiltinFn::kAtomicExchange:
+        case wgsl::BuiltinFn::kAtomicExchange:
             return push_function_inst(spv::Op::OpAtomicExchange, {
                                                                      result_type,
                                                                      result_id,
@@ -3214,7 +3214,7 @@
                                                                      semantics,
                                                                      value,
                                                                  });
-        case core::BuiltinFn::kAtomicCompareExchangeWeak: {
+        case wgsl::BuiltinFn::kAtomicCompareExchangeWeak: {
             auto comparator = GenerateExpression(call->Arguments()[1]);
             if (comparator == 0) {
                 return false;
diff --git a/src/tint/lang/spirv/writer/ast_printer/helper_test.h b/src/tint/lang/spirv/writer/ast_printer/helper_test.h
index 28ac79b..2bb30da 100644
--- a/src/tint/lang/spirv/writer/ast_printer/helper_test.h
+++ b/src/tint/lang/spirv/writer/ast_printer/helper_test.h
@@ -101,7 +101,7 @@
     void Validate(Builder& b) {
         BinaryWriter writer;
         writer.WriteHeader(b.Module().IdBound());
-        writer.WriteModule(&b.Module());
+        writer.WriteModule(b.Module());
         auto binary = writer.Result();
 
         std::string spv_errors;
diff --git a/src/tint/lang/spirv/writer/ast_raise/BUILD.bazel b/src/tint/lang/spirv/writer/ast_raise/BUILD.bazel
index 4712380..b68aec9 100644
--- a/src/tint/lang/spirv/writer/ast_raise/BUILD.bazel
+++ b/src/tint/lang/spirv/writer/ast_raise/BUILD.bazel
@@ -81,8 +81,10 @@
     "while_to_loop_test.cc",
   ],
   deps = [
+    "//src/tint/api/common",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
diff --git a/src/tint/lang/spirv/writer/ast_raise/BUILD.cmake b/src/tint/lang/spirv/writer/ast_raise/BUILD.cmake
index c20fa20..b36edc2 100644
--- a/src/tint/lang/spirv/writer/ast_raise/BUILD.cmake
+++ b/src/tint/lang/spirv/writer/ast_raise/BUILD.cmake
@@ -85,8 +85,10 @@
 )
 
 tint_target_add_dependencies(tint_lang_spirv_writer_ast_raise_test test
+  tint_api_common
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
diff --git a/src/tint/lang/spirv/writer/ast_raise/BUILD.gn b/src/tint/lang/spirv/writer/ast_raise/BUILD.gn
index 4c4d9f3..5ab53d5 100644
--- a/src/tint/lang/spirv/writer/ast_raise/BUILD.gn
+++ b/src/tint/lang/spirv/writer/ast_raise/BUILD.gn
@@ -85,8 +85,10 @@
       ]
       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/ir",
         "${tint_src_dir}/lang/core/type",
         "${tint_src_dir}/lang/wgsl",
         "${tint_src_dir}/lang/wgsl/ast",
diff --git a/src/tint/lang/spirv/writer/atomic_builtin_test.cc b/src/tint/lang/spirv/writer/atomic_builtin_test.cc
index 2cbc65f..60e4228 100644
--- a/src/tint/lang/spirv/writer/atomic_builtin_test.cc
+++ b/src/tint/lang/spirv/writer/atomic_builtin_test.cc
@@ -26,7 +26,7 @@
 TEST_F(SpirvWriterTest, AtomicAdd_Storage) {
     auto* var = b.Var("var", ty.ptr(storage, ty.atomic(ty.i32())));
     var->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -44,7 +44,7 @@
 }
 
 TEST_F(SpirvWriterTest, AtomicAdd_Workgroup) {
-    auto* var = b.RootBlock()->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -61,7 +61,7 @@
 }
 
 TEST_F(SpirvWriterTest, AtomicAnd) {
-    auto* var = b.RootBlock()->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -78,7 +78,7 @@
 }
 
 TEST_F(SpirvWriterTest, AtomicCompareExchangeWeak) {
-    auto* var = b.RootBlock()->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* cmp = b.FunctionParam("cmp", ty.i32());
     auto* val = b.FunctionParam("val", ty.i32());
@@ -103,7 +103,7 @@
 }
 
 TEST_F(SpirvWriterTest, AtomicExchange) {
-    auto* var = b.RootBlock()->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -120,7 +120,7 @@
 }
 
 TEST_F(SpirvWriterTest, AtomicLoad) {
-    auto* var = b.RootBlock()->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* func = b.Function("foo", ty.i32());
 
@@ -135,7 +135,7 @@
 }
 
 TEST_F(SpirvWriterTest, AtomicMax_I32) {
-    auto* var = b.RootBlock()->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -152,7 +152,7 @@
 }
 
 TEST_F(SpirvWriterTest, AtomicMax_U32) {
-    auto* var = b.RootBlock()->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.u32()))));
+    auto* var = mod.root_block->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.u32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.u32());
     auto* func = b.Function("foo", ty.u32());
@@ -169,7 +169,7 @@
 }
 
 TEST_F(SpirvWriterTest, AtomicMin_I32) {
-    auto* var = b.RootBlock()->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -186,7 +186,7 @@
 }
 
 TEST_F(SpirvWriterTest, AtomicMin_U32) {
-    auto* var = b.RootBlock()->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.u32()))));
+    auto* var = mod.root_block->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.u32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.u32());
     auto* func = b.Function("foo", ty.u32());
@@ -203,7 +203,7 @@
 }
 
 TEST_F(SpirvWriterTest, AtomicOr) {
-    auto* var = b.RootBlock()->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -220,7 +220,7 @@
 }
 
 TEST_F(SpirvWriterTest, AtomicStore) {
-    auto* var = b.RootBlock()->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.void_());
@@ -236,7 +236,7 @@
 }
 
 TEST_F(SpirvWriterTest, AtomicSub) {
-    auto* var = b.RootBlock()->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -253,7 +253,7 @@
 }
 
 TEST_F(SpirvWriterTest, AtomicXor) {
-    auto* var = b.RootBlock()->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var("var", ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
diff --git a/src/tint/lang/spirv/writer/builtin_test.cc b/src/tint/lang/spirv/writer/builtin_test.cc
index 3b84143..64dc0c7 100644
--- a/src/tint/lang/spirv/writer/builtin_test.cc
+++ b/src/tint/lang/spirv/writer/builtin_test.cc
@@ -1828,7 +1828,7 @@
 TEST_F(SpirvWriterTest, Builtin_ArrayLength) {
     auto* var = b.Var("var", ty.ptr(storage, ty.runtime_array(ty.i32())));
     var->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.u32());
     b.Append(func->Block(), [&] {
@@ -1852,7 +1852,7 @@
                                                      });
     auto* var = b.Var("var", ty.ptr(storage, str));
     var->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.u32());
     b.Append(func->Block(), [&] {
diff --git a/src/tint/lang/spirv/writer/common/binary_writer.cc b/src/tint/lang/spirv/writer/common/binary_writer.cc
index 92d527f..d9e83fa 100644
--- a/src/tint/lang/spirv/writer/common/binary_writer.cc
+++ b/src/tint/lang/spirv/writer/common/binary_writer.cc
@@ -28,9 +28,9 @@
 
 BinaryWriter::~BinaryWriter() = default;
 
-void BinaryWriter::WriteModule(const Module* module) {
-    out_.reserve(module->TotalSize());
-    module->Iterate([this](const Instruction& inst) { this->process_instruction(inst); });
+void BinaryWriter::WriteModule(const Module& module) {
+    out_.reserve(module.TotalSize());
+    module.Iterate([this](const Instruction& inst) { this->process_instruction(inst); });
 }
 
 void BinaryWriter::WriteInstruction(const Instruction& inst) {
diff --git a/src/tint/lang/spirv/writer/common/binary_writer.h b/src/tint/lang/spirv/writer/common/binary_writer.h
index d3de4b5..b2d4d45 100644
--- a/src/tint/lang/spirv/writer/common/binary_writer.h
+++ b/src/tint/lang/spirv/writer/common/binary_writer.h
@@ -36,7 +36,7 @@
     /// Writes the given module data into a binary. Note, this does not emit the SPIR-V header. You
     /// **must** call WriteHeader() before WriteModule() if you want the SPIR-V to be emitted.
     /// @param module the module to assemble from
-    void WriteModule(const Module* module);
+    void WriteModule(const Module& module);
 
     /// Writes the given instruction into the binary.
     /// @param inst the instruction to assemble
diff --git a/src/tint/lang/spirv/writer/common/binary_writer_test.cc b/src/tint/lang/spirv/writer/common/binary_writer_test.cc
index 6b44272..c991677 100644
--- a/src/tint/lang/spirv/writer/common/binary_writer_test.cc
+++ b/src/tint/lang/spirv/writer/common/binary_writer_test.cc
@@ -38,7 +38,7 @@
 
     m.PushAnnot(spv::Op::OpKill, {Operand(2.4f)});
     BinaryWriter bw;
-    bw.WriteModule(&m);
+    bw.WriteModule(m);
 
     auto res = bw.Result();
     ASSERT_EQ(res.size(), 2u);
@@ -52,7 +52,7 @@
 
     m.PushAnnot(spv::Op::OpKill, {Operand(2u)});
     BinaryWriter bw;
-    bw.WriteModule(&m);
+    bw.WriteModule(m);
 
     auto res = bw.Result();
     ASSERT_EQ(res.size(), 2u);
@@ -64,7 +64,7 @@
 
     m.PushAnnot(spv::Op::OpKill, {Operand("my_string")});
     BinaryWriter bw;
-    bw.WriteModule(&m);
+    bw.WriteModule(m);
 
     auto res = bw.Result();
     ASSERT_EQ(res.size(), 4u);
@@ -89,7 +89,7 @@
 
     m.PushAnnot(spv::Op::OpKill, {Operand("mystring")});
     BinaryWriter bw;
-    bw.WriteModule(&m);
+    bw.WriteModule(m);
 
     auto res = bw.Result();
     ASSERT_EQ(res.size(), 4u);
diff --git a/src/tint/lang/spirv/writer/common/helper_test.h b/src/tint/lang/spirv/writer/common/helper_test.h
index 5e727a9..9969eff 100644
--- a/src/tint/lang/spirv/writer/common/helper_test.h
+++ b/src/tint/lang/spirv/writer/common/helper_test.h
@@ -76,7 +76,7 @@
 template <typename BASE>
 class SpirvWriterTestHelperBase : public BASE {
   public:
-    SpirvWriterTestHelperBase() : writer_(&mod, false) {}
+    SpirvWriterTestHelperBase() : writer_(mod, false) {}
 
     /// The test module.
     core::ir::Module mod;
@@ -103,15 +103,15 @@
     /// @param options the optional writer options to use when raising the IR
     /// @returns true if generation and validation succeeded
     bool Generate(Printer& writer, Options options = {}) {
-        auto raised = raise::Raise(&mod, options);
+        auto raised = raise::Raise(mod, options);
         if (!raised) {
-            err_ = raised.Failure();
+            err_ = raised.Failure().reason.str();
             return false;
         }
 
         auto spirv = writer.Generate();
         if (!spirv) {
-            err_ = spirv.Failure();
+            err_ = spirv.Failure().reason.str();
             return false;
         }
 
diff --git a/src/tint/lang/spirv/writer/common/options.h b/src/tint/lang/spirv/writer/common/options.h
index fce8659..57e81e8 100644
--- a/src/tint/lang/spirv/writer/common/options.h
+++ b/src/tint/lang/spirv/writer/common/options.h
@@ -26,35 +26,35 @@
     /// Set to `true` to disable software robustness that prevents out-of-bounds accesses.
     bool disable_robustness = false;
 
-    /// Set to `true` to generate a PointSize builtin and have it set to 1.0
-    /// from all vertex shaders in the module.
-    bool emit_vertex_point_size = true;
-
-    /// Set to `true` to disable workgroup memory zero initialization
-    bool disable_workgroup_init = false;
-
-    /// Set to `true` to clamp frag depth
-    bool clamp_frag_depth = false;
-
-    /// Options used in the binding mappings for external textures
-    ExternalTextureOptions external_texture_options = {};
-
-    /// Options used in the bindings remapper
-    BindingRemapperOptions binding_remapper_options = {};
-
-    /// Set to `true` to initialize workgroup memory with OpConstantNull when
-    /// VK_KHR_zero_initialize_workgroup_memory is enabled.
-    bool use_zero_initialize_workgroup_memory_extension = false;
-
     /// Set to `true` to skip robustness transform on textures.
     bool disable_image_robustness = false;
 
     /// Set to `true` to disable index clamping on the runtime-sized arrays in robustness transform.
     bool disable_runtime_sized_array_index_clamping = false;
 
+    /// Set to `true` to disable workgroup memory zero initialization
+    bool disable_workgroup_init = false;
+
+    /// Set to `true` to initialize workgroup memory with OpConstantNull when
+    /// VK_KHR_zero_initialize_workgroup_memory is enabled.
+    bool use_zero_initialize_workgroup_memory_extension = false;
+
+    /// Set to `true` to generate a PointSize builtin and have it set to 1.0
+    /// from all vertex shaders in the module.
+    bool emit_vertex_point_size = true;
+
+    /// Set to `true` to clamp frag depth
+    bool clamp_frag_depth = false;
+
     /// Set to `true` to generate SPIR-V via the Tint IR instead of from the AST.
     bool use_tint_ir = false;
 
+    /// Options used in the binding mappings for external textures
+    ExternalTextureOptions external_texture_options = {};
+
+    /// Options used in the bindings remapper
+    BindingRemapperOptions binding_remapper_options = {};
+
     /// Set to `true` to require `SPV_KHR_subgroup_uniform_control_flow` extension and
     /// `SubgroupUniformControlFlowKHR` execution mode for compute stage entry points in generated
     /// SPIRV module. Issue: dawn:464
@@ -62,15 +62,15 @@
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
     TINT_REFLECT(disable_robustness,
-                 emit_vertex_point_size,
-                 disable_workgroup_init,
-                 clamp_frag_depth,
-                 external_texture_options,
-                 binding_remapper_options,
-                 use_zero_initialize_workgroup_memory_extension,
                  disable_image_robustness,
                  disable_runtime_sized_array_index_clamping,
+                 disable_workgroup_init,
+                 use_zero_initialize_workgroup_memory_extension,
+                 emit_vertex_point_size,
+                 clamp_frag_depth,
                  use_tint_ir,
+                 external_texture_options,
+                 binding_remapper_options,
                  experimental_require_subgroup_uniform_control_flow);
 };
 
diff --git a/src/tint/lang/spirv/writer/common/spv_dump_test.cc b/src/tint/lang/spirv/writer/common/spv_dump_test.cc
index 3fcba23..0f36a1b 100644
--- a/src/tint/lang/spirv/writer/common/spv_dump_test.cc
+++ b/src/tint/lang/spirv/writer/common/spv_dump_test.cc
@@ -58,7 +58,7 @@
 std::string DumpModule(Module& module) {
     BinaryWriter writer;
     writer.WriteHeader(module.IdBound());
-    writer.WriteModule(&module);
+    writer.WriteModule(module);
     return Disassemble(writer.Result());
 }
 
diff --git a/src/tint/lang/spirv/writer/discard_test.cc b/src/tint/lang/spirv/writer/discard_test.cc
index cf190b9..0d2390e 100644
--- a/src/tint/lang/spirv/writer/discard_test.cc
+++ b/src/tint/lang/spirv/writer/discard_test.cc
@@ -23,7 +23,7 @@
 TEST_F(SpirvWriterTest, Discard) {
     auto* buffer = b.Var("buffer", ty.ptr<storage, i32>());
     buffer->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(buffer);
+    mod.root_block->Append(buffer);
 
     auto* front_facing = b.FunctionParam("front_facing", ty.bool_());
     front_facing->SetBuiltin(core::ir::FunctionParam::Builtin::kFrontFacing);
diff --git a/src/tint/lang/spirv/writer/printer/printer.cc b/src/tint/lang/spirv/writer/printer/printer.cc
index 35c9327..258335c 100644
--- a/src/tint/lang/spirv/writer/printer/printer.cc
+++ b/src/tint/lang/spirv/writer/printer/printer.cc
@@ -150,13 +150,13 @@
 
 }  // namespace
 
-Printer::Printer(core::ir::Module* module, bool zero_init_workgroup_mem)
-    : ir_(module), b_(*module), zero_init_workgroup_memory_(zero_init_workgroup_mem) {}
+Printer::Printer(core::ir::Module& module, bool zero_init_workgroup_mem)
+    : ir_(module), b_(module), zero_init_workgroup_memory_(zero_init_workgroup_mem) {}
 
-Result<std::vector<uint32_t>, std::string> Printer::Generate() {
-    auto valid = core::ir::ValidateAndDumpIfNeeded(*ir_, "SPIR-V writer");
+Result<std::vector<uint32_t>> Printer::Generate() {
+    auto valid = core::ir::ValidateAndDumpIfNeeded(ir_, "SPIR-V writer");
     if (!valid) {
-        return std::move(valid.Failure());
+        return valid.Failure();
     }
 
     // TODO(crbug.com/tint/1906): Check supported extensions.
@@ -168,19 +168,17 @@
     // TODO(crbug.com/tint/1906): Emit extensions.
 
     // Emit module-scope declarations.
-    if (ir_->root_block) {
-        EmitRootBlock(ir_->root_block);
-    }
+    EmitRootBlock(ir_.root_block);
 
     // Emit functions.
-    for (auto* func : ir_->functions) {
+    for (auto* func : ir_.functions) {
         EmitFunction(func);
     }
 
     // Serialize the module into binary SPIR-V.
     BinaryWriter writer;
     writer.WriteHeader(module_.IdBound(), kWriterVersion);
-    writer.WriteModule(&module_);
+    writer.WriteModule(module_);
     return std::move(writer.Result());
 }
 
@@ -240,7 +238,7 @@
     auto id = Constant(constant->Value());
 
     // Set the name for the SPIR-V result ID if provided in the module.
-    if (auto name = ir_->NameOf(constant)) {
+    if (auto name = ir_.NameOf(constant)) {
         module_.PushDebug(spv::Op::OpName, {id, Operand(name.Name())});
     }
 
@@ -324,7 +322,7 @@
 }
 
 uint32_t Printer::Type(const core::type::Type* ty) {
-    ty = DedupType(ty, ir_->Types());
+    ty = DedupType(ty, ir_.Types());
     return types_.GetOrCreate(ty, [&] {
         auto id = module_.NextId();
         Switch(
@@ -526,7 +524,7 @@
     auto id = Value(func);
 
     // Emit the function name.
-    module_.PushDebug(spv::Op::OpName, {id, Operand(ir_->NameOf(func).Name())});
+    module_.PushDebug(spv::Op::OpName, {id, Operand(ir_.NameOf(func).Name())});
 
     // Emit OpEntryPoint and OpExecutionMode declarations if needed.
     if (func->Stage() != core::ir::Function::PipelineStage::kUndefined) {
@@ -545,7 +543,7 @@
         auto param_id = Value(param);
         params.push_back(Instruction(spv::Op::OpFunctionParameter, {param_type_id, param_id}));
         function_type.param_type_ids.Push(param_type_id);
-        if (auto name = ir_->NameOf(param)) {
+        if (auto name = ir_.NameOf(param)) {
             module_.PushDebug(spv::Op::OpName, {param_id, Operand(name.Name())});
         }
     }
@@ -603,44 +601,42 @@
             return;
     }
 
-    OperandList operands = {U32Operand(stage), id, ir_->NameOf(func).Name()};
+    OperandList operands = {U32Operand(stage), id, ir_.NameOf(func).Name()};
 
     // Add the list of all referenced shader IO variables.
-    if (ir_->root_block) {
-        for (auto* global : *ir_->root_block) {
-            auto* var = global->As<core::ir::Var>();
-            if (!var) {
-                continue;
-            }
+    for (auto* global : *ir_.root_block) {
+        auto* var = global->As<core::ir::Var>();
+        if (!var) {
+            continue;
+        }
 
-            auto* ptr = var->Result()->Type()->As<core::type::Pointer>();
-            if (!(ptr->AddressSpace() == core::AddressSpace::kIn ||
-                  ptr->AddressSpace() == core::AddressSpace::kOut)) {
-                continue;
-            }
+        auto* ptr = var->Result()->Type()->As<core::type::Pointer>();
+        if (!(ptr->AddressSpace() == core::AddressSpace::kIn ||
+              ptr->AddressSpace() == core::AddressSpace::kOut)) {
+            continue;
+        }
 
-            // Determine if this IO variable is used by the entry point.
-            bool used = false;
-            for (const auto& use : var->Result()->Usages()) {
-                auto* block = use.instruction->Block();
-                while (block->Parent()) {
-                    block = block->Parent()->Block();
-                }
-                if (block == func->Block()) {
-                    used = true;
-                    break;
-                }
+        // Determine if this IO variable is used by the entry point.
+        bool used = false;
+        for (const auto& use : var->Result()->Usages()) {
+            auto* block = use.instruction->Block();
+            while (block->Parent()) {
+                block = block->Parent()->Block();
             }
-            if (!used) {
-                continue;
+            if (block == func->Block()) {
+                used = true;
+                break;
             }
-            operands.push_back(Value(var));
+        }
+        if (!used) {
+            continue;
+        }
+        operands.push_back(Value(var));
 
-            // Add the `DepthReplacing` execution mode if `frag_depth` is used.
-            if (var->Attributes().builtin == core::BuiltinValue::kFragDepth) {
-                module_.PushExecutionMode(spv::Op::OpExecutionMode,
-                                          {id, U32Operand(SpvExecutionModeDepthReplacing)});
-            }
+        // Add the `DepthReplacing` execution mode if `frag_depth` is used.
+        if (var->Attributes().builtin == core::BuiltinValue::kFragDepth) {
+            module_.PushExecutionMode(spv::Op::OpExecutionMode,
+                                      {id, U32Operand(SpvExecutionModeDepthReplacing)});
         }
     }
 
@@ -725,7 +721,7 @@
 
         // Set the name for the SPIR-V result ID if provided in the module.
         if (inst->Result() && !inst->Is<core::ir::Var>()) {
-            if (auto name = ir_->NameOf(inst)) {
+            if (auto name = ir_.NameOf(inst)) {
                 module_.PushDebug(spv::Op::OpName, {Value(inst), Operand(name.Name())});
             }
         }
@@ -1425,13 +1421,13 @@
         case core::BuiltinFn::kSubgroupBallot:
             module_.PushCapability(SpvCapabilityGroupNonUniformBallot);
             op = spv::Op::OpGroupNonUniformBallot;
-            operands.push_back(Constant(ir_->constant_values.Get(u32(spv::Scope::Subgroup))));
-            operands.push_back(Constant(ir_->constant_values.Get(true)));
+            operands.push_back(Constant(ir_.constant_values.Get(u32(spv::Scope::Subgroup))));
+            operands.push_back(Constant(ir_.constant_values.Get(true)));
             break;
         case core::BuiltinFn::kSubgroupBroadcast:
             module_.PushCapability(SpvCapabilityGroupNonUniformBallot);
             op = spv::Op::OpGroupNonUniformBroadcast;
-            operands.push_back(Constant(ir_->constant_values.Get(u32(spv::Scope::Subgroup))));
+            operands.push_back(Constant(ir_.constant_values.Get(u32(spv::Scope::Subgroup))));
             break;
         case core::BuiltinFn::kTan:
             glsl_ext_inst(GLSLstd450Tan);
@@ -1606,7 +1602,7 @@
 void Printer::EmitLoadVectorElement(core::ir::LoadVectorElement* load) {
     auto* vec_ptr_ty = load->From()->Type()->As<core::type::Pointer>();
     auto* el_ty = load->Result()->Type();
-    auto* el_ptr_ty = ir_->Types().ptr(vec_ptr_ty->AddressSpace(), el_ty, vec_ptr_ty->Access());
+    auto* el_ptr_ty = ir_.Types().ptr(vec_ptr_ty->AddressSpace(), el_ty, vec_ptr_ty->Access());
     auto el_ptr_id = module_.NextId();
     current_function_.push_inst(
         spv::Op::OpAccessChain,
@@ -1725,7 +1721,7 @@
 void Printer::EmitStoreVectorElement(core::ir::StoreVectorElement* store) {
     auto* vec_ptr_ty = store->To()->Type()->As<core::type::Pointer>();
     auto* el_ty = store->Value()->Type();
-    auto* el_ptr_ty = ir_->Types().ptr(vec_ptr_ty->AddressSpace(), el_ty, vec_ptr_ty->Access());
+    auto* el_ptr_ty = ir_.Types().ptr(vec_ptr_ty->AddressSpace(), el_ty, vec_ptr_ty->Access());
     auto el_ptr_id = module_.NextId();
     current_function_.push_inst(
         spv::Op::OpAccessChain,
@@ -1897,7 +1893,7 @@
     }
 
     // Set the name if present.
-    if (auto name = ir_->NameOf(var)) {
+    if (auto name = ir_.NameOf(var)) {
         module_.PushDebug(spv::Op::OpName, {id, Operand(name.Name())});
     }
 }
diff --git a/src/tint/lang/spirv/writer/printer/printer.h b/src/tint/lang/spirv/writer/printer/printer.h
index 0b061e6..7512685 100644
--- a/src/tint/lang/spirv/writer/printer/printer.h
+++ b/src/tint/lang/spirv/writer/printer/printer.h
@@ -81,10 +81,10 @@
     /// @param module the Tint IR module to generate
     /// @param zero_init_workgroup_memory `true` to initialize all the variables in the Workgroup
     ///                                   storage class with OpConstantNull
-    Printer(core::ir::Module* module, bool zero_init_workgroup_memory);
+    Printer(core::ir::Module& module, bool zero_init_workgroup_memory);
 
-    /// @returns the generated SPIR-V binary on success, or an error string on failure
-    tint::Result<std::vector<uint32_t>, std::string> Generate();
+    /// @returns the generated SPIR-V binary on success, or failure
+    tint::Result<std::vector<uint32_t>> Generate();
 
     /// @returns the module that this writer has produced
     writer::Module& Module() { return module_; }
@@ -279,7 +279,7 @@
     /// @returns the label ID
     uint32_t GetTerminatorBlockLabel(core::ir::Terminator* t);
 
-    core::ir::Module* ir_;
+    core::ir::Module& ir_;
     core::ir::Builder b_;
     writer::Module module_;
     BinaryWriter writer_;
diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
index 313d6fb..678397f 100644
--- a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
+++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
@@ -44,19 +44,19 @@
 /// PIMPL state for the transform.
 struct State {
     /// The IR module.
-    core::ir::Module* ir = nullptr;
+    core::ir::Module& ir;
 
     /// The IR builder.
-    core::ir::Builder b{*ir};
+    core::ir::Builder b{ir};
 
     /// The type manager.
-    core::type::Manager& ty{ir->Types()};
+    core::type::Manager& ty{ir.Types()};
 
     /// Process the module.
     void Process() {
         // Find the builtins that need replacing.
         Vector<core::ir::CoreBuiltinCall*, 4> worklist;
-        for (auto* inst : ir->instructions.Objects()) {
+        for (auto* inst : ir.instructions.Objects()) {
             if (!inst->Alive()) {
                 continue;
             }
@@ -160,8 +160,8 @@
             TINT_ASSERT_OR_RETURN(replacement);
 
             // Replace the old builtin result with the new value.
-            if (auto name = ir->NameOf(builtin->Result())) {
-                ir->SetName(replacement, name);
+            if (auto name = ir.NameOf(builtin->Result())) {
+                ir.SetName(replacement, name);
             }
             builtin->Result()->ReplaceAllUsesWith(replacement);
             builtin->Destroy();
@@ -172,7 +172,7 @@
     /// @param value the literal value
     /// @returns the literal operand
     LiteralOperand* Literal(u32 value) {
-        return ir->values.Create<LiteralOperand>(b.ConstantValue(value));
+        return ir.values.Create<LiteralOperand>(b.ConstantValue(value));
     }
 
     /// Handle an `arrayLength()` builtin.
@@ -255,7 +255,7 @@
 
                 // Construct the atomicCompareExchange result structure.
                 call = b.Construct(
-                    core::type::CreateAtomicCompareExchangeResult(ty, ir->symbols, int_ty),
+                    core::type::CreateAtomicCompareExchangeResult(ty, ir.symbols, int_ty),
                     Vector{original, compare->Result()});
                 break;
             }
@@ -851,10 +851,10 @@
 
 }  // namespace
 
-Result<SuccessType, std::string> BuiltinPolyfill(core::ir::Module* ir) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "BuiltinPolyfill transform");
+Result<SuccessType> BuiltinPolyfill(core::ir::Module& ir) {
+    auto result = ValidateAndDumpIfNeeded(ir, "BuiltinPolyfill transform");
     if (!result) {
-        return result;
+        return result.Failure();
     }
 
     State{ir}.Process();
diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill.h b/src/tint/lang/spirv/writer/raise/builtin_polyfill.h
index 5b16292..469d6a4 100644
--- a/src/tint/lang/spirv/writer/raise/builtin_polyfill.h
+++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill.h
@@ -19,6 +19,7 @@
 
 #include "src/tint/lang/core/ir/constant.h"
 #include "src/tint/lang/core/type/type.h"
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward declarations.
@@ -32,8 +33,8 @@
 /// BuiltinPolyfill is a transform that replaces calls to builtins with polyfills and calls to
 /// SPIR-V backend intrinsic functions.
 /// @param module the module to transform
-/// @returns an error string on failure
-Result<SuccessType, std::string> BuiltinPolyfill(core::ir::Module* module);
+/// @returns success or failure
+Result<SuccessType> BuiltinPolyfill(core::ir::Module& module);
 
 /// LiteralOperand is a type of constant value that is intended to be emitted as a literal in
 /// the SPIR-V instruction stream.
diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc b/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc
index 5bd292a..ee8626e 100644
--- a/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc
+++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc
@@ -42,7 +42,7 @@
                                                         });
     auto* var = b.Var("var", ty.ptr(storage, str_ty));
     var->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.u32());
     b.Append(func->Block(), [&] {
@@ -106,7 +106,7 @@
                                                         });
     auto* var = b.Var("var", ty.ptr(storage, str_ty));
     var->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.u32());
     b.Append(func->Block(), [&] {
@@ -176,7 +176,7 @@
                                                         });
     auto* var = b.Var("var", ty.ptr(storage, str_ty));
     var->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* func = b.Function("foo", ty.u32());
     b.Append(func->Block(), [&] {
@@ -240,7 +240,7 @@
 TEST_F(SpirvWriter_BuiltinPolyfillTest, AtomicAdd_Storage) {
     auto* var = b.Var(ty.ptr(storage, ty.atomic(ty.i32())));
     var->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(var);
+    mod.root_block->Append(var);
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -284,7 +284,7 @@
 }
 
 TEST_F(SpirvWriter_BuiltinPolyfillTest, AtomicAdd_Workgroup) {
-    auto* var = b.RootBlock()->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -328,7 +328,7 @@
 }
 
 TEST_F(SpirvWriter_BuiltinPolyfillTest, AtomicAnd) {
-    auto* var = b.RootBlock()->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -372,7 +372,7 @@
 }
 
 TEST_F(SpirvWriter_BuiltinPolyfillTest, AtomicCompareExchangeWeak) {
-    auto* var = b.RootBlock()->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* cmp = b.FunctionParam("cmp", ty.i32());
     auto* val = b.FunctionParam("val", ty.i32());
@@ -433,7 +433,7 @@
 }
 
 TEST_F(SpirvWriter_BuiltinPolyfillTest, AtomicExchange) {
-    auto* var = b.RootBlock()->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -477,7 +477,7 @@
 }
 
 TEST_F(SpirvWriter_BuiltinPolyfillTest, AtomicLoad) {
-    auto* var = b.RootBlock()->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* func = b.Function("foo", ty.i32());
 
@@ -519,7 +519,7 @@
 }
 
 TEST_F(SpirvWriter_BuiltinPolyfillTest, AtomicMax_I32) {
-    auto* var = b.RootBlock()->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -563,7 +563,7 @@
 }
 
 TEST_F(SpirvWriter_BuiltinPolyfillTest, AtomicMax_U32) {
-    auto* var = b.RootBlock()->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.u32()))));
+    auto* var = mod.root_block->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.u32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.u32());
     auto* func = b.Function("foo", ty.u32());
@@ -607,7 +607,7 @@
 }
 
 TEST_F(SpirvWriter_BuiltinPolyfillTest, AtomicMin_I32) {
-    auto* var = b.RootBlock()->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -651,7 +651,7 @@
 }
 
 TEST_F(SpirvWriter_BuiltinPolyfillTest, AtomicMin_U32) {
-    auto* var = b.RootBlock()->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.u32()))));
+    auto* var = mod.root_block->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.u32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.u32());
     auto* func = b.Function("foo", ty.u32());
@@ -695,7 +695,7 @@
 }
 
 TEST_F(SpirvWriter_BuiltinPolyfillTest, AtomicOr) {
-    auto* var = b.RootBlock()->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -739,7 +739,7 @@
 }
 
 TEST_F(SpirvWriter_BuiltinPolyfillTest, AtomicStore) {
-    auto* var = b.RootBlock()->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.void_());
@@ -783,7 +783,7 @@
 }
 
 TEST_F(SpirvWriter_BuiltinPolyfillTest, AtomicSub) {
-    auto* var = b.RootBlock()->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
@@ -827,7 +827,7 @@
 }
 
 TEST_F(SpirvWriter_BuiltinPolyfillTest, AtomicXor) {
-    auto* var = b.RootBlock()->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
+    auto* var = mod.root_block->Append(b.Var(ty.ptr(workgroup, ty.atomic(ty.i32()))));
 
     auto* arg1 = b.FunctionParam("arg1", ty.i32());
     auto* func = b.Function("foo", ty.i32());
diff --git a/src/tint/lang/spirv/writer/raise/expand_implicit_splats.cc b/src/tint/lang/spirv/writer/raise/expand_implicit_splats.cc
index 775bf53..35353ec 100644
--- a/src/tint/lang/spirv/writer/raise/expand_implicit_splats.cc
+++ b/src/tint/lang/spirv/writer/raise/expand_implicit_splats.cc
@@ -28,14 +28,14 @@
 
 namespace {
 
-void Run(core::ir::Module* ir) {
-    core::ir::Builder b(*ir);
+void Run(core::ir::Module& ir) {
+    core::ir::Builder b{ir};
 
     // Find the instructions that use implicit splats and either modify them in place or record them
     // to be replaced in a second pass.
     Vector<core::ir::Binary*, 4> binary_worklist;
     Vector<core::ir::CoreBuiltinCall*, 4> builtin_worklist;
-    for (auto* inst : ir->instructions.Objects()) {
+    for (auto* inst : ir.instructions.Objects()) {
         if (!inst->Alive()) {
             continue;
         }
@@ -99,8 +99,8 @@
                 vts->AppendArg(binary->LHS());
                 vts->AppendArg(binary->RHS());
             }
-            if (auto name = ir->NameOf(binary)) {
-                ir->SetName(vts->Result(), name);
+            if (auto name = ir.NameOf(binary)) {
+                ir.SetName(vts->Result(), name);
             }
             binary->Result()->ReplaceAllUsesWith(vts->Result());
             binary->ReplaceWith(vts);
@@ -131,10 +131,10 @@
 
 }  // namespace
 
-Result<SuccessType, std::string> ExpandImplicitSplats(core::ir::Module* ir) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "ExpandImplicitSplats transform");
+Result<SuccessType> ExpandImplicitSplats(core::ir::Module& ir) {
+    auto result = ValidateAndDumpIfNeeded(ir, "ExpandImplicitSplats transform");
     if (!result) {
-        return result;
+        return result.Failure();
     }
 
     Run(ir);
diff --git a/src/tint/lang/spirv/writer/raise/expand_implicit_splats.h b/src/tint/lang/spirv/writer/raise/expand_implicit_splats.h
index 18bf1d8..0a58bfe 100644
--- a/src/tint/lang/spirv/writer/raise/expand_implicit_splats.h
+++ b/src/tint/lang/spirv/writer/raise/expand_implicit_splats.h
@@ -17,6 +17,7 @@
 
 #include <string>
 
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward declarations.
@@ -29,8 +30,8 @@
 /// ExpandImplicitSplats is a transform that expands implicit vector splat operands in construct
 /// instructions and binary instructions where not supported by SPIR-V.
 /// @param module the module to transform
-/// @returns an error string on failure
-Result<SuccessType, std::string> ExpandImplicitSplats(core::ir::Module* module);
+/// @returns success or failure
+Result<SuccessType> ExpandImplicitSplats(core::ir::Module& module);
 
 }  // namespace tint::spirv::writer::raise
 
diff --git a/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.cc b/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.cc
index 30322ec..b475ebb 100644
--- a/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.cc
+++ b/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.cc
@@ -31,13 +31,13 @@
 
 namespace {
 
-void Run(core::ir::Module* ir) {
-    core::ir::Builder b(*ir);
+void Run(core::ir::Module& ir) {
+    core::ir::Builder b{ir};
 
     // Find the instructions that need to be modified.
     Vector<core::ir::Binary*, 4> binary_worklist;
     Vector<core::ir::Convert*, 4> convert_worklist;
-    for (auto* inst : ir->instructions.Objects()) {
+    for (auto* inst : ir.instructions.Objects()) {
         if (!inst->Alive()) {
             continue;
         }
@@ -64,8 +64,8 @@
 
         // Helper to replace the instruction with a new one.
         auto replace = [&](core::ir::Instruction* inst) {
-            if (auto name = ir->NameOf(binary)) {
-                ir->SetName(inst->Result(), name);
+            if (auto name = ir.NameOf(binary)) {
+                ir.SetName(inst->Result(), name);
             }
             binary->Result()->ReplaceAllUsesWith(inst->Result());
             binary->ReplaceWith(inst);
@@ -142,8 +142,8 @@
 
         // Reconstruct the result matrix from the converted columns.
         auto* construct = b.Construct(out_mat, std::move(args));
-        if (auto name = ir->NameOf(convert)) {
-            ir->SetName(construct->Result(), name);
+        if (auto name = ir.NameOf(convert)) {
+            ir.SetName(construct->Result(), name);
         }
         convert->Result()->ReplaceAllUsesWith(construct->Result());
         convert->ReplaceWith(construct);
@@ -153,10 +153,10 @@
 
 }  // namespace
 
-Result<SuccessType, std::string> HandleMatrixArithmetic(core::ir::Module* ir) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "HandleMatrixArithmetic transform");
+Result<SuccessType> HandleMatrixArithmetic(core::ir::Module& ir) {
+    auto result = ValidateAndDumpIfNeeded(ir, "HandleMatrixArithmetic transform");
     if (!result) {
-        return result;
+        return result.Failure();
     }
 
     Run(ir);
diff --git a/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.h b/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.h
index 41b4a72..40cf739 100644
--- a/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.h
+++ b/src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.h
@@ -17,6 +17,7 @@
 
 #include <string>
 
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward declarations.
@@ -29,8 +30,8 @@
 /// HandleMatrixArithmetic is a transform that converts arithmetic instruction that use matrix into
 /// SPIR-V intrinsics or polyfills.
 /// @param module the module to transform
-/// @returns an error string on failure
-Result<SuccessType, std::string> HandleMatrixArithmetic(core::ir::Module* module);
+/// @returns success or failure
+Result<SuccessType> HandleMatrixArithmetic(core::ir::Module& module);
 
 }  // namespace tint::spirv::writer::raise
 
diff --git a/src/tint/lang/spirv/writer/raise/merge_return.cc b/src/tint/lang/spirv/writer/raise/merge_return.cc
index c09fdc6..75e40e6 100644
--- a/src/tint/lang/spirv/writer/raise/merge_return.cc
+++ b/src/tint/lang/spirv/writer/raise/merge_return.cc
@@ -33,13 +33,13 @@
 /// PIMPL state for the transform, for a single function.
 struct State {
     /// The IR module.
-    core::ir::Module* ir = nullptr;
+    core::ir::Module& ir;
 
     /// The IR builder.
-    core::ir::Builder b{*ir};
+    core::ir::Builder b{ir};
 
     /// The type manager.
-    core::type::Manager& ty{ir->Types()};
+    core::type::Manager& ty{ir.Types()};
 
     /// The "has not returned" flag.
     core::ir::Var* continue_execution = nullptr;
@@ -53,11 +53,7 @@
     core::ir::Return* fn_return = nullptr;
 
     /// A set of control instructions that transitively hold a return instruction
-    Hashset<core::ir::ControlInstruction*, 8> holds_return_;
-
-    /// Constructor
-    /// @param mod the module
-    explicit State(core::ir::Module* mod) : ir(mod) {}
+    Hashset<core::ir::ControlInstruction*, 8> holds_return_{};
 
     /// Process the function.
     /// @param fn the function to process
@@ -290,14 +286,14 @@
 
 }  // namespace
 
-Result<SuccessType, std::string> MergeReturn(core::ir::Module* ir) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "MergeReturn transform");
+Result<SuccessType> MergeReturn(core::ir::Module& ir) {
+    auto result = ValidateAndDumpIfNeeded(ir, "MergeReturn transform");
     if (!result) {
         return result;
     }
 
     // Process each function.
-    for (auto* fn : ir->functions) {
+    for (auto* fn : ir.functions) {
         State{ir}.Process(fn);
     }
 
diff --git a/src/tint/lang/spirv/writer/raise/merge_return.h b/src/tint/lang/spirv/writer/raise/merge_return.h
index 1ad6d87..182165c 100644
--- a/src/tint/lang/spirv/writer/raise/merge_return.h
+++ b/src/tint/lang/spirv/writer/raise/merge_return.h
@@ -17,6 +17,7 @@
 
 #include <string>
 
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward declarations.
@@ -29,8 +30,8 @@
 /// MergeReturn is a transform merges multiple return statements in a function into a single return
 /// at the end of the function.
 /// @param module the module to transform
-/// @returns an error string on failure
-Result<SuccessType, std::string> MergeReturn(core::ir::Module* module);
+/// @returns success or failure
+Result<SuccessType> MergeReturn(core::ir::Module& module);
 
 }  // namespace tint::spirv::writer::raise
 
diff --git a/src/tint/lang/spirv/writer/raise/merge_return_test.cc b/src/tint/lang/spirv/writer/raise/merge_return_test.cc
index a7a53a5..df94b94 100644
--- a/src/tint/lang/spirv/writer/raise/merge_return_test.cc
+++ b/src/tint/lang/spirv/writer/raise/merge_return_test.cc
@@ -497,7 +497,7 @@
 
 TEST_F(SpirvWriter_MergeReturnTest, IfElse_ThenStatements) {
     auto* global = b.Var(ty.ptr<private_, i32>());
-    b.RootBlock()->Append(global);
+    mod.root_block->Append(global);
 
     auto* cond = b.FunctionParam(ty.bool_());
     auto* func = b.Function("foo", ty.void_());
@@ -573,7 +573,7 @@
 // to make sure that creation order doesn't matter.
 TEST_F(SpirvWriter_MergeReturnTest, IfElse_ThenStatements_ReturnsCreatedInDifferentOrder) {
     auto* global = b.Var(ty.ptr<private_, i32>());
-    b.RootBlock()->Append(global);
+    mod.root_block->Append(global);
 
     auto* cond = b.FunctionParam(ty.bool_());
     auto* func = b.Function("foo", ty.void_());
@@ -647,7 +647,7 @@
 
 TEST_F(SpirvWriter_MergeReturnTest, IfElse_Nested) {
     auto* global = b.Var(ty.ptr<private_, i32>());
-    b.RootBlock()->Append(global);
+    mod.root_block->Append(global);
 
     auto* func = b.Function("foo", ty.i32());
     auto* condA = b.FunctionParam("condA", ty.bool_());
@@ -793,7 +793,7 @@
 
 TEST_F(SpirvWriter_MergeReturnTest, IfElse_Nested_TrivialMerge) {
     auto* global = b.Var(ty.ptr<private_, i32>());
-    b.RootBlock()->Append(global);
+    mod.root_block->Append(global);
 
     auto* func = b.Function("foo", ty.i32());
     auto* condA = b.FunctionParam("condA", ty.bool_());
@@ -914,7 +914,7 @@
 
 TEST_F(SpirvWriter_MergeReturnTest, IfElse_Nested_WithBasicBlockArguments) {
     auto* global = b.Var(ty.ptr<private_, i32>());
-    b.RootBlock()->Append(global);
+    mod.root_block->Append(global);
 
     auto* func = b.Function("foo", ty.i32());
     auto* condA = b.FunctionParam("condA", ty.bool_());
@@ -1213,7 +1213,7 @@
 
 TEST_F(SpirvWriter_MergeReturnTest, Loop_ConditionalReturnInBody) {
     auto* global = b.Var(ty.ptr<private_, i32>());
-    b.RootBlock()->Append(global);
+    mod.root_block->Append(global);
 
     auto* cond = b.FunctionParam(ty.bool_());
     auto* func = b.Function("foo", ty.i32());
@@ -1327,7 +1327,7 @@
 
 TEST_F(SpirvWriter_MergeReturnTest, Loop_ConditionalReturnInBody_UnreachableMerge) {
     auto* global = b.Var(ty.ptr<private_, i32>());
-    b.RootBlock()->Append(global);
+    mod.root_block->Append(global);
 
     auto* cond = b.FunctionParam(ty.bool_());
     auto* func = b.Function("foo", ty.i32());
@@ -1432,7 +1432,7 @@
 
 TEST_F(SpirvWriter_MergeReturnTest, DISABLED_Loop_WithBasicBlockArgumentsOnMerge) {
     auto* global = b.Var(ty.ptr<private_, i32>());
-    b.RootBlock()->Append(global);
+    mod.root_block->Append(global);
 
     auto* cond = b.FunctionParam(ty.bool_());
     auto* func = b.Function("foo", ty.i32());
@@ -1610,7 +1610,7 @@
 
 TEST_F(SpirvWriter_MergeReturnTest, Switch_ConditionalReturnInBody) {
     auto* global = b.Var(ty.ptr<private_, i32>());
-    b.RootBlock()->Append(global);
+    mod.root_block->Append(global);
 
     auto* cond = b.FunctionParam(ty.i32());
     auto* func = b.Function("foo", ty.i32());
diff --git a/src/tint/lang/spirv/writer/raise/raise.cc b/src/tint/lang/spirv/writer/raise/raise.cc
index c4be7ea..93989a4 100644
--- a/src/tint/lang/spirv/writer/raise/raise.cc
+++ b/src/tint/lang/spirv/writer/raise/raise.cc
@@ -25,6 +25,7 @@
 #include "src/tint/lang/core/ir/transform/multiplanar_external_texture.h"
 #include "src/tint/lang/core/ir/transform/robustness.h"
 #include "src/tint/lang/core/ir/transform/std140.h"
+#include "src/tint/lang/core/ir/transform/zero_init_workgroup_memory.h"
 #include "src/tint/lang/spirv/writer/raise/builtin_polyfill.h"
 #include "src/tint/lang/spirv/writer/raise/expand_implicit_splats.h"
 #include "src/tint/lang/spirv/writer/raise/handle_matrix_arithmetic.h"
@@ -34,7 +35,7 @@
 
 namespace tint::spirv::writer::raise {
 
-Result<SuccessType, std::string> Raise(core::ir::Module* module, const Options& options) {
+Result<SuccessType> Raise(core::ir::Module& module, const Options& options) {
 #define RUN_TRANSFORM(name, ...)         \
     do {                                 \
         auto result = name(__VA_ARGS__); \
@@ -70,6 +71,11 @@
     RUN_TRANSFORM(core::ir::transform::MultiplanarExternalTexture, module,
                   options.external_texture_options);
 
+    if (!options.disable_workgroup_init &&
+        !options.use_zero_initialize_workgroup_memory_extension) {
+        RUN_TRANSFORM(core::ir::transform::ZeroInitWorkgroupMemory, module);
+    }
+
     RUN_TRANSFORM(core::ir::transform::AddEmptyEntryPoint, module);
     RUN_TRANSFORM(core::ir::transform::Bgra8UnormPolyfill, module);
     RUN_TRANSFORM(core::ir::transform::BlockDecoratedStructs, module);
diff --git a/src/tint/lang/spirv/writer/raise/raise.h b/src/tint/lang/spirv/writer/raise/raise.h
index adaae92..18aa923 100644
--- a/src/tint/lang/spirv/writer/raise/raise.h
+++ b/src/tint/lang/spirv/writer/raise/raise.h
@@ -18,6 +18,7 @@
 #include <string>
 
 #include "src/tint/lang/spirv/writer/common/options.h"
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward declarations
@@ -30,8 +31,8 @@
 /// Raise a core IR module to the SPIR-V dialect of the IR.
 /// @param module the core IR module to raise to SPIR-V dialect
 /// @param options the SPIR-V writer options
-/// @returns success or an error string
-Result<SuccessType, std::string> Raise(core::ir::Module* module, const Options& options);
+/// @returns success or failure
+Result<SuccessType> Raise(core::ir::Module& module, const Options& options);
 
 }  // namespace tint::spirv::writer::raise
 
diff --git a/src/tint/lang/spirv/writer/raise/shader_io.cc b/src/tint/lang/spirv/writer/raise/shader_io.cc
index d4c60ed..f807c31 100644
--- a/src/tint/lang/spirv/writer/raise/shader_io.cc
+++ b/src/tint/lang/spirv/writer/raise/shader_io.cc
@@ -47,7 +47,7 @@
     core::ir::Value* frag_depth_clamp_args = nullptr;
 
     /// Constructor
-    StateImpl(core::ir::Module* mod, core::ir::Function* f, const ShaderIOConfig& cfg)
+    StateImpl(core::ir::Module& mod, core::ir::Function* f, const ShaderIOConfig& cfg)
         : ShaderIOBackendState(mod, f), config(cfg) {}
 
     /// Destructor
@@ -66,7 +66,7 @@
                   const char* name_suffix) {
         for (auto io : entries) {
             StringStream name;
-            name << ir->NameOf(func).Name();
+            name << ir.NameOf(func).Name();
 
             if (io.attributes.builtin) {
                 // SampleMask must be an array for Vulkan.
@@ -96,7 +96,7 @@
                 io.attributes.interpolation,
                 io.attributes.invariant,
             });
-            b.RootBlock()->Append(var);
+            ir.root_block->Append(var);
             vars.Push(var);
         }
     }
@@ -158,7 +158,7 @@
         // Create the clamp args struct and variable.
         if (!frag_depth_clamp_args) {
             // Check that there are no push constants in the module already.
-            for (auto* inst : *b.RootBlock()) {
+            for (auto* inst : *ir.root_block) {
                 if (auto* var = inst->As<core::ir::Var>()) {
                     auto* ptr = var->Result()->Type()->As<core::type::Pointer>();
                     if (ptr->AddressSpace() == core::AddressSpace::kPushConstant) {
@@ -168,16 +168,16 @@
             }
 
             // Declare the struct.
-            auto* str = ty.Struct(ir->symbols.Register("FragDepthClampArgs"),
+            auto* str = ty.Struct(ir.symbols.Register("FragDepthClampArgs"),
                                   {
-                                      {ir->symbols.Register("min"), ty.f32()},
-                                      {ir->symbols.Register("max"), ty.f32()},
+                                      {ir.symbols.Register("min"), ty.f32()},
+                                      {ir.symbols.Register("max"), ty.f32()},
                                   });
             str->SetStructFlag(core::type::kBlock);
 
             // Declare the variable.
             auto* var = b.Var("tint_frag_depth_clamp_args", ty.ptr(push_constant, str));
-            b.RootBlock()->Append(var);
+            ir.root_block->Append(var);
             frag_depth_clamp_args = var->Result();
         }
 
@@ -195,13 +195,13 @@
 };
 }  // namespace
 
-Result<SuccessType, std::string> ShaderIO(core::ir::Module* ir, const ShaderIOConfig& config) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "ShaderIO transform");
+Result<SuccessType> ShaderIO(core::ir::Module& ir, const ShaderIOConfig& config) {
+    auto result = ValidateAndDumpIfNeeded(ir, "ShaderIO transform");
     if (!result) {
         return result;
     }
 
-    core::ir::transform::RunShaderIOBase(ir, [&](core::ir::Module* mod, core::ir::Function* func) {
+    core::ir::transform::RunShaderIOBase(ir, [&](core::ir::Module& mod, core::ir::Function* func) {
         return std::make_unique<StateImpl>(mod, func, config);
     });
 
diff --git a/src/tint/lang/spirv/writer/raise/shader_io.h b/src/tint/lang/spirv/writer/raise/shader_io.h
index 41a2c64..adfd325 100644
--- a/src/tint/lang/spirv/writer/raise/shader_io.h
+++ b/src/tint/lang/spirv/writer/raise/shader_io.h
@@ -17,6 +17,7 @@
 
 #include <string>
 
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward declarations.
@@ -38,8 +39,8 @@
 /// global variables to prepare them for SPIR-V codegen.
 /// @param module the module to transform
 /// @param config the configuration
-/// @returns an error string on failure
-Result<SuccessType, std::string> ShaderIO(core::ir::Module* module, const ShaderIOConfig& config);
+/// @returns success or failure
+Result<SuccessType> ShaderIO(core::ir::Module& module, const ShaderIOConfig& config);
 
 }  // namespace tint::spirv::writer::raise
 
diff --git a/src/tint/lang/spirv/writer/raise/shader_io_test.cc b/src/tint/lang/spirv/writer/raise/shader_io_test.cc
index e4edbf9..343f778 100644
--- a/src/tint/lang/spirv/writer/raise/shader_io_test.cc
+++ b/src/tint/lang/spirv/writer/raise/shader_io_test.cc
@@ -690,7 +690,7 @@
                                  },
                              });
 
-    auto* buffer = b.RootBlock()->Append(b.Var(ty.ptr(storage, str_ty, read)));
+    auto* buffer = mod.root_block->Append(b.Var(ty.ptr(storage, str_ty, read)));
 
     auto* ep = b.Function("vert", str_ty);
     ep->SetStage(core::ir::Function::PipelineStage::kVertex);
diff --git a/src/tint/lang/spirv/writer/raise/var_for_dynamic_index.cc b/src/tint/lang/spirv/writer/raise/var_for_dynamic_index.cc
index e749a28..88d564f 100644
--- a/src/tint/lang/spirv/writer/raise/var_for_dynamic_index.cc
+++ b/src/tint/lang/spirv/writer/raise/var_for_dynamic_index.cc
@@ -111,12 +111,12 @@
     return result;
 }
 
-void Run(core::ir::Module* ir) {
-    core::ir::Builder builder(*ir);
+void Run(core::ir::Module& ir) {
+    core::ir::Builder builder(ir);
 
     // Find the access instructions that need replacing.
     Vector<AccessToReplace, 4> worklist;
-    for (auto* inst : ir->instructions.Objects()) {
+    for (auto* inst : ir.instructions.Objects()) {
         if (auto* access = inst->As<core::ir::Access>()) {
             if (auto to_replace = ShouldReplace(access)) {
                 worklist.Push(to_replace.value());
@@ -146,7 +146,7 @@
 
         // Declare a local variable and copy the source object to it.
         auto* local = object_to_local.GetOrCreate(source_object, [&] {
-            auto* decl = builder.Var(ir->Types().ptr(
+            auto* decl = builder.Var(ir.Types().ptr(
                 core::AddressSpace::kFunction, source_object->Type(), core::Access::kReadWrite));
             decl->SetInitializer(source_object);
             decl->InsertBefore(access);
@@ -170,7 +170,7 @@
         }
 
         core::ir::Instruction* new_access = builder.Access(
-            ir->Types().ptr(core::AddressSpace::kFunction, access_type, core::Access::kReadWrite),
+            ir.Types().ptr(core::AddressSpace::kFunction, access_type, core::Access::kReadWrite),
             local, indices);
         new_access->InsertBefore(access);
 
@@ -189,8 +189,8 @@
 
 }  // namespace
 
-Result<SuccessType, std::string> VarForDynamicIndex(core::ir::Module* ir) {
-    auto result = ValidateAndDumpIfNeeded(*ir, "VarForDynamicIndex transform");
+Result<SuccessType> VarForDynamicIndex(core::ir::Module& ir) {
+    auto result = ValidateAndDumpIfNeeded(ir, "VarForDynamicIndex transform");
     if (!result) {
         return result;
     }
diff --git a/src/tint/lang/spirv/writer/raise/var_for_dynamic_index.h b/src/tint/lang/spirv/writer/raise/var_for_dynamic_index.h
index 6878db4..c731558 100644
--- a/src/tint/lang/spirv/writer/raise/var_for_dynamic_index.h
+++ b/src/tint/lang/spirv/writer/raise/var_for_dynamic_index.h
@@ -17,6 +17,7 @@
 
 #include <string>
 
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward declarations.
@@ -31,8 +32,8 @@
 /// SPIR-V writer as there is no SPIR-V instruction that can dynamically index a non-pointer
 /// composite.
 /// @param module the module to transform
-/// @returns an error string on failure
-Result<SuccessType, std::string> VarForDynamicIndex(core::ir::Module* module);
+/// @returns success or failure
+Result<SuccessType> VarForDynamicIndex(core::ir::Module& module);
 
 }  // namespace tint::spirv::writer::raise
 
diff --git a/src/tint/lang/spirv/writer/var_test.cc b/src/tint/lang/spirv/writer/var_test.cc
index 2e37175..f6d1ac5 100644
--- a/src/tint/lang/spirv/writer/var_test.cc
+++ b/src/tint/lang/spirv/writer/var_test.cc
@@ -102,7 +102,7 @@
 }
 
 TEST_F(SpirvWriterTest, PrivateVar_NoInit) {
-    b.RootBlock()->Append(b.Var("v", ty.ptr<private_, i32>()));
+    mod.root_block->Append(b.Var("v", ty.ptr<private_, i32>()));
 
     ASSERT_TRUE(Generate()) << Error() << output_;
     EXPECT_INST("%v = OpVariable %_ptr_Private_int Private");
@@ -111,7 +111,7 @@
 TEST_F(SpirvWriterTest, PrivateVar_WithInit) {
     auto* v = b.Var("v", ty.ptr<private_, i32>());
     v->SetInitializer(b.Constant(42_i));
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     ASSERT_TRUE(Generate()) << Error() << output_;
     EXPECT_INST("%v = OpVariable %_ptr_Private_int Private %int_42");
@@ -120,7 +120,7 @@
 TEST_F(SpirvWriterTest, PrivateVar_LoadAndStore) {
     auto* v = b.Var("v", ty.ptr<private_, i32>());
     v->SetInitializer(b.Constant(42_i));
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
@@ -139,14 +139,14 @@
 }
 
 TEST_F(SpirvWriterTest, WorkgroupVar) {
-    b.RootBlock()->Append(b.Var("v", ty.ptr<workgroup, i32>()));
+    mod.root_block->Append(b.Var("v", ty.ptr<workgroup, i32>()));
 
     ASSERT_TRUE(Generate()) << Error() << output_;
     EXPECT_INST("%v = OpVariable %_ptr_Workgroup_int Workgroup");
 }
 
 TEST_F(SpirvWriterTest, WorkgroupVar_LoadAndStore) {
-    auto* v = b.RootBlock()->Append(b.Var("v", ty.ptr<workgroup, i32>()));
+    auto* v = mod.root_block->Append(b.Var("v", ty.ptr<workgroup, i32>()));
 
     auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kCompute,
                             std::array{1u, 1u, 1u});
@@ -166,10 +166,10 @@
 }
 
 TEST_F(SpirvWriterTest, WorkgroupVar_ZeroInitializeWithExtension) {
-    b.RootBlock()->Append(b.Var("v", ty.ptr<workgroup, i32>()));
+    mod.root_block->Append(b.Var("v", ty.ptr<workgroup, i32>()));
 
     // Create a writer with the zero_init_workgroup_memory flag set to `true`.
-    Printer gen(&mod, true);
+    Printer gen(mod, true);
     ASSERT_TRUE(Generate(gen)) << Error() << output_;
     EXPECT_INST("%4 = OpConstantNull %int");
     EXPECT_INST("%v = OpVariable %_ptr_Workgroup_int Workgroup %4");
@@ -178,7 +178,7 @@
 TEST_F(SpirvWriterTest, StorageVar_ReadOnly) {
     auto* v = b.Var("v", ty.ptr<storage, i32, read>());
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     ASSERT_TRUE(Generate()) << Error() << output_;
     EXPECT_INST(R"(
@@ -197,7 +197,7 @@
 TEST_F(SpirvWriterTest, StorageVar_LoadAndStore) {
     auto* v = b.Var("v", ty.ptr<storage, i32, read_write>());
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kCompute,
                             std::array{1u, 1u, 1u});
@@ -223,7 +223,7 @@
 TEST_F(SpirvWriterTest, StorageVar_WriteOnly) {
     auto* v = b.Var("v", ty.ptr<storage, i32, write>());
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kCompute,
                             std::array{1u, 1u, 1u});
@@ -248,7 +248,7 @@
 TEST_F(SpirvWriterTest, UniformVar) {
     auto* v = b.Var("v", ty.ptr<uniform, i32>());
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     ASSERT_TRUE(Generate()) << Error() << output_;
     EXPECT_INST(R"(
@@ -266,7 +266,7 @@
 TEST_F(SpirvWriterTest, UniformVar_Load) {
     auto* v = b.Var("v", ty.ptr<uniform, i32>());
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kCompute,
                             std::array{1u, 1u, 1u});
@@ -285,7 +285,7 @@
 
 TEST_F(SpirvWriterTest, PushConstantVar) {
     auto* v = b.Var("v", ty.ptr<push_constant, i32>());
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     ASSERT_TRUE(Generate()) << Error() << output_;
     EXPECT_INST(R"(
@@ -300,7 +300,7 @@
 
 TEST_F(SpirvWriterTest, PushConstantVar_Load) {
     auto* v = b.Var("v", ty.ptr<push_constant, i32>());
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.i32());
     b.Append(func->Block(), [&] {
@@ -320,7 +320,7 @@
 TEST_F(SpirvWriterTest, SamplerVar) {
     auto* v = b.Var("v", ty.ptr(core::AddressSpace::kHandle, ty.sampler(), core::Access::kRead));
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     ASSERT_TRUE(Generate()) << Error() << output_;
     EXPECT_INST(R"(
@@ -337,7 +337,7 @@
 TEST_F(SpirvWriterTest, SamplerVar_Load) {
     auto* v = b.Var("v", ty.ptr(core::AddressSpace::kHandle, ty.sampler(), core::Access::kRead));
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
@@ -356,7 +356,7 @@
                     ty.Get<core::type::SampledTexture>(core::type::TextureDimension::k2d, ty.f32()),
                     core::Access::kRead));
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     ASSERT_TRUE(Generate()) << Error() << output_;
     EXPECT_INST(R"(
@@ -376,7 +376,7 @@
                     ty.Get<core::type::SampledTexture>(core::type::TextureDimension::k2d, ty.f32()),
                     core::Access::kRead));
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
@@ -397,7 +397,7 @@
                                     core::type::StorageTexture::SubtypeFor(format, ty)),
                                 core::Access::kRead));
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     ASSERT_TRUE(Generate()) << Error() << output_;
     EXPECT_INST(R"(
@@ -420,7 +420,7 @@
                                     core::type::StorageTexture::SubtypeFor(format, ty)),
                                 core::Access::kRead));
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     ASSERT_TRUE(Generate()) << Error() << output_;
     EXPECT_INST(R"(
@@ -442,7 +442,7 @@
                                     core::type::StorageTexture::SubtypeFor(format, ty)),
                                 core::Access::kRead));
     v->SetBindingPoint(0, 0);
-    b.RootBlock()->Append(v);
+    mod.root_block->Append(v);
 
     ASSERT_TRUE(Generate()) << Error() << output_;
     EXPECT_INST(R"(
diff --git a/src/tint/lang/spirv/writer/writer.cc b/src/tint/lang/spirv/writer/writer.cc
index c8181bc..08a83fd 100644
--- a/src/tint/lang/spirv/writer/writer.cc
+++ b/src/tint/lang/spirv/writer/writer.cc
@@ -32,9 +32,9 @@
 Output::~Output() = default;
 Output::Output(const Output&) = default;
 
-Result<Output, std::string> Generate(const Program& program, const Options& options) {
+Result<Output> Generate(const Program& program, const Options& options) {
     if (!program.IsValid()) {
-        return std::string("input program is not valid");
+        return Failure{program.Diagnostics()};
     }
 
     bool zero_initialize_workgroup_memory =
@@ -46,25 +46,25 @@
         // Convert the AST program to an IR module.
         auto converted = wgsl::reader::ProgramToIR(program);
         if (!converted) {
-            return "IR converter: " + converted.Failure();
+            return converted.Failure();
         }
 
         auto ir = converted.Move();
 
         // Apply transforms as required by writer options.
-        auto remapper = core::ir::transform::BindingRemapper(&ir, options.binding_remapper_options);
+        auto remapper = core::ir::transform::BindingRemapper(ir, options.binding_remapper_options);
         if (!remapper) {
             return remapper.Failure();
         }
 
         // Raise the IR to the SPIR-V dialect.
-        auto raised = raise::Raise(&ir, options);
+        auto raised = raise::Raise(ir, options);
         if (!raised) {
             return std::move(raised.Failure());
         }
 
         // Generate the SPIR-V code.
-        auto impl = std::make_unique<Printer>(&ir, zero_initialize_workgroup_memory);
+        auto impl = std::make_unique<Printer>(ir, zero_initialize_workgroup_memory);
         auto spirv = impl->Generate();
         if (!spirv) {
             return std::move(spirv.Failure());
@@ -74,7 +74,7 @@
         // Sanitize the program.
         auto sanitized_result = Sanitize(program, options);
         if (!sanitized_result.program.IsValid()) {
-            return sanitized_result.program.Diagnostics().str();
+            return Failure{sanitized_result.program.Diagnostics()};
         }
 
         // Generate the SPIR-V code.
@@ -82,7 +82,7 @@
             sanitized_result.program, zero_initialize_workgroup_memory,
             options.experimental_require_subgroup_uniform_control_flow);
         if (!impl->Generate()) {
-            return impl->Diagnostics().str();
+            return Failure{impl->Diagnostics()};
         }
         output.spirv = std::move(impl->Result());
     }
diff --git a/src/tint/lang/spirv/writer/writer.h b/src/tint/lang/spirv/writer/writer.h
index 7845cb9..4eceb63 100644
--- a/src/tint/lang/spirv/writer/writer.h
+++ b/src/tint/lang/spirv/writer/writer.h
@@ -19,6 +19,7 @@
 
 #include "src/tint/lang/spirv/writer/common/options.h"
 #include "src/tint/lang/spirv/writer/output.h"
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward declarations
@@ -29,11 +30,11 @@
 namespace tint::spirv::writer {
 
 /// Generate SPIR-V for a program, according to a set of configuration options.
-/// The result will contain the SPIR-V or an error string.
+/// The result will contain the SPIR-V or failure.
 /// @param program the program to translate to SPIR-V
 /// @param options the configuration options to use when generating SPIR-V
-/// @returns the resulting SPIR-V and supplementary information, or an error string
-Result<Output, std::string> Generate(const Program& program, const Options& options);
+/// @returns the resulting SPIR-V and supplementary information, or failure.
+Result<Output> Generate(const Program& program, const Options& options);
 
 }  // namespace tint::spirv::writer
 
diff --git a/src/tint/lang/spirv/writer/writer_bench.cc b/src/tint/lang/spirv/writer/writer_bench.cc
index b514576..adef3df 100644
--- a/src/tint/lang/spirv/writer/writer_bench.cc
+++ b/src/tint/lang/spirv/writer/writer_bench.cc
@@ -30,7 +30,7 @@
     for (auto _ : state) {
         auto res = Generate(program, options);
         if (!res) {
-            state.SkipWithError(res.Failure());
+            state.SkipWithError(res.Failure().reason.str());
         }
     }
 }
diff --git a/src/tint/lang/wgsl/BUILD.bazel b/src/tint/lang/wgsl/BUILD.bazel
index d235e5b..83e4df2 100644
--- a/src/tint/lang/wgsl/BUILD.bazel
+++ b/src/tint/lang/wgsl/BUILD.bazel
@@ -26,11 +26,13 @@
 cc_library(
   name = "wgsl",
   srcs = [
+    "builtin_fn.cc",
     "diagnostic_rule.cc",
     "diagnostic_severity.cc",
     "extension.cc",
   ],
   hdrs = [
+    "builtin_fn.h",
     "diagnostic_rule.h",
     "diagnostic_severity.h",
     "extension.h",
@@ -74,6 +76,7 @@
     "//src/tint/lang/wgsl/helpers:test",
     "//src/tint/lang/wgsl/program",
     "//src/tint/lang/wgsl/reader",
+    "//src/tint/lang/wgsl/reader/lower",
     "//src/tint/lang/wgsl/reader/program_to_ir",
     "//src/tint/lang/wgsl/resolver",
     "//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/BUILD.cmake b/src/tint/lang/wgsl/BUILD.cmake
index c4ee2f3..c72aa5e 100644
--- a/src/tint/lang/wgsl/BUILD.cmake
+++ b/src/tint/lang/wgsl/BUILD.cmake
@@ -24,6 +24,8 @@
 include(lang/wgsl/ast/BUILD.cmake)
 include(lang/wgsl/helpers/BUILD.cmake)
 include(lang/wgsl/inspector/BUILD.cmake)
+include(lang/wgsl/intrinsic/BUILD.cmake)
+include(lang/wgsl/ir/BUILD.cmake)
 include(lang/wgsl/program/BUILD.cmake)
 include(lang/wgsl/reader/BUILD.cmake)
 include(lang/wgsl/resolver/BUILD.cmake)
@@ -35,6 +37,8 @@
 # Kind:      lib
 ################################################################################
 tint_add_target(tint_lang_wgsl lib
+  lang/wgsl/builtin_fn.cc
+  lang/wgsl/builtin_fn.h
   lang/wgsl/diagnostic_rule.cc
   lang/wgsl/diagnostic_rule.h
   lang/wgsl/diagnostic_severity.cc
@@ -77,6 +81,7 @@
   tint_lang_wgsl_helpers_test
   tint_lang_wgsl_program
   tint_lang_wgsl_reader
+  tint_lang_wgsl_reader_lower
   tint_lang_wgsl_reader_program_to_ir
   tint_lang_wgsl_resolver
   tint_lang_wgsl_sem
diff --git a/src/tint/lang/wgsl/BUILD.gn b/src/tint/lang/wgsl/BUILD.gn
index dafa9c3..4ddc480 100644
--- a/src/tint/lang/wgsl/BUILD.gn
+++ b/src/tint/lang/wgsl/BUILD.gn
@@ -31,6 +31,8 @@
 
 libtint_source_set("wgsl") {
   sources = [
+    "builtin_fn.cc",
+    "builtin_fn.h",
     "diagnostic_rule.cc",
     "diagnostic_rule.h",
     "diagnostic_severity.cc",
@@ -71,6 +73,7 @@
       "${tint_src_dir}/lang/wgsl/helpers:unittests",
       "${tint_src_dir}/lang/wgsl/program",
       "${tint_src_dir}/lang/wgsl/reader",
+      "${tint_src_dir}/lang/wgsl/reader/lower",
       "${tint_src_dir}/lang/wgsl/reader/program_to_ir",
       "${tint_src_dir}/lang/wgsl/resolver",
       "${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/ast/BUILD.bazel b/src/tint/lang/wgsl/ast/BUILD.bazel
index 1674ad6..3bed5ae 100644
--- a/src/tint/lang/wgsl/ast/BUILD.bazel
+++ b/src/tint/lang/wgsl/ast/BUILD.bazel
@@ -280,6 +280,7 @@
     "//src/tint/api/common",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
diff --git a/src/tint/lang/wgsl/ast/BUILD.cmake b/src/tint/lang/wgsl/ast/BUILD.cmake
index 9715482..f9293f9 100644
--- a/src/tint/lang/wgsl/ast/BUILD.cmake
+++ b/src/tint/lang/wgsl/ast/BUILD.cmake
@@ -281,6 +281,7 @@
   tint_api_common
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
diff --git a/src/tint/lang/wgsl/ast/BUILD.gn b/src/tint/lang/wgsl/ast/BUILD.gn
index 3732774..2cc22fe 100644
--- a/src/tint/lang/wgsl/ast/BUILD.gn
+++ b/src/tint/lang/wgsl/ast/BUILD.gn
@@ -282,6 +282,7 @@
       "${tint_src_dir}/api/common",
       "${tint_src_dir}/lang/core",
       "${tint_src_dir}/lang/core/constant",
+      "${tint_src_dir}/lang/core/ir",
       "${tint_src_dir}/lang/core/type",
       "${tint_src_dir}/lang/wgsl",
       "${tint_src_dir}/lang/wgsl/ast",
diff --git a/src/tint/lang/wgsl/ast/transform/BUILD.bazel b/src/tint/lang/wgsl/ast/transform/BUILD.bazel
index 6b75460..03b8500 100644
--- a/src/tint/lang/wgsl/ast/transform/BUILD.bazel
+++ b/src/tint/lang/wgsl/ast/transform/BUILD.bazel
@@ -166,6 +166,7 @@
     "//src/tint/api/options",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
diff --git a/src/tint/lang/wgsl/ast/transform/BUILD.cmake b/src/tint/lang/wgsl/ast/transform/BUILD.cmake
index a9dd202..1f7ecf6 100644
--- a/src/tint/lang/wgsl/ast/transform/BUILD.cmake
+++ b/src/tint/lang/wgsl/ast/transform/BUILD.cmake
@@ -165,6 +165,7 @@
   tint_api_options
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
diff --git a/src/tint/lang/wgsl/ast/transform/BUILD.gn b/src/tint/lang/wgsl/ast/transform/BUILD.gn
index 22706b8..958683e 100644
--- a/src/tint/lang/wgsl/ast/transform/BUILD.gn
+++ b/src/tint/lang/wgsl/ast/transform/BUILD.gn
@@ -168,6 +168,7 @@
       "${tint_src_dir}/api/options",
       "${tint_src_dir}/lang/core",
       "${tint_src_dir}/lang/core/constant",
+      "${tint_src_dir}/lang/core/ir",
       "${tint_src_dir}/lang/core/type",
       "${tint_src_dir}/lang/wgsl",
       "${tint_src_dir}/lang/wgsl/ast",
diff --git a/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc b/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc
index c065eea..3b655c3 100644
--- a/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc
+++ b/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc
@@ -41,7 +41,7 @@
     for (auto* fn : program.AST().Functions()) {
         if (auto* sem_fn = program.Sem().Get(fn)) {
             for (auto* builtin : sem_fn->DirectlyCalledBuiltins()) {
-                if (builtin->Fn() == core::BuiltinFn::kArrayLength) {
+                if (builtin->Fn() == wgsl::BuiltinFn::kArrayLength) {
                     return true;
                 }
             }
@@ -207,7 +207,7 @@
 
             auto* call = sem.Get(call_expr)->UnwrapMaterialize()->As<sem::Call>();
             auto* builtin = call->Target()->As<sem::BuiltinFn>();
-            if (!builtin || builtin->Fn() != core::BuiltinFn::kArrayLength) {
+            if (!builtin || builtin->Fn() != wgsl::BuiltinFn::kArrayLength) {
                 continue;
             }
 
diff --git a/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc b/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc
index 2c92aa3..ca324f1 100644
--- a/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc
+++ b/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc
@@ -858,13 +858,13 @@
         const uint32_t width = WidthOf(target);
 
         // select(target(v), low_limit, v < low_condition)
-        auto* select_low = b.Call(core::BuiltinFn::kSelect,                 //
+        auto* select_low = b.Call(wgsl::BuiltinFn::kSelect,                 //
                                   b.Call(T(target), "v"),                   //
                                   ScalarOrVector(width, limits.low_limit),  //
                                   b.LessThan("v", ScalarOrVector(width, limits.low_condition)));
 
         // select(high_limit, select_low, v < high_condition)
-        auto* select_high = b.Call(core::BuiltinFn::kSelect,                  //
+        auto* select_high = b.Call(wgsl::BuiltinFn::kSelect,                  //
                                    ScalarOrVector(width, limits.high_limit),  //
                                    select_low,                                //
                                    b.LessThan("v", ScalarOrVector(width, limits.high_condition)));
@@ -1080,28 +1080,28 @@
             call->Target(),  //
             [&](const sem::BuiltinFn* builtin) {
                 switch (builtin->Fn()) {
-                    case core::BuiltinFn::kAcosh:
+                    case wgsl::BuiltinFn::kAcosh:
                         if (cfg.builtins.acosh != Level::kNone) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return acosh(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kAsinh:
+                    case wgsl::BuiltinFn::kAsinh:
                         if (cfg.builtins.asinh) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return asinh(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kAtanh:
+                    case wgsl::BuiltinFn::kAtanh:
                         if (cfg.builtins.atanh != Level::kNone) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return atanh(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kClamp:
+                    case wgsl::BuiltinFn::kClamp:
                         if (cfg.builtins.clamp_int) {
                             auto& sig = builtin->Signature();
                             if (sig.parameters[0]->Type()->is_integer_scalar_or_vector()) {
@@ -1111,49 +1111,49 @@
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kCountLeadingZeros:
+                    case wgsl::BuiltinFn::kCountLeadingZeros:
                         if (cfg.builtins.count_leading_zeros) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return countLeadingZeros(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kCountTrailingZeros:
+                    case wgsl::BuiltinFn::kCountTrailingZeros:
                         if (cfg.builtins.count_trailing_zeros) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return countTrailingZeros(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kExtractBits:
+                    case wgsl::BuiltinFn::kExtractBits:
                         if (cfg.builtins.extract_bits != Level::kNone) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return extractBits(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kFirstLeadingBit:
+                    case wgsl::BuiltinFn::kFirstLeadingBit:
                         if (cfg.builtins.first_leading_bit) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return firstLeadingBit(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kFirstTrailingBit:
+                    case wgsl::BuiltinFn::kFirstTrailingBit:
                         if (cfg.builtins.first_trailing_bit) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return firstTrailingBit(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kInsertBits:
+                    case wgsl::BuiltinFn::kInsertBits:
                         if (cfg.builtins.insert_bits != Level::kNone) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return insertBits(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kReflect:
+                    case wgsl::BuiltinFn::kReflect:
                         // Only polyfill for vec2<f32>. See https://crbug.com/tint/1798 for
                         // more details.
                         if (cfg.builtins.reflect_vec2_f32) {
@@ -1166,14 +1166,14 @@
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kSaturate:
+                    case wgsl::BuiltinFn::kSaturate:
                         if (cfg.builtins.saturate) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return saturate(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kSign:
+                    case wgsl::BuiltinFn::kSign:
                         if (cfg.builtins.sign_int) {
                             auto* ty = builtin->ReturnType();
                             if (ty->is_signed_integer_scalar_or_vector()) {
@@ -1183,7 +1183,7 @@
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kTextureLoad:
+                    case wgsl::BuiltinFn::kTextureLoad:
                         if (cfg.builtins.bgra8unorm) {
                             auto& sig = builtin->Signature();
                             auto* tex = sig.Parameter(core::ParameterUsage::kTexture);
@@ -1199,7 +1199,7 @@
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kTextureSampleBaseClampToEdge:
+                    case wgsl::BuiltinFn::kTextureSampleBaseClampToEdge:
                         if (cfg.builtins.texture_sample_base_clamp_to_edge_2d_f32) {
                             auto& sig = builtin->Signature();
                             auto* tex = sig.Parameter(core::ParameterUsage::kTexture);
@@ -1213,7 +1213,7 @@
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kTextureStore:
+                    case wgsl::BuiltinFn::kTextureStore:
                         if (cfg.builtins.bgra8unorm) {
                             auto& sig = builtin->Signature();
                             auto* tex = sig.Parameter(core::ParameterUsage::kTexture);
@@ -1231,7 +1231,7 @@
                                             args.Push(arg);
                                         }
                                         return ctx.dst->Call(
-                                            tint::ToString(core::BuiltinFn::kTextureStore),
+                                            tint::ToString(wgsl::BuiltinFn::kTextureStore),
                                             std::move(args));
                                     });
                                     made_changes = true;
@@ -1240,7 +1240,7 @@
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kQuantizeToF16:
+                    case wgsl::BuiltinFn::kQuantizeToF16:
                         if (cfg.builtins.quantize_to_vec_f16) {
                             if (auto* vec = builtin->ReturnType()->As<core::type::Vector>()) {
                                 return builtin_polyfills.GetOrCreate(
@@ -1249,7 +1249,7 @@
                         }
                         return Symbol{};
 
-                    case core::BuiltinFn::kWorkgroupUniformLoad:
+                    case wgsl::BuiltinFn::kWorkgroupUniformLoad:
                         if (cfg.builtins.workgroup_uniform_load) {
                             return builtin_polyfills.GetOrCreate(builtin, [&] {
                                 return workgroupUniformLoad(builtin->ReturnType());
diff --git a/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc b/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc
index 8c9d3e2..95e1af0 100644
--- a/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc
+++ b/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc
@@ -154,12 +154,12 @@
                     return;
                 }
 
-                if (builtin->Fn() == core::BuiltinFn::kTextureStore) {
+                if (builtin->Fn() == wgsl::BuiltinFn::kTextureStore) {
                     // A call to textureStore() will always be a statement.
                     // Wrap it inside a conditional block.
                     auto* masked_call = b.If(b.Not(flag), b.Block(ctx.Clone(stmt->Declaration())));
                     ctx.Replace(stmt->Declaration(), masked_call);
-                } else if (builtin->IsAtomic() && builtin->Fn() != core::BuiltinFn::kAtomicLoad) {
+                } else if (builtin->IsAtomic() && builtin->Fn() != wgsl::BuiltinFn::kAtomicLoad) {
                     // A call to an atomic builtin can be a statement or an expression.
                     if (auto* call_stmt = stmt->Declaration()->As<CallStatement>();
                         call_stmt && call_stmt->expr == call) {
@@ -180,7 +180,7 @@
                         auto result = b.Sym();
                         Type result_ty;
                         const Statement* masked_call = nullptr;
-                        if (builtin->Fn() == core::BuiltinFn::kAtomicCompareExchangeWeak) {
+                        if (builtin->Fn() == wgsl::BuiltinFn::kAtomicCompareExchangeWeak) {
                             // Special case for atomicCompareExchangeWeak as we cannot name its
                             // result type. We have to declare an equivalent struct and copy the
                             // original member values over to it.
diff --git a/src/tint/lang/wgsl/ast/transform/helper_test.h b/src/tint/lang/wgsl/ast/transform/helper_test.h
index 836209a..de01f24 100644
--- a/src/tint/lang/wgsl/ast/transform/helper_test.h
+++ b/src/tint/lang/wgsl/ast/transform/helper_test.h
@@ -39,7 +39,7 @@
     wgsl::writer::Options options;
     auto result = wgsl::writer::Generate(program, options);
     if (!result) {
-        return "WGSL writer failed:\n" + result.Failure();
+        return result.Failure().reason.str();
     }
 
     auto res = result->wgsl;
diff --git a/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc b/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
index 21e5309..131f670 100644
--- a/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
+++ b/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
@@ -194,7 +194,7 @@
 
             if (builtin && !builtin->Parameters().IsEmpty() &&
                 builtin->Parameters()[0]->Type()->Is<core::type::ExternalTexture>() &&
-                builtin->Fn() != core::BuiltinFn::kTextureDimensions) {
+                builtin->Fn() != wgsl::BuiltinFn::kTextureDimensions) {
                 if (auto* var_user =
                         sem.GetVal(expr->args[0])->UnwrapLoad()->As<sem::VariableUser>()) {
                     auto it = new_binding_symbols.find(var_user->Variable());
@@ -208,9 +208,9 @@
                     auto& syms = it->second;
 
                     switch (builtin->Fn()) {
-                        case core::BuiltinFn::kTextureLoad:
+                        case wgsl::BuiltinFn::kTextureLoad:
                             return createTextureLoad(call, syms);
-                        case core::BuiltinFn::kTextureSampleBaseClampToEdge:
+                        case wgsl::BuiltinFn::kTextureSampleBaseClampToEdge:
                             return createTextureSampleBaseClampToEdge(expr, syms);
                         default:
                             break;
@@ -309,13 +309,13 @@
     /// builtin function.
     /// @param call_type determines which function body to generate
     /// @returns a statement list that makes of the body of the chosen function
-    auto buildTextureBuiltinBody(core::BuiltinFn call_type) {
+    auto buildTextureBuiltinBody(wgsl::BuiltinFn call_type) {
         tint::Vector<const Statement*, 16> stmts;
         const CallExpression* single_plane_call = nullptr;
         const CallExpression* plane_0_call = nullptr;
         const CallExpression* plane_1_call = nullptr;
         switch (call_type) {
-            case core::BuiltinFn::kTextureSampleBaseClampToEdge:
+            case wgsl::BuiltinFn::kTextureSampleBaseClampToEdge:
                 stmts.Push(b.Decl(b.Let(
                     "modifiedCoords", b.Mul(b.MemberAccessor("params", "coordTransformationMatrix"),
                                             b.Call<vec3<f32>>("coord", 1_a)))));
@@ -345,7 +345,7 @@
                 // textureSampleLevel(plane1, smp, plane1_clamped, 0.0);
                 plane_1_call = b.Call("textureSampleLevel", "plane1", "smp", "plane1_clamped", 0_a);
                 break;
-            case core::BuiltinFn::kTextureLoad:
+            case wgsl::BuiltinFn::kTextureLoad:
                 // textureLoad(plane0, coord, 0);
                 single_plane_call = b.Call("textureLoad", "plane0", "coord", 0_a);
                 // textureLoad(plane0, coord, 0);
@@ -439,7 +439,7 @@
                        b.Param("params", b.ty(params_struct_sym)),
                    },
                    b.ty.vec4(b.ty.f32()),
-                   buildTextureBuiltinBody(core::BuiltinFn::kTextureSampleBaseClampToEdge));
+                   buildTextureBuiltinBody(wgsl::BuiltinFn::kTextureSampleBaseClampToEdge));
         }
 
         return b.Call(texture_sample_external_sym, tint::Vector{
@@ -486,7 +486,7 @@
                        b.Param("params", b.ty(params_struct_sym)),
                    },
                    b.ty.vec4(b.ty.f32()),  //
-                   buildTextureBuiltinBody(core::BuiltinFn::kTextureLoad));
+                   buildTextureBuiltinBody(wgsl::BuiltinFn::kTextureLoad));
 
             return name;
         });
diff --git a/src/tint/lang/wgsl/ast/transform/robustness.cc b/src/tint/lang/wgsl/ast/transform/robustness.cc
index 09b85fd..b4df27d 100644
--- a/src/tint/lang/wgsl/ast/transform/robustness.cc
+++ b/src/tint/lang/wgsl/ast/transform/robustness.cc
@@ -246,7 +246,7 @@
                     // Must clamp, even if the index is constant.
 
                     auto* arr_ptr = b.AddressOf(ctx.Clone(expr->Object()->Declaration()));
-                    return b.Sub(b.Call(core::BuiltinFn::kArrayLength, arr_ptr), 1_u);
+                    return b.Sub(b.Call(wgsl::BuiltinFn::kArrayLength, arr_ptr), 1_u);
                 }
                 if (auto count = arr->ConstantCount()) {
                     if (expr->Index()->ConstantValue()) {
@@ -352,7 +352,7 @@
 
         auto* expr_sem = expr->Unwrap()->As<sem::IndexAccessorExpression>();
         auto idx = CastToU32(expr_sem->Index());
-        auto* clamped_idx = b.Call(core::BuiltinFn::kMin, idx, max);
+        auto* clamped_idx = b.Call(wgsl::BuiltinFn::kMin, idx, max);
         ctx.Replace(expr->Declaration()->index, clamped_idx);
     }
 
@@ -367,14 +367,14 @@
         }
 
         if (predicate) {
-            if (builtin->Fn() == core::BuiltinFn::kWorkgroupUniformLoad) {
+            if (builtin->Fn() == wgsl::BuiltinFn::kWorkgroupUniformLoad) {
                 // https://www.w3.org/TR/WGSL/#workgroupUniformLoad-builtin:
                 //  "Executes a control barrier synchronization function that affects memory and
                 //   atomic operations in the workgroup address space."
                 // Because the call acts like a control barrier, we need to make sure that we still
                 // trigger a workgroup barrier if the predicate fails.
                 PredicateCall(call, predicate,
-                              b.Block(b.CallStmt(b.Call(core::BuiltinFn::kWorkgroupBarrier))));
+                              b.Block(b.CallStmt(b.Call(wgsl::BuiltinFn::kWorkgroupBarrier))));
             } else {
                 PredicateCall(call, predicate);
             }
@@ -417,7 +417,7 @@
                 // let num_levels = textureNumLevels(texture-arg);
                 num_levels = b.Symbols().New("num_levels");
                 hoist.InsertBefore(
-                    stmt, b.Decl(b.Let(num_levels, b.Call(core::BuiltinFn::kTextureNumLevels,
+                    stmt, b.Decl(b.Let(num_levels, b.Call(wgsl::BuiltinFn::kTextureNumLevels,
                                                           ctx.Clone(texture_arg)))));
 
                 // predicate: level_idx < num_levels
@@ -442,12 +442,12 @@
                 // predicate: all(coords < textureDimensions(texture))
                 auto* dimensions =
                     level_idx.IsValid()
-                        ? b.Call(core::BuiltinFn::kTextureDimensions, ctx.Clone(texture_arg),
-                                 b.Call(core::BuiltinFn::kMin, b.Expr(level_idx),
+                        ? b.Call(wgsl::BuiltinFn::kTextureDimensions, ctx.Clone(texture_arg),
+                                 b.Call(wgsl::BuiltinFn::kMin, b.Expr(level_idx),
                                         b.Sub(num_levels, 1_a)))
-                        : b.Call(core::BuiltinFn::kTextureDimensions, ctx.Clone(texture_arg));
+                        : b.Call(wgsl::BuiltinFn::kTextureDimensions, ctx.Clone(texture_arg));
                 predicate =
-                    And(predicate, b.Call(core::BuiltinFn::kAll, b.LessThan(coords, dimensions)));
+                    And(predicate, b.Call(wgsl::BuiltinFn::kAll, b.LessThan(coords, dimensions)));
 
                 // Replace the level argument with `coord`
                 ctx.Replace(arg, b.Expr(coords));
@@ -457,7 +457,7 @@
         if (array_arg_idx >= 0) {
             // let array_idx = u32(array-arg)
             auto* arg = expr->args[static_cast<size_t>(array_arg_idx)];
-            auto* num_layers = b.Call(core::BuiltinFn::kTextureNumLayers, ctx.Clone(texture_arg));
+            auto* num_layers = b.Call(wgsl::BuiltinFn::kTextureNumLayers, ctx.Clone(texture_arg));
             auto array_idx = b.Symbols().New("array_idx");
             hoist.InsertBefore(stmt, b.Decl(b.Let(array_idx, CastToUnsigned(ctx.Clone(arg), 1u))));
 
@@ -502,10 +502,10 @@
                 const auto* arg = expr->args[static_cast<size_t>(level_arg_idx)];
                 level_idx = b.Symbols().New("level_idx");
                 const auto* num_levels =
-                    b.Call(core::BuiltinFn::kTextureNumLevels, ctx.Clone(texture_arg));
+                    b.Call(wgsl::BuiltinFn::kTextureNumLevels, ctx.Clone(texture_arg));
                 const auto* max = b.Sub(num_levels, 1_a);
                 hoist.InsertBefore(
-                    stmt, b.Decl(b.Let(level_idx, b.Call(core::BuiltinFn::kMin,
+                    stmt, b.Decl(b.Let(level_idx, b.Call(wgsl::BuiltinFn::kMin,
                                                          b.Call<u32>(ctx.Clone(arg)), max))));
                 ctx.Replace(arg, b.Expr(level_idx));
             }
@@ -519,9 +519,9 @@
                 const auto width = WidthOf(param->Type());
                 const auto* dimensions =
                     level_idx.IsValid()
-                        ? b.Call(core::BuiltinFn::kTextureDimensions, ctx.Clone(texture_arg),
+                        ? b.Call(wgsl::BuiltinFn::kTextureDimensions, ctx.Clone(texture_arg),
                                  level_idx)
-                        : b.Call(core::BuiltinFn::kTextureDimensions, ctx.Clone(texture_arg));
+                        : b.Call(wgsl::BuiltinFn::kTextureDimensions, ctx.Clone(texture_arg));
 
                 // dimensions is u32 or vecN<u32>
                 const auto* unsigned_max = b.Sub(dimensions, ScalarOrVec(b.Expr(1_a), width));
@@ -529,9 +529,9 @@
                     const auto* zero = ScalarOrVec(b.Expr(0_a), width);
                     const auto* signed_max = CastToSigned(unsigned_max, width);
                     ctx.Replace(arg,
-                                b.Call(core::BuiltinFn::kClamp, ctx.Clone(arg), zero, signed_max));
+                                b.Call(wgsl::BuiltinFn::kClamp, ctx.Clone(arg), zero, signed_max));
                 } else {
-                    ctx.Replace(arg, b.Call(core::BuiltinFn::kMin, ctx.Clone(arg), unsigned_max));
+                    ctx.Replace(arg, b.Call(wgsl::BuiltinFn::kMin, ctx.Clone(arg), unsigned_max));
                 }
             }
         }
@@ -540,14 +540,14 @@
         if (array_arg_idx >= 0) {
             auto* param = builtin->Parameters()[static_cast<size_t>(array_arg_idx)];
             auto* arg = expr->args[static_cast<size_t>(array_arg_idx)];
-            auto* num_layers = b.Call(core::BuiltinFn::kTextureNumLayers, ctx.Clone(texture_arg));
+            auto* num_layers = b.Call(wgsl::BuiltinFn::kTextureNumLayers, ctx.Clone(texture_arg));
 
             const auto* unsigned_max = b.Sub(num_layers, 1_a);
             if (param->Type()->is_signed_integer_scalar()) {
                 const auto* signed_max = CastToSigned(unsigned_max, 1u);
-                ctx.Replace(arg, b.Call(core::BuiltinFn::kClamp, ctx.Clone(arg), 0_a, signed_max));
+                ctx.Replace(arg, b.Call(wgsl::BuiltinFn::kClamp, ctx.Clone(arg), 0_a, signed_max));
             } else {
-                ctx.Replace(arg, b.Call(core::BuiltinFn::kMin, ctx.Clone(arg), unsigned_max));
+                ctx.Replace(arg, b.Call(wgsl::BuiltinFn::kMin, ctx.Clone(arg), unsigned_max));
             }
         }
     }
@@ -555,9 +555,9 @@
     /// @param type builtin type
     /// @returns true if the given builtin is a texture function that requires predication or
     /// clamping of arguments.
-    bool TextureBuiltinNeedsRobustness(core::BuiltinFn type) {
-        return type == core::BuiltinFn::kTextureLoad || type == core::BuiltinFn::kTextureStore ||
-               type == core::BuiltinFn::kTextureDimensions;
+    bool TextureBuiltinNeedsRobustness(wgsl::BuiltinFn type) {
+        return type == wgsl::BuiltinFn::kTextureLoad || type == wgsl::BuiltinFn::kTextureStore ||
+               type == wgsl::BuiltinFn::kTextureDimensions;
     }
 
     /// @returns a bitwise and of the two expressions, or the other expression if one is null.
diff --git a/src/tint/lang/wgsl/ast/transform/substitute_override.cc b/src/tint/lang/wgsl/ast/transform/substitute_override.cc
index 9f41800..833aa67 100644
--- a/src/tint/lang/wgsl/ast/transform/substitute_override.cc
+++ b/src/tint/lang/wgsl/ast/transform/substitute_override.cc
@@ -111,7 +111,7 @@
             if (auto* access = sem->UnwrapMaterialize()->As<sem::IndexAccessorExpression>()) {
                 if (access->Object()->UnwrapMaterialize()->Type()->HoldsAbstract() &&
                     access->Index()->Stage() == core::EvaluationStage::kOverride) {
-                    auto* obj = b.Call(core::str(core::BuiltinFn::kTintMaterialize),
+                    auto* obj = b.Call(wgsl::str(wgsl::BuiltinFn::kTintMaterialize),
                                        ctx.Clone(expr->object));
                     return b.IndexAccessor(obj, ctx.Clone(expr->index));
                 }
diff --git a/src/tint/lang/wgsl/builtin_fn.cc b/src/tint/lang/wgsl/builtin_fn.cc
new file mode 100644
index 0000000..5ba2090
--- /dev/null
+++ b/src/tint/lang/wgsl/builtin_fn.cc
@@ -0,0 +1,713 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by 'tools/src/cmd/gen' using the template:
+//   src/tint/lang/wgsl/builtin_fn.cc.tmpl
+//
+// To regenerate run: './tools/run gen'
+//
+//                       Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/lang/wgsl/builtin_fn.h"
+
+namespace tint::wgsl {
+
+BuiltinFn ParseBuiltinFn(std::string_view name) {
+    if (name == "abs") {
+        return BuiltinFn::kAbs;
+    }
+    if (name == "acos") {
+        return BuiltinFn::kAcos;
+    }
+    if (name == "acosh") {
+        return BuiltinFn::kAcosh;
+    }
+    if (name == "all") {
+        return BuiltinFn::kAll;
+    }
+    if (name == "any") {
+        return BuiltinFn::kAny;
+    }
+    if (name == "arrayLength") {
+        return BuiltinFn::kArrayLength;
+    }
+    if (name == "asin") {
+        return BuiltinFn::kAsin;
+    }
+    if (name == "asinh") {
+        return BuiltinFn::kAsinh;
+    }
+    if (name == "atan") {
+        return BuiltinFn::kAtan;
+    }
+    if (name == "atan2") {
+        return BuiltinFn::kAtan2;
+    }
+    if (name == "atanh") {
+        return BuiltinFn::kAtanh;
+    }
+    if (name == "ceil") {
+        return BuiltinFn::kCeil;
+    }
+    if (name == "clamp") {
+        return BuiltinFn::kClamp;
+    }
+    if (name == "cos") {
+        return BuiltinFn::kCos;
+    }
+    if (name == "cosh") {
+        return BuiltinFn::kCosh;
+    }
+    if (name == "countLeadingZeros") {
+        return BuiltinFn::kCountLeadingZeros;
+    }
+    if (name == "countOneBits") {
+        return BuiltinFn::kCountOneBits;
+    }
+    if (name == "countTrailingZeros") {
+        return BuiltinFn::kCountTrailingZeros;
+    }
+    if (name == "cross") {
+        return BuiltinFn::kCross;
+    }
+    if (name == "degrees") {
+        return BuiltinFn::kDegrees;
+    }
+    if (name == "determinant") {
+        return BuiltinFn::kDeterminant;
+    }
+    if (name == "distance") {
+        return BuiltinFn::kDistance;
+    }
+    if (name == "dot") {
+        return BuiltinFn::kDot;
+    }
+    if (name == "dot4I8Packed") {
+        return BuiltinFn::kDot4I8Packed;
+    }
+    if (name == "dot4U8Packed") {
+        return BuiltinFn::kDot4U8Packed;
+    }
+    if (name == "dpdx") {
+        return BuiltinFn::kDpdx;
+    }
+    if (name == "dpdxCoarse") {
+        return BuiltinFn::kDpdxCoarse;
+    }
+    if (name == "dpdxFine") {
+        return BuiltinFn::kDpdxFine;
+    }
+    if (name == "dpdy") {
+        return BuiltinFn::kDpdy;
+    }
+    if (name == "dpdyCoarse") {
+        return BuiltinFn::kDpdyCoarse;
+    }
+    if (name == "dpdyFine") {
+        return BuiltinFn::kDpdyFine;
+    }
+    if (name == "exp") {
+        return BuiltinFn::kExp;
+    }
+    if (name == "exp2") {
+        return BuiltinFn::kExp2;
+    }
+    if (name == "extractBits") {
+        return BuiltinFn::kExtractBits;
+    }
+    if (name == "faceForward") {
+        return BuiltinFn::kFaceForward;
+    }
+    if (name == "firstLeadingBit") {
+        return BuiltinFn::kFirstLeadingBit;
+    }
+    if (name == "firstTrailingBit") {
+        return BuiltinFn::kFirstTrailingBit;
+    }
+    if (name == "floor") {
+        return BuiltinFn::kFloor;
+    }
+    if (name == "fma") {
+        return BuiltinFn::kFma;
+    }
+    if (name == "fract") {
+        return BuiltinFn::kFract;
+    }
+    if (name == "frexp") {
+        return BuiltinFn::kFrexp;
+    }
+    if (name == "fwidth") {
+        return BuiltinFn::kFwidth;
+    }
+    if (name == "fwidthCoarse") {
+        return BuiltinFn::kFwidthCoarse;
+    }
+    if (name == "fwidthFine") {
+        return BuiltinFn::kFwidthFine;
+    }
+    if (name == "insertBits") {
+        return BuiltinFn::kInsertBits;
+    }
+    if (name == "inverseSqrt") {
+        return BuiltinFn::kInverseSqrt;
+    }
+    if (name == "ldexp") {
+        return BuiltinFn::kLdexp;
+    }
+    if (name == "length") {
+        return BuiltinFn::kLength;
+    }
+    if (name == "log") {
+        return BuiltinFn::kLog;
+    }
+    if (name == "log2") {
+        return BuiltinFn::kLog2;
+    }
+    if (name == "max") {
+        return BuiltinFn::kMax;
+    }
+    if (name == "min") {
+        return BuiltinFn::kMin;
+    }
+    if (name == "mix") {
+        return BuiltinFn::kMix;
+    }
+    if (name == "modf") {
+        return BuiltinFn::kModf;
+    }
+    if (name == "normalize") {
+        return BuiltinFn::kNormalize;
+    }
+    if (name == "pack2x16float") {
+        return BuiltinFn::kPack2X16Float;
+    }
+    if (name == "pack2x16snorm") {
+        return BuiltinFn::kPack2X16Snorm;
+    }
+    if (name == "pack2x16unorm") {
+        return BuiltinFn::kPack2X16Unorm;
+    }
+    if (name == "pack4x8snorm") {
+        return BuiltinFn::kPack4X8Snorm;
+    }
+    if (name == "pack4x8unorm") {
+        return BuiltinFn::kPack4X8Unorm;
+    }
+    if (name == "pow") {
+        return BuiltinFn::kPow;
+    }
+    if (name == "quantizeToF16") {
+        return BuiltinFn::kQuantizeToF16;
+    }
+    if (name == "radians") {
+        return BuiltinFn::kRadians;
+    }
+    if (name == "reflect") {
+        return BuiltinFn::kReflect;
+    }
+    if (name == "refract") {
+        return BuiltinFn::kRefract;
+    }
+    if (name == "reverseBits") {
+        return BuiltinFn::kReverseBits;
+    }
+    if (name == "round") {
+        return BuiltinFn::kRound;
+    }
+    if (name == "saturate") {
+        return BuiltinFn::kSaturate;
+    }
+    if (name == "select") {
+        return BuiltinFn::kSelect;
+    }
+    if (name == "sign") {
+        return BuiltinFn::kSign;
+    }
+    if (name == "sin") {
+        return BuiltinFn::kSin;
+    }
+    if (name == "sinh") {
+        return BuiltinFn::kSinh;
+    }
+    if (name == "smoothstep") {
+        return BuiltinFn::kSmoothstep;
+    }
+    if (name == "sqrt") {
+        return BuiltinFn::kSqrt;
+    }
+    if (name == "step") {
+        return BuiltinFn::kStep;
+    }
+    if (name == "storageBarrier") {
+        return BuiltinFn::kStorageBarrier;
+    }
+    if (name == "tan") {
+        return BuiltinFn::kTan;
+    }
+    if (name == "tanh") {
+        return BuiltinFn::kTanh;
+    }
+    if (name == "transpose") {
+        return BuiltinFn::kTranspose;
+    }
+    if (name == "trunc") {
+        return BuiltinFn::kTrunc;
+    }
+    if (name == "unpack2x16float") {
+        return BuiltinFn::kUnpack2X16Float;
+    }
+    if (name == "unpack2x16snorm") {
+        return BuiltinFn::kUnpack2X16Snorm;
+    }
+    if (name == "unpack2x16unorm") {
+        return BuiltinFn::kUnpack2X16Unorm;
+    }
+    if (name == "unpack4x8snorm") {
+        return BuiltinFn::kUnpack4X8Snorm;
+    }
+    if (name == "unpack4x8unorm") {
+        return BuiltinFn::kUnpack4X8Unorm;
+    }
+    if (name == "workgroupBarrier") {
+        return BuiltinFn::kWorkgroupBarrier;
+    }
+    if (name == "workgroupUniformLoad") {
+        return BuiltinFn::kWorkgroupUniformLoad;
+    }
+    if (name == "textureBarrier") {
+        return BuiltinFn::kTextureBarrier;
+    }
+    if (name == "textureDimensions") {
+        return BuiltinFn::kTextureDimensions;
+    }
+    if (name == "textureGather") {
+        return BuiltinFn::kTextureGather;
+    }
+    if (name == "textureGatherCompare") {
+        return BuiltinFn::kTextureGatherCompare;
+    }
+    if (name == "textureNumLayers") {
+        return BuiltinFn::kTextureNumLayers;
+    }
+    if (name == "textureNumLevels") {
+        return BuiltinFn::kTextureNumLevels;
+    }
+    if (name == "textureNumSamples") {
+        return BuiltinFn::kTextureNumSamples;
+    }
+    if (name == "textureSample") {
+        return BuiltinFn::kTextureSample;
+    }
+    if (name == "textureSampleBias") {
+        return BuiltinFn::kTextureSampleBias;
+    }
+    if (name == "textureSampleCompare") {
+        return BuiltinFn::kTextureSampleCompare;
+    }
+    if (name == "textureSampleCompareLevel") {
+        return BuiltinFn::kTextureSampleCompareLevel;
+    }
+    if (name == "textureSampleGrad") {
+        return BuiltinFn::kTextureSampleGrad;
+    }
+    if (name == "textureSampleLevel") {
+        return BuiltinFn::kTextureSampleLevel;
+    }
+    if (name == "textureSampleBaseClampToEdge") {
+        return BuiltinFn::kTextureSampleBaseClampToEdge;
+    }
+    if (name == "textureStore") {
+        return BuiltinFn::kTextureStore;
+    }
+    if (name == "textureLoad") {
+        return BuiltinFn::kTextureLoad;
+    }
+    if (name == "atomicLoad") {
+        return BuiltinFn::kAtomicLoad;
+    }
+    if (name == "atomicStore") {
+        return BuiltinFn::kAtomicStore;
+    }
+    if (name == "atomicAdd") {
+        return BuiltinFn::kAtomicAdd;
+    }
+    if (name == "atomicSub") {
+        return BuiltinFn::kAtomicSub;
+    }
+    if (name == "atomicMax") {
+        return BuiltinFn::kAtomicMax;
+    }
+    if (name == "atomicMin") {
+        return BuiltinFn::kAtomicMin;
+    }
+    if (name == "atomicAnd") {
+        return BuiltinFn::kAtomicAnd;
+    }
+    if (name == "atomicOr") {
+        return BuiltinFn::kAtomicOr;
+    }
+    if (name == "atomicXor") {
+        return BuiltinFn::kAtomicXor;
+    }
+    if (name == "atomicExchange") {
+        return BuiltinFn::kAtomicExchange;
+    }
+    if (name == "atomicCompareExchangeWeak") {
+        return BuiltinFn::kAtomicCompareExchangeWeak;
+    }
+    if (name == "subgroupBallot") {
+        return BuiltinFn::kSubgroupBallot;
+    }
+    if (name == "subgroupBroadcast") {
+        return BuiltinFn::kSubgroupBroadcast;
+    }
+    if (name == "_tint_materialize") {
+        return BuiltinFn::kTintMaterialize;
+    }
+    return BuiltinFn::kNone;
+}
+
+const char* str(BuiltinFn i) {
+    switch (i) {
+        case BuiltinFn::kNone:
+            return "<none>";
+        case BuiltinFn::kAbs:
+            return "abs";
+        case BuiltinFn::kAcos:
+            return "acos";
+        case BuiltinFn::kAcosh:
+            return "acosh";
+        case BuiltinFn::kAll:
+            return "all";
+        case BuiltinFn::kAny:
+            return "any";
+        case BuiltinFn::kArrayLength:
+            return "arrayLength";
+        case BuiltinFn::kAsin:
+            return "asin";
+        case BuiltinFn::kAsinh:
+            return "asinh";
+        case BuiltinFn::kAtan:
+            return "atan";
+        case BuiltinFn::kAtan2:
+            return "atan2";
+        case BuiltinFn::kAtanh:
+            return "atanh";
+        case BuiltinFn::kCeil:
+            return "ceil";
+        case BuiltinFn::kClamp:
+            return "clamp";
+        case BuiltinFn::kCos:
+            return "cos";
+        case BuiltinFn::kCosh:
+            return "cosh";
+        case BuiltinFn::kCountLeadingZeros:
+            return "countLeadingZeros";
+        case BuiltinFn::kCountOneBits:
+            return "countOneBits";
+        case BuiltinFn::kCountTrailingZeros:
+            return "countTrailingZeros";
+        case BuiltinFn::kCross:
+            return "cross";
+        case BuiltinFn::kDegrees:
+            return "degrees";
+        case BuiltinFn::kDeterminant:
+            return "determinant";
+        case BuiltinFn::kDistance:
+            return "distance";
+        case BuiltinFn::kDot:
+            return "dot";
+        case BuiltinFn::kDot4I8Packed:
+            return "dot4I8Packed";
+        case BuiltinFn::kDot4U8Packed:
+            return "dot4U8Packed";
+        case BuiltinFn::kDpdx:
+            return "dpdx";
+        case BuiltinFn::kDpdxCoarse:
+            return "dpdxCoarse";
+        case BuiltinFn::kDpdxFine:
+            return "dpdxFine";
+        case BuiltinFn::kDpdy:
+            return "dpdy";
+        case BuiltinFn::kDpdyCoarse:
+            return "dpdyCoarse";
+        case BuiltinFn::kDpdyFine:
+            return "dpdyFine";
+        case BuiltinFn::kExp:
+            return "exp";
+        case BuiltinFn::kExp2:
+            return "exp2";
+        case BuiltinFn::kExtractBits:
+            return "extractBits";
+        case BuiltinFn::kFaceForward:
+            return "faceForward";
+        case BuiltinFn::kFirstLeadingBit:
+            return "firstLeadingBit";
+        case BuiltinFn::kFirstTrailingBit:
+            return "firstTrailingBit";
+        case BuiltinFn::kFloor:
+            return "floor";
+        case BuiltinFn::kFma:
+            return "fma";
+        case BuiltinFn::kFract:
+            return "fract";
+        case BuiltinFn::kFrexp:
+            return "frexp";
+        case BuiltinFn::kFwidth:
+            return "fwidth";
+        case BuiltinFn::kFwidthCoarse:
+            return "fwidthCoarse";
+        case BuiltinFn::kFwidthFine:
+            return "fwidthFine";
+        case BuiltinFn::kInsertBits:
+            return "insertBits";
+        case BuiltinFn::kInverseSqrt:
+            return "inverseSqrt";
+        case BuiltinFn::kLdexp:
+            return "ldexp";
+        case BuiltinFn::kLength:
+            return "length";
+        case BuiltinFn::kLog:
+            return "log";
+        case BuiltinFn::kLog2:
+            return "log2";
+        case BuiltinFn::kMax:
+            return "max";
+        case BuiltinFn::kMin:
+            return "min";
+        case BuiltinFn::kMix:
+            return "mix";
+        case BuiltinFn::kModf:
+            return "modf";
+        case BuiltinFn::kNormalize:
+            return "normalize";
+        case BuiltinFn::kPack2X16Float:
+            return "pack2x16float";
+        case BuiltinFn::kPack2X16Snorm:
+            return "pack2x16snorm";
+        case BuiltinFn::kPack2X16Unorm:
+            return "pack2x16unorm";
+        case BuiltinFn::kPack4X8Snorm:
+            return "pack4x8snorm";
+        case BuiltinFn::kPack4X8Unorm:
+            return "pack4x8unorm";
+        case BuiltinFn::kPow:
+            return "pow";
+        case BuiltinFn::kQuantizeToF16:
+            return "quantizeToF16";
+        case BuiltinFn::kRadians:
+            return "radians";
+        case BuiltinFn::kReflect:
+            return "reflect";
+        case BuiltinFn::kRefract:
+            return "refract";
+        case BuiltinFn::kReverseBits:
+            return "reverseBits";
+        case BuiltinFn::kRound:
+            return "round";
+        case BuiltinFn::kSaturate:
+            return "saturate";
+        case BuiltinFn::kSelect:
+            return "select";
+        case BuiltinFn::kSign:
+            return "sign";
+        case BuiltinFn::kSin:
+            return "sin";
+        case BuiltinFn::kSinh:
+            return "sinh";
+        case BuiltinFn::kSmoothstep:
+            return "smoothstep";
+        case BuiltinFn::kSqrt:
+            return "sqrt";
+        case BuiltinFn::kStep:
+            return "step";
+        case BuiltinFn::kStorageBarrier:
+            return "storageBarrier";
+        case BuiltinFn::kTan:
+            return "tan";
+        case BuiltinFn::kTanh:
+            return "tanh";
+        case BuiltinFn::kTranspose:
+            return "transpose";
+        case BuiltinFn::kTrunc:
+            return "trunc";
+        case BuiltinFn::kUnpack2X16Float:
+            return "unpack2x16float";
+        case BuiltinFn::kUnpack2X16Snorm:
+            return "unpack2x16snorm";
+        case BuiltinFn::kUnpack2X16Unorm:
+            return "unpack2x16unorm";
+        case BuiltinFn::kUnpack4X8Snorm:
+            return "unpack4x8snorm";
+        case BuiltinFn::kUnpack4X8Unorm:
+            return "unpack4x8unorm";
+        case BuiltinFn::kWorkgroupBarrier:
+            return "workgroupBarrier";
+        case BuiltinFn::kWorkgroupUniformLoad:
+            return "workgroupUniformLoad";
+        case BuiltinFn::kTextureBarrier:
+            return "textureBarrier";
+        case BuiltinFn::kTextureDimensions:
+            return "textureDimensions";
+        case BuiltinFn::kTextureGather:
+            return "textureGather";
+        case BuiltinFn::kTextureGatherCompare:
+            return "textureGatherCompare";
+        case BuiltinFn::kTextureNumLayers:
+            return "textureNumLayers";
+        case BuiltinFn::kTextureNumLevels:
+            return "textureNumLevels";
+        case BuiltinFn::kTextureNumSamples:
+            return "textureNumSamples";
+        case BuiltinFn::kTextureSample:
+            return "textureSample";
+        case BuiltinFn::kTextureSampleBias:
+            return "textureSampleBias";
+        case BuiltinFn::kTextureSampleCompare:
+            return "textureSampleCompare";
+        case BuiltinFn::kTextureSampleCompareLevel:
+            return "textureSampleCompareLevel";
+        case BuiltinFn::kTextureSampleGrad:
+            return "textureSampleGrad";
+        case BuiltinFn::kTextureSampleLevel:
+            return "textureSampleLevel";
+        case BuiltinFn::kTextureSampleBaseClampToEdge:
+            return "textureSampleBaseClampToEdge";
+        case BuiltinFn::kTextureStore:
+            return "textureStore";
+        case BuiltinFn::kTextureLoad:
+            return "textureLoad";
+        case BuiltinFn::kAtomicLoad:
+            return "atomicLoad";
+        case BuiltinFn::kAtomicStore:
+            return "atomicStore";
+        case BuiltinFn::kAtomicAdd:
+            return "atomicAdd";
+        case BuiltinFn::kAtomicSub:
+            return "atomicSub";
+        case BuiltinFn::kAtomicMax:
+            return "atomicMax";
+        case BuiltinFn::kAtomicMin:
+            return "atomicMin";
+        case BuiltinFn::kAtomicAnd:
+            return "atomicAnd";
+        case BuiltinFn::kAtomicOr:
+            return "atomicOr";
+        case BuiltinFn::kAtomicXor:
+            return "atomicXor";
+        case BuiltinFn::kAtomicExchange:
+            return "atomicExchange";
+        case BuiltinFn::kAtomicCompareExchangeWeak:
+            return "atomicCompareExchangeWeak";
+        case BuiltinFn::kSubgroupBallot:
+            return "subgroupBallot";
+        case BuiltinFn::kSubgroupBroadcast:
+            return "subgroupBroadcast";
+        case BuiltinFn::kTintMaterialize:
+            return "_tint_materialize";
+    }
+    return "<unknown>";
+}
+
+bool IsCoarseDerivative(BuiltinFn f) {
+    return f == BuiltinFn::kDpdxCoarse || f == BuiltinFn::kDpdyCoarse ||
+           f == BuiltinFn::kFwidthCoarse;
+}
+
+bool IsFineDerivative(BuiltinFn f) {
+    return f == BuiltinFn::kDpdxFine || f == BuiltinFn::kDpdyFine || f == BuiltinFn::kFwidthFine;
+}
+
+bool IsDerivative(BuiltinFn f) {
+    return f == BuiltinFn::kDpdx || f == BuiltinFn::kDpdy || f == BuiltinFn::kFwidth ||
+           IsCoarseDerivative(f) || IsFineDerivative(f);
+}
+
+bool IsTexture(BuiltinFn f) {
+    return IsImageQuery(f) ||                                //
+           f == BuiltinFn::kTextureGather ||                 //
+           f == BuiltinFn::kTextureGatherCompare ||          //
+           f == BuiltinFn::kTextureLoad ||                   //
+           f == BuiltinFn::kTextureSample ||                 //
+           f == BuiltinFn::kTextureSampleBaseClampToEdge ||  //
+           f == BuiltinFn::kTextureSampleBias ||             //
+           f == BuiltinFn::kTextureSampleCompare ||          //
+           f == BuiltinFn::kTextureSampleCompareLevel ||     //
+           f == BuiltinFn::kTextureSampleGrad ||             //
+           f == BuiltinFn::kTextureSampleLevel ||            //
+           f == BuiltinFn::kTextureStore;
+}
+
+bool IsImageQuery(BuiltinFn f) {
+    return f == BuiltinFn::kTextureDimensions || f == BuiltinFn::kTextureNumLayers ||
+           f == BuiltinFn::kTextureNumLevels || f == BuiltinFn::kTextureNumSamples;
+}
+
+bool IsDataPacking(BuiltinFn f) {
+    return f == BuiltinFn::kPack4X8Snorm || f == BuiltinFn::kPack4X8Unorm ||
+           f == BuiltinFn::kPack2X16Snorm || f == BuiltinFn::kPack2X16Unorm ||
+           f == BuiltinFn::kPack2X16Float;
+}
+
+bool IsDataUnpacking(BuiltinFn f) {
+    return f == BuiltinFn::kUnpack4X8Snorm || f == BuiltinFn::kUnpack4X8Unorm ||
+           f == BuiltinFn::kUnpack2X16Snorm || f == BuiltinFn::kUnpack2X16Unorm ||
+           f == BuiltinFn::kUnpack2X16Float;
+}
+
+bool IsBarrier(BuiltinFn f) {
+    return f == BuiltinFn::kWorkgroupBarrier || f == BuiltinFn::kStorageBarrier ||
+           f == BuiltinFn::kTextureBarrier;
+}
+
+bool IsAtomic(BuiltinFn f) {
+    return f == BuiltinFn::kAtomicLoad || f == BuiltinFn::kAtomicStore ||
+           f == BuiltinFn::kAtomicAdd || f == BuiltinFn::kAtomicSub || f == BuiltinFn::kAtomicMax ||
+           f == BuiltinFn::kAtomicMin || f == BuiltinFn::kAtomicAnd || f == BuiltinFn::kAtomicOr ||
+           f == BuiltinFn::kAtomicXor || f == BuiltinFn::kAtomicExchange ||
+           f == BuiltinFn::kAtomicCompareExchangeWeak;
+}
+
+bool IsDP4a(BuiltinFn f) {
+    return f == BuiltinFn::kDot4I8Packed || f == BuiltinFn::kDot4U8Packed;
+}
+
+bool IsSubgroup(BuiltinFn f) {
+    return f == BuiltinFn::kSubgroupBallot || f == BuiltinFn::kSubgroupBroadcast;
+}
+
+bool HasSideEffects(BuiltinFn f) {
+    switch (f) {
+        case BuiltinFn::kAtomicAdd:
+        case BuiltinFn::kAtomicAnd:
+        case BuiltinFn::kAtomicCompareExchangeWeak:
+        case BuiltinFn::kAtomicExchange:
+        case BuiltinFn::kAtomicMax:
+        case BuiltinFn::kAtomicMin:
+        case BuiltinFn::kAtomicOr:
+        case BuiltinFn::kAtomicStore:
+        case BuiltinFn::kAtomicSub:
+        case BuiltinFn::kAtomicXor:
+        case BuiltinFn::kTextureStore:
+        case BuiltinFn::kWorkgroupUniformLoad:
+            return true;
+        default:
+            break;
+    }
+    return false;
+}
+
+}  // namespace tint::wgsl
diff --git a/src/tint/lang/wgsl/builtin_fn.cc.tmpl b/src/tint/lang/wgsl/builtin_fn.cc.tmpl
new file mode 100644
index 0000000..cf79bee
--- /dev/null
+++ b/src/tint/lang/wgsl/builtin_fn.cc.tmpl
@@ -0,0 +1,132 @@
+{{- /*
+--------------------------------------------------------------------------------
+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/wgsl/wgsl.def" -}}
+#include "src/tint/lang/wgsl/builtin_fn.h"
+
+namespace tint::wgsl {
+
+BuiltinFn ParseBuiltinFn(std::string_view name) {
+{{- range $I.Sem.Builtins  }}
+    if (name == "{{.Name}}") {
+        return BuiltinFn::k{{PascalCase .Name}};
+    }
+{{- end  }}
+    return BuiltinFn::kNone;
+}
+
+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>";
+}
+
+bool IsCoarseDerivative(BuiltinFn f) {
+    return f == BuiltinFn::kDpdxCoarse || f == BuiltinFn::kDpdyCoarse ||
+           f == BuiltinFn::kFwidthCoarse;
+}
+
+bool IsFineDerivative(BuiltinFn f) {
+    return f == BuiltinFn::kDpdxFine || f == BuiltinFn::kDpdyFine ||
+           f == BuiltinFn::kFwidthFine;
+}
+
+bool IsDerivative(BuiltinFn f) {
+    return f == BuiltinFn::kDpdx || f == BuiltinFn::kDpdy ||
+           f == BuiltinFn::kFwidth || IsCoarseDerivative(f) ||
+           IsFineDerivative(f);
+}
+
+bool IsTexture(BuiltinFn f) {
+    return IsImageQuery(f) ||                                //
+           f == BuiltinFn::kTextureGather ||                 //
+           f == BuiltinFn::kTextureGatherCompare ||          //
+           f == BuiltinFn::kTextureLoad ||                   //
+           f == BuiltinFn::kTextureSample ||                 //
+           f == BuiltinFn::kTextureSampleBaseClampToEdge ||  //
+           f == BuiltinFn::kTextureSampleBias ||             //
+           f == BuiltinFn::kTextureSampleCompare ||          //
+           f == BuiltinFn::kTextureSampleCompareLevel ||     //
+           f == BuiltinFn::kTextureSampleGrad ||             //
+           f == BuiltinFn::kTextureSampleLevel ||            //
+           f == BuiltinFn::kTextureStore;
+}
+
+bool IsImageQuery(BuiltinFn f) {
+    return f == BuiltinFn::kTextureDimensions ||
+           f == BuiltinFn::kTextureNumLayers || f == BuiltinFn::kTextureNumLevels ||
+           f == BuiltinFn::kTextureNumSamples;
+}
+
+bool IsDataPacking(BuiltinFn f) {
+    return f == BuiltinFn::kPack4X8Snorm || f == BuiltinFn::kPack4X8Unorm ||
+           f == BuiltinFn::kPack2X16Snorm || f == BuiltinFn::kPack2X16Unorm ||
+           f == BuiltinFn::kPack2X16Float;
+}
+
+bool IsDataUnpacking(BuiltinFn f) {
+    return f == BuiltinFn::kUnpack4X8Snorm || f == BuiltinFn::kUnpack4X8Unorm ||
+           f == BuiltinFn::kUnpack2X16Snorm || f == BuiltinFn::kUnpack2X16Unorm ||
+           f == BuiltinFn::kUnpack2X16Float;
+}
+
+bool IsBarrier(BuiltinFn f) {
+    return f == BuiltinFn::kWorkgroupBarrier || f == BuiltinFn::kStorageBarrier ||
+           f == BuiltinFn::kTextureBarrier;
+}
+
+bool IsAtomic(BuiltinFn f) {
+    return f == BuiltinFn::kAtomicLoad || f == BuiltinFn::kAtomicStore ||
+           f == BuiltinFn::kAtomicAdd || f == BuiltinFn::kAtomicSub ||
+           f == BuiltinFn::kAtomicMax || f == BuiltinFn::kAtomicMin ||
+           f == BuiltinFn::kAtomicAnd || f == BuiltinFn::kAtomicOr ||
+           f == BuiltinFn::kAtomicXor || f == BuiltinFn::kAtomicExchange ||
+           f == BuiltinFn::kAtomicCompareExchangeWeak;
+}
+
+bool IsDP4a(BuiltinFn f) {
+    return f == BuiltinFn::kDot4I8Packed || f == BuiltinFn::kDot4U8Packed;
+}
+
+bool IsSubgroup(BuiltinFn f) {
+    return f == BuiltinFn::kSubgroupBallot || f == BuiltinFn::kSubgroupBroadcast;
+}
+
+bool HasSideEffects(BuiltinFn f) {
+    switch (f) {
+        case BuiltinFn::kAtomicAdd:
+        case BuiltinFn::kAtomicAnd:
+        case BuiltinFn::kAtomicCompareExchangeWeak:
+        case BuiltinFn::kAtomicExchange:
+        case BuiltinFn::kAtomicMax:
+        case BuiltinFn::kAtomicMin:
+        case BuiltinFn::kAtomicOr:
+        case BuiltinFn::kAtomicStore:
+        case BuiltinFn::kAtomicSub:
+        case BuiltinFn::kAtomicXor:
+        case BuiltinFn::kTextureStore:
+        case BuiltinFn::kWorkgroupUniformLoad:
+            return true;
+        default:
+            break;
+    }
+    return false;
+}
+
+}  // namespace tint::wgsl
diff --git a/src/tint/lang/wgsl/builtin_fn.h b/src/tint/lang/wgsl/builtin_fn.h
new file mode 100644
index 0000000..724d36d
--- /dev/null
+++ b/src/tint/lang/wgsl/builtin_fn.h
@@ -0,0 +1,478 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by 'tools/src/cmd/gen' using the template:
+//   src/tint/lang/wgsl/builtin_fn.h.tmpl
+//
+// To regenerate run: './tools/run gen'
+//
+//                       Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_TINT_LANG_WGSL_BUILTIN_FN_H_
+#define SRC_TINT_LANG_WGSL_BUILTIN_FN_H_
+
+#include <cstdint>
+#include <string>
+
+#include "src/tint/utils/traits/traits.h"
+
+// \cond DO_NOT_DOCUMENT
+namespace tint::wgsl {
+
+/// Enumerator of all builtin functions
+enum class BuiltinFn : uint8_t {
+    kAbs,
+    kAcos,
+    kAcosh,
+    kAll,
+    kAny,
+    kArrayLength,
+    kAsin,
+    kAsinh,
+    kAtan,
+    kAtan2,
+    kAtanh,
+    kCeil,
+    kClamp,
+    kCos,
+    kCosh,
+    kCountLeadingZeros,
+    kCountOneBits,
+    kCountTrailingZeros,
+    kCross,
+    kDegrees,
+    kDeterminant,
+    kDistance,
+    kDot,
+    kDot4I8Packed,
+    kDot4U8Packed,
+    kDpdx,
+    kDpdxCoarse,
+    kDpdxFine,
+    kDpdy,
+    kDpdyCoarse,
+    kDpdyFine,
+    kExp,
+    kExp2,
+    kExtractBits,
+    kFaceForward,
+    kFirstLeadingBit,
+    kFirstTrailingBit,
+    kFloor,
+    kFma,
+    kFract,
+    kFrexp,
+    kFwidth,
+    kFwidthCoarse,
+    kFwidthFine,
+    kInsertBits,
+    kInverseSqrt,
+    kLdexp,
+    kLength,
+    kLog,
+    kLog2,
+    kMax,
+    kMin,
+    kMix,
+    kModf,
+    kNormalize,
+    kPack2X16Float,
+    kPack2X16Snorm,
+    kPack2X16Unorm,
+    kPack4X8Snorm,
+    kPack4X8Unorm,
+    kPow,
+    kQuantizeToF16,
+    kRadians,
+    kReflect,
+    kRefract,
+    kReverseBits,
+    kRound,
+    kSaturate,
+    kSelect,
+    kSign,
+    kSin,
+    kSinh,
+    kSmoothstep,
+    kSqrt,
+    kStep,
+    kStorageBarrier,
+    kTan,
+    kTanh,
+    kTranspose,
+    kTrunc,
+    kUnpack2X16Float,
+    kUnpack2X16Snorm,
+    kUnpack2X16Unorm,
+    kUnpack4X8Snorm,
+    kUnpack4X8Unorm,
+    kWorkgroupBarrier,
+    kWorkgroupUniformLoad,
+    kTextureBarrier,
+    kTextureDimensions,
+    kTextureGather,
+    kTextureGatherCompare,
+    kTextureNumLayers,
+    kTextureNumLevels,
+    kTextureNumSamples,
+    kTextureSample,
+    kTextureSampleBias,
+    kTextureSampleCompare,
+    kTextureSampleCompareLevel,
+    kTextureSampleGrad,
+    kTextureSampleLevel,
+    kTextureSampleBaseClampToEdge,
+    kTextureStore,
+    kTextureLoad,
+    kAtomicLoad,
+    kAtomicStore,
+    kAtomicAdd,
+    kAtomicSub,
+    kAtomicMax,
+    kAtomicMin,
+    kAtomicAnd,
+    kAtomicOr,
+    kAtomicXor,
+    kAtomicExchange,
+    kAtomicCompareExchangeWeak,
+    kSubgroupBallot,
+    kSubgroupBroadcast,
+    kTintMaterialize,
+    kNone,
+};
+
+/// Matches the BuiltinFn by name
+/// @param name the builtin name to parse
+/// @returns the parsed BuiltinFn, or BuiltinFn::kNone if `name` did not
+/// match any builtin function.
+BuiltinFn ParseBuiltinFn(std::string_view name);
+
+/// @returns the name of the builtin function type. The spelling, including
+/// case, matches the name in the WGSL spec.
+const char* str(BuiltinFn i);
+
+/// Emits the name of the builtin function type. The spelling, including case,
+/// matches the name in the WGSL spec.
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& o, BuiltinFn i) {
+    return o << str(i);
+}
+
+/// All builtin functions
+constexpr BuiltinFn kBuiltinFns[] = {
+    BuiltinFn::kAbs,
+    BuiltinFn::kAcos,
+    BuiltinFn::kAcosh,
+    BuiltinFn::kAll,
+    BuiltinFn::kAny,
+    BuiltinFn::kArrayLength,
+    BuiltinFn::kAsin,
+    BuiltinFn::kAsinh,
+    BuiltinFn::kAtan,
+    BuiltinFn::kAtan2,
+    BuiltinFn::kAtanh,
+    BuiltinFn::kCeil,
+    BuiltinFn::kClamp,
+    BuiltinFn::kCos,
+    BuiltinFn::kCosh,
+    BuiltinFn::kCountLeadingZeros,
+    BuiltinFn::kCountOneBits,
+    BuiltinFn::kCountTrailingZeros,
+    BuiltinFn::kCross,
+    BuiltinFn::kDegrees,
+    BuiltinFn::kDeterminant,
+    BuiltinFn::kDistance,
+    BuiltinFn::kDot,
+    BuiltinFn::kDot4I8Packed,
+    BuiltinFn::kDot4U8Packed,
+    BuiltinFn::kDpdx,
+    BuiltinFn::kDpdxCoarse,
+    BuiltinFn::kDpdxFine,
+    BuiltinFn::kDpdy,
+    BuiltinFn::kDpdyCoarse,
+    BuiltinFn::kDpdyFine,
+    BuiltinFn::kExp,
+    BuiltinFn::kExp2,
+    BuiltinFn::kExtractBits,
+    BuiltinFn::kFaceForward,
+    BuiltinFn::kFirstLeadingBit,
+    BuiltinFn::kFirstTrailingBit,
+    BuiltinFn::kFloor,
+    BuiltinFn::kFma,
+    BuiltinFn::kFract,
+    BuiltinFn::kFrexp,
+    BuiltinFn::kFwidth,
+    BuiltinFn::kFwidthCoarse,
+    BuiltinFn::kFwidthFine,
+    BuiltinFn::kInsertBits,
+    BuiltinFn::kInverseSqrt,
+    BuiltinFn::kLdexp,
+    BuiltinFn::kLength,
+    BuiltinFn::kLog,
+    BuiltinFn::kLog2,
+    BuiltinFn::kMax,
+    BuiltinFn::kMin,
+    BuiltinFn::kMix,
+    BuiltinFn::kModf,
+    BuiltinFn::kNormalize,
+    BuiltinFn::kPack2X16Float,
+    BuiltinFn::kPack2X16Snorm,
+    BuiltinFn::kPack2X16Unorm,
+    BuiltinFn::kPack4X8Snorm,
+    BuiltinFn::kPack4X8Unorm,
+    BuiltinFn::kPow,
+    BuiltinFn::kQuantizeToF16,
+    BuiltinFn::kRadians,
+    BuiltinFn::kReflect,
+    BuiltinFn::kRefract,
+    BuiltinFn::kReverseBits,
+    BuiltinFn::kRound,
+    BuiltinFn::kSaturate,
+    BuiltinFn::kSelect,
+    BuiltinFn::kSign,
+    BuiltinFn::kSin,
+    BuiltinFn::kSinh,
+    BuiltinFn::kSmoothstep,
+    BuiltinFn::kSqrt,
+    BuiltinFn::kStep,
+    BuiltinFn::kStorageBarrier,
+    BuiltinFn::kTan,
+    BuiltinFn::kTanh,
+    BuiltinFn::kTranspose,
+    BuiltinFn::kTrunc,
+    BuiltinFn::kUnpack2X16Float,
+    BuiltinFn::kUnpack2X16Snorm,
+    BuiltinFn::kUnpack2X16Unorm,
+    BuiltinFn::kUnpack4X8Snorm,
+    BuiltinFn::kUnpack4X8Unorm,
+    BuiltinFn::kWorkgroupBarrier,
+    BuiltinFn::kWorkgroupUniformLoad,
+    BuiltinFn::kTextureBarrier,
+    BuiltinFn::kTextureDimensions,
+    BuiltinFn::kTextureGather,
+    BuiltinFn::kTextureGatherCompare,
+    BuiltinFn::kTextureNumLayers,
+    BuiltinFn::kTextureNumLevels,
+    BuiltinFn::kTextureNumSamples,
+    BuiltinFn::kTextureSample,
+    BuiltinFn::kTextureSampleBias,
+    BuiltinFn::kTextureSampleCompare,
+    BuiltinFn::kTextureSampleCompareLevel,
+    BuiltinFn::kTextureSampleGrad,
+    BuiltinFn::kTextureSampleLevel,
+    BuiltinFn::kTextureSampleBaseClampToEdge,
+    BuiltinFn::kTextureStore,
+    BuiltinFn::kTextureLoad,
+    BuiltinFn::kAtomicLoad,
+    BuiltinFn::kAtomicStore,
+    BuiltinFn::kAtomicAdd,
+    BuiltinFn::kAtomicSub,
+    BuiltinFn::kAtomicMax,
+    BuiltinFn::kAtomicMin,
+    BuiltinFn::kAtomicAnd,
+    BuiltinFn::kAtomicOr,
+    BuiltinFn::kAtomicXor,
+    BuiltinFn::kAtomicExchange,
+    BuiltinFn::kAtomicCompareExchangeWeak,
+    BuiltinFn::kSubgroupBallot,
+    BuiltinFn::kSubgroupBroadcast,
+    BuiltinFn::kTintMaterialize,
+};
+
+/// All builtin function names
+constexpr const char* kBuiltinFnStrings[] = {
+    "abs",
+    "acos",
+    "acosh",
+    "all",
+    "any",
+    "arrayLength",
+    "asin",
+    "asinh",
+    "atan",
+    "atan2",
+    "atanh",
+    "ceil",
+    "clamp",
+    "cos",
+    "cosh",
+    "countLeadingZeros",
+    "countOneBits",
+    "countTrailingZeros",
+    "cross",
+    "degrees",
+    "determinant",
+    "distance",
+    "dot",
+    "dot4I8Packed",
+    "dot4U8Packed",
+    "dpdx",
+    "dpdxCoarse",
+    "dpdxFine",
+    "dpdy",
+    "dpdyCoarse",
+    "dpdyFine",
+    "exp",
+    "exp2",
+    "extractBits",
+    "faceForward",
+    "firstLeadingBit",
+    "firstTrailingBit",
+    "floor",
+    "fma",
+    "fract",
+    "frexp",
+    "fwidth",
+    "fwidthCoarse",
+    "fwidthFine",
+    "insertBits",
+    "inverseSqrt",
+    "ldexp",
+    "length",
+    "log",
+    "log2",
+    "max",
+    "min",
+    "mix",
+    "modf",
+    "normalize",
+    "pack2x16float",
+    "pack2x16snorm",
+    "pack2x16unorm",
+    "pack4x8snorm",
+    "pack4x8unorm",
+    "pow",
+    "quantizeToF16",
+    "radians",
+    "reflect",
+    "refract",
+    "reverseBits",
+    "round",
+    "saturate",
+    "select",
+    "sign",
+    "sin",
+    "sinh",
+    "smoothstep",
+    "sqrt",
+    "step",
+    "storageBarrier",
+    "tan",
+    "tanh",
+    "transpose",
+    "trunc",
+    "unpack2x16float",
+    "unpack2x16snorm",
+    "unpack2x16unorm",
+    "unpack4x8snorm",
+    "unpack4x8unorm",
+    "workgroupBarrier",
+    "workgroupUniformLoad",
+    "textureBarrier",
+    "textureDimensions",
+    "textureGather",
+    "textureGatherCompare",
+    "textureNumLayers",
+    "textureNumLevels",
+    "textureNumSamples",
+    "textureSample",
+    "textureSampleBias",
+    "textureSampleCompare",
+    "textureSampleCompareLevel",
+    "textureSampleGrad",
+    "textureSampleLevel",
+    "textureSampleBaseClampToEdge",
+    "textureStore",
+    "textureLoad",
+    "atomicLoad",
+    "atomicStore",
+    "atomicAdd",
+    "atomicSub",
+    "atomicMax",
+    "atomicMin",
+    "atomicAnd",
+    "atomicOr",
+    "atomicXor",
+    "atomicExchange",
+    "atomicCompareExchangeWeak",
+    "subgroupBallot",
+    "subgroupBroadcast",
+    "_tint_materialize",
+};
+
+/// Determines if the given `f` is a coarse derivative.
+/// @param f the builtin type
+/// @returns true if the given derivative is coarse.
+bool IsCoarseDerivative(BuiltinFn f);
+
+/// Determines if the given `f` is a fine derivative.
+/// @param f the builtin type
+/// @returns true if the given derivative is fine.
+bool IsFineDerivative(BuiltinFn f);
+
+/// Determine if the given `f` is a derivative builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is a derivative builtin
+bool IsDerivative(BuiltinFn f);
+
+/// Determines if the given `f` is a texture operation builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is a texture operation builtin
+bool IsTexture(BuiltinFn f);
+
+/// Determines if the given `f` is an image query builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is an image query builtin
+bool IsImageQuery(BuiltinFn f);
+
+/// Determines if the given `f` is a data packing builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is a data packing builtin
+bool IsDataPacking(BuiltinFn f);
+
+/// Determines if the given `f` is a data unpacking builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is a data unpacking builtin
+bool IsDataUnpacking(BuiltinFn f);
+
+/// Determines if the given `f` is a barrier builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is a barrier builtin
+bool IsBarrier(BuiltinFn f);
+
+/// Determines if the given `f` is an atomic builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is an atomic builtin
+bool IsAtomic(BuiltinFn f);
+
+/// Determines if the given `f` is a DP4a builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is a DP4a builtin
+bool IsDP4a(BuiltinFn f);
+
+/// Determines if the given `f` is a subgroup builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is a subgroup builtin
+bool IsSubgroup(BuiltinFn f);
+
+/// Determines if the given `f` may have side-effects (i.e. writes to at least one of its inputs)
+/// @returns true if intrinsic may have side-effects
+bool HasSideEffects(BuiltinFn f);
+
+}  // namespace tint::wgsl
+// \endcond
+
+#endif  // SRC_TINT_LANG_WGSL_BUILTIN_FN_H_
diff --git a/src/tint/lang/wgsl/builtin_fn.h.tmpl b/src/tint/lang/wgsl/builtin_fn.h.tmpl
new file mode 100644
index 0000000..e69eda2
--- /dev/null
+++ b/src/tint/lang/wgsl/builtin_fn.h.tmpl
@@ -0,0 +1,128 @@
+{{- /*
+--------------------------------------------------------------------------------
+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/wgsl/wgsl.def" -}}
+
+#ifndef SRC_TINT_LANG_WGSL_BUILTIN_FN_H_
+#define SRC_TINT_LANG_WGSL_BUILTIN_FN_H_
+
+#include <cstdint>
+#include <string>
+
+#include "src/tint/utils/traits/traits.h"
+
+// \cond DO_NOT_DOCUMENT
+namespace tint::wgsl {
+
+/// Enumerator of all builtin functions
+enum class BuiltinFn : uint8_t {
+{{- range $I.Sem.Builtins }}
+    k{{PascalCase .Name}},
+{{- end }}
+    kNone,
+};
+
+/// Matches the BuiltinFn by name
+/// @param name the builtin name to parse
+/// @returns the parsed BuiltinFn, or BuiltinFn::kNone if `name` did not
+/// match any builtin function.
+BuiltinFn ParseBuiltinFn(std::string_view name);
+
+/// @returns the name of the builtin function type. The spelling, including
+/// case, matches the name in the WGSL spec.
+const char* str(BuiltinFn i);
+
+/// Emits the name of the builtin function type. The spelling, including case,
+/// matches the name in the WGSL spec.
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& o, BuiltinFn i) {
+  return o << str(i);
+}
+
+/// All builtin functions
+constexpr BuiltinFn kBuiltinFns[] = {
+{{- range $I.Sem.Builtins }}
+    BuiltinFn::k{{PascalCase .Name}},
+{{- end }}
+};
+
+/// All builtin function names
+constexpr const char* kBuiltinFnStrings[] = {
+{{- range $I.Sem.Builtins }}
+    "{{.Name}}",
+{{- end }}
+};
+
+/// Determines if the given `f` is a coarse derivative.
+/// @param f the builtin type
+/// @returns true if the given derivative is coarse.
+bool IsCoarseDerivative(BuiltinFn f);
+
+/// Determines if the given `f` is a fine derivative.
+/// @param f the builtin type
+/// @returns true if the given derivative is fine.
+bool IsFineDerivative(BuiltinFn f);
+
+/// Determine if the given `f` is a derivative builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is a derivative builtin
+bool IsDerivative(BuiltinFn f);
+
+/// Determines if the given `f` is a texture operation builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is a texture operation builtin
+bool IsTexture(BuiltinFn f);
+
+/// Determines if the given `f` is an image query builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is an image query builtin
+bool IsImageQuery(BuiltinFn f);
+
+/// Determines if the given `f` is a data packing builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is a data packing builtin
+bool IsDataPacking(BuiltinFn f);
+
+/// Determines if the given `f` is a data unpacking builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is a data unpacking builtin
+bool IsDataUnpacking(BuiltinFn f);
+
+/// Determines if the given `f` is a barrier builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is a barrier builtin
+bool IsBarrier(BuiltinFn f);
+
+/// Determines if the given `f` is an atomic builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is an atomic builtin
+bool IsAtomic(BuiltinFn f);
+
+/// Determines if the given `f` is a DP4a builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is a DP4a builtin
+bool IsDP4a(BuiltinFn f);
+
+/// Determines if the given `f` is a subgroup builtin.
+/// @param f the builtin type
+/// @returns true if the given `f` is a subgroup builtin
+bool IsSubgroup(BuiltinFn f);
+
+/// Determines if the given `f` may have side-effects (i.e. writes to at least one of its inputs)
+/// @returns true if intrinsic may have side-effects
+bool HasSideEffects(BuiltinFn f);
+
+}  // namespace tint::wgsl
+// \endcond
+
+#endif  // SRC_TINT_LANG_WGSL_BUILTIN_FN_H_
diff --git a/src/tint/lang/wgsl/helpers/BUILD.bazel b/src/tint/lang/wgsl/helpers/BUILD.bazel
index c9687b0..7162fb1 100644
--- a/src/tint/lang/wgsl/helpers/BUILD.bazel
+++ b/src/tint/lang/wgsl/helpers/BUILD.bazel
@@ -85,6 +85,7 @@
     "//src/tint/lang/wgsl/helpers",
     "//src/tint/lang/wgsl/program",
     "//src/tint/lang/wgsl/reader",
+    "//src/tint/lang/wgsl/reader/lower",
     "//src/tint/lang/wgsl/reader/program_to_ir",
     "//src/tint/lang/wgsl/resolver",
     "//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/helpers/BUILD.cmake b/src/tint/lang/wgsl/helpers/BUILD.cmake
index 8cf2e47..8781482 100644
--- a/src/tint/lang/wgsl/helpers/BUILD.cmake
+++ b/src/tint/lang/wgsl/helpers/BUILD.cmake
@@ -84,6 +84,7 @@
   tint_lang_wgsl_helpers
   tint_lang_wgsl_program
   tint_lang_wgsl_reader
+  tint_lang_wgsl_reader_lower
   tint_lang_wgsl_reader_program_to_ir
   tint_lang_wgsl_resolver
   tint_lang_wgsl_sem
diff --git a/src/tint/lang/wgsl/helpers/BUILD.gn b/src/tint/lang/wgsl/helpers/BUILD.gn
index be773f2..57843c5 100644
--- a/src/tint/lang/wgsl/helpers/BUILD.gn
+++ b/src/tint/lang/wgsl/helpers/BUILD.gn
@@ -87,6 +87,7 @@
       "${tint_src_dir}/lang/wgsl/helpers",
       "${tint_src_dir}/lang/wgsl/program",
       "${tint_src_dir}/lang/wgsl/reader",
+      "${tint_src_dir}/lang/wgsl/reader/lower",
       "${tint_src_dir}/lang/wgsl/reader/program_to_ir",
       "${tint_src_dir}/lang/wgsl/resolver",
       "${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/helpers/ir_program_test.h b/src/tint/lang/wgsl/helpers/ir_program_test.h
index 63bdd7f..fb5fd01 100644
--- a/src/tint/lang/wgsl/helpers/ir_program_test.h
+++ b/src/tint/lang/wgsl/helpers/ir_program_test.h
@@ -24,6 +24,7 @@
 #include "src/tint/lang/core/ir/validator.h"
 #include "src/tint/lang/core/number.h"
 #include "src/tint/lang/wgsl/program/program_builder.h"
+#include "src/tint/lang/wgsl/reader/lower/lower.h"
 #include "src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h"
 #include "src/tint/lang/wgsl/reader/reader.h"
 #include "src/tint/lang/wgsl/resolver/resolve.h"
@@ -38,20 +39,26 @@
     IRProgramTestBase() = default;
     ~IRProgramTestBase() override = default;
 
-    /// Build the module, cleaning up the program before returning.
-    /// @returns the generated module
-    tint::Result<core::ir::Module, std::string> Build() {
+    /// Builds a core-dialect module from this ProgramBuilder.
+    /// @returns the generated core-dialect module
+    tint::Result<core::ir::Module> Build() {
         Program program{resolver::Resolve(*this)};
         if (!program.IsValid()) {
-            return program.Diagnostics().str();
+            return Failure{program.Diagnostics()};
         }
 
         auto result = wgsl::reader::ProgramToIR(program);
-        if (result) {
-            auto validated = core::ir::Validate(result.Get());
-            if (!validated) {
-                return validated.Failure().str();
-            }
+        if (!result) {
+            return result.Failure();
+        }
+
+        // WGSL-dialect -> core-dialect
+        if (auto lower = wgsl::reader::Lower(result.Get()); !lower) {
+            return lower.Failure();
+        }
+
+        if (auto validate = core::ir::Validate(result.Get()); !validate) {
+            return validate.Failure();
         }
         return result;
     }
@@ -59,25 +66,20 @@
     /// Build the module from the given WGSL.
     /// @param wgsl the WGSL to convert to IR
     /// @returns the generated module
-    tint::Result<core::ir::Module, std::string> Build(std::string wgsl) {
+    Result<core::ir::Module> Build(std::string wgsl) {
 #if TINT_BUILD_WGSL_READER
         Source::File file("test.wgsl", std::move(wgsl));
-        auto program = wgsl::reader::Parse(&file);
-        if (!program.IsValid()) {
-            return program.Diagnostics().str();
-        }
-
-        auto result = wgsl::reader::ProgramToIR(program);
+        auto result = wgsl::reader::WgslToIR(&file);
         if (result) {
             auto validated = core::ir::Validate(result.Get());
             if (!validated) {
-                return validated.Failure().str();
+                return validated.Failure();
             }
         }
         return result;
 #else
         (void)wgsl;
-        return std::string("error: Tint not built with the WGSL reader");
+        return Failure{"error: Tint not built with the WGSL reader"};
 #endif
     }
 
diff --git a/src/tint/lang/wgsl/inspector/BUILD.bazel b/src/tint/lang/wgsl/inspector/BUILD.bazel
index 86f9897..edbb595 100644
--- a/src/tint/lang/wgsl/inspector/BUILD.bazel
+++ b/src/tint/lang/wgsl/inspector/BUILD.bazel
@@ -77,6 +77,7 @@
     "//src/tint/api/common",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
diff --git a/src/tint/lang/wgsl/inspector/BUILD.cmake b/src/tint/lang/wgsl/inspector/BUILD.cmake
index 5c0e910..8cfe979 100644
--- a/src/tint/lang/wgsl/inspector/BUILD.cmake
+++ b/src/tint/lang/wgsl/inspector/BUILD.cmake
@@ -76,6 +76,7 @@
   tint_api_common
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
diff --git a/src/tint/lang/wgsl/inspector/BUILD.gn b/src/tint/lang/wgsl/inspector/BUILD.gn
index 00feb25..566230b 100644
--- a/src/tint/lang/wgsl/inspector/BUILD.gn
+++ b/src/tint/lang/wgsl/inspector/BUILD.gn
@@ -79,6 +79,7 @@
       "${tint_src_dir}/api/common",
       "${tint_src_dir}/lang/core",
       "${tint_src_dir}/lang/core/constant",
+      "${tint_src_dir}/lang/core/ir",
       "${tint_src_dir}/lang/core/type",
       "${tint_src_dir}/lang/wgsl",
       "${tint_src_dir}/lang/wgsl/ast",
diff --git a/src/tint/lang/wgsl/intrinsic/BUILD.bazel b/src/tint/lang/wgsl/intrinsic/BUILD.bazel
new file mode 100644
index 0000000..9f81589
--- /dev/null
+++ b/src/tint/lang/wgsl/intrinsic/BUILD.bazel
@@ -0,0 +1,26 @@
+# Copyright 2023 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# 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")
+
diff --git a/src/tint/lang/wgsl/intrinsic/BUILD.cmake b/src/tint/lang/wgsl/intrinsic/BUILD.cmake
new file mode 100644
index 0000000..f5bf63c
--- /dev/null
+++ b/src/tint/lang/wgsl/intrinsic/BUILD.cmake
@@ -0,0 +1,24 @@
+# Copyright 2023 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# 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
+################################################################################
+
+include(lang/wgsl/intrinsic/data/BUILD.cmake)
diff --git a/src/tint/lang/wgsl/intrinsic/BUILD.gn b/src/tint/lang/wgsl/intrinsic/BUILD.gn
new file mode 100644
index 0000000..b502e46
--- /dev/null
+++ b/src/tint/lang/wgsl/intrinsic/BUILD.gn
@@ -0,0 +1,26 @@
+# Copyright 2023 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# 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")
diff --git a/src/tint/lang/wgsl/intrinsic/data/BUILD.bazel b/src/tint/lang/wgsl/intrinsic/data/BUILD.bazel
new file mode 100644
index 0000000..7a62681
--- /dev/null
+++ b/src/tint/lang/wgsl/intrinsic/data/BUILD.bazel
@@ -0,0 +1,56 @@
+# Copyright 2023 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# 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 = "data",
+  srcs = [
+    "data.cc",
+  ],
+  hdrs = [
+    "data.h",
+  ],
+  deps = [
+    "//src/tint/lang/core",
+    "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/intrinsic",
+    "//src/tint/lang/core/intrinsic/data",
+    "//src/tint/lang/core/type",
+    "//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/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/wgsl/intrinsic/data/BUILD.cmake b/src/tint/lang/wgsl/intrinsic/data/BUILD.cmake
new file mode 100644
index 0000000..d676529
--- /dev/null
+++ b/src/tint/lang/wgsl/intrinsic/data/BUILD.cmake
@@ -0,0 +1,51 @@
+# Copyright 2023 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# 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_wgsl_intrinsic_data
+# Kind:      lib
+################################################################################
+tint_add_target(tint_lang_wgsl_intrinsic_data lib
+  lang/wgsl/intrinsic/data/data.cc
+  lang/wgsl/intrinsic/data/data.h
+)
+
+tint_target_add_dependencies(tint_lang_wgsl_intrinsic_data lib
+  tint_lang_core
+  tint_lang_core_constant
+  tint_lang_core_intrinsic
+  tint_lang_core_intrinsic_data
+  tint_lang_core_type
+  tint_utils_containers
+  tint_utils_diagnostic
+  tint_utils_ice
+  tint_utils_id
+  tint_utils_macros
+  tint_utils_math
+  tint_utils_memory
+  tint_utils_result
+  tint_utils_rtti
+  tint_utils_symbol
+  tint_utils_text
+  tint_utils_traits
+)
diff --git a/src/tint/lang/wgsl/intrinsic/data/BUILD.gn b/src/tint/lang/wgsl/intrinsic/data/BUILD.gn
new file mode 100644
index 0000000..ba1f02a
--- /dev/null
+++ b/src/tint/lang/wgsl/intrinsic/data/BUILD.gn
@@ -0,0 +1,52 @@
+# Copyright 2023 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# 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("data") {
+  sources = [
+    "data.cc",
+    "data.h",
+  ]
+  deps = [
+    "${tint_src_dir}/lang/core",
+    "${tint_src_dir}/lang/core/constant",
+    "${tint_src_dir}/lang/core/intrinsic",
+    "${tint_src_dir}/lang/core/intrinsic/data",
+    "${tint_src_dir}/lang/core/type",
+    "${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/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/wgsl/intrinsic/data/data.cc b/src/tint/lang/wgsl/intrinsic/data/data.cc
new file mode 100644
index 0000000..4548260
--- /dev/null
+++ b/src/tint/lang/wgsl/intrinsic/data/data.cc
@@ -0,0 +1,12273 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by 'tools/src/cmd/gen' using the template:
+//   src/tint/lang/wgsl/intrinsic/data/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/data/type_matchers.h"
+#include "src/tint/lang/wgsl/intrinsic/data/data.h"
+#include "src/tint/utils/text/string_stream.h"
+
+namespace tint::wgsl::intrinsic::data {
+
+using namespace tint::core::intrinsic::data;  // NOLINT(build/namespaces)
+
+namespace {
+
+using ConstEvalFunctionIndex = tint::core::intrinsic::ConstEvalFunctionIndex;
+using IntrinsicInfo = tint::core::intrinsic::IntrinsicInfo;
+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 NumberMatcherIndicesIndex = tint::core::intrinsic::NumberMatcherIndicesIndex;
+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 TemplateNumberIndex = tint::core::intrinsic::TemplateNumberIndex;
+using TemplateNumberInfo = tint::core::intrinsic::TemplateNumberInfo;
+using TemplateTypeIndex = tint::core::intrinsic::TemplateTypeIndex;
+using TemplateTypeInfo = tint::core::intrinsic::TemplateTypeInfo;
+using Type = tint::core::type::Type;
+using TypeMatcher = tint::core::intrinsic::TypeMatcher;
+using TypeMatcherIndex = tint::core::intrinsic::TypeMatcherIndex;
+using TypeMatcherIndicesIndex = tint::core::intrinsic::TypeMatcherIndicesIndex;
+
+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 bool'
+constexpr TypeMatcher kBoolMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (!MatchBool(state, ty)) {
+      return nullptr;
+    }
+    return BuildBool(state, ty);
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "bool";
+  }
+};
+
+
+/// TypeMatcher for 'type ia'
+constexpr TypeMatcher kIaMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (!MatchIa(state, ty)) {
+      return nullptr;
+    }
+    return BuildIa(state, ty);
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    ss << "abstract-int";
+    return ss.str();
+  }
+};
+
+
+/// TypeMatcher for 'type fa'
+constexpr TypeMatcher kFaMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (!MatchFa(state, ty)) {
+      return nullptr;
+    }
+    return BuildFa(state, ty);
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    ss << "abstract-float";
+    return ss.str();
+  }
+};
+
+
+/// 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);
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "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);
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "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);
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "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);
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "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);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "vec2<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type vec3'
+constexpr TypeMatcher kVec3Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchVec3(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildVec3(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "vec3<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type vec4'
+constexpr TypeMatcher kVec4Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchVec4(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildVec4(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "vec4<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type mat2x2'
+constexpr TypeMatcher kMat2X2Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchMat2X2(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildMat2X2(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "mat2x2<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type mat2x3'
+constexpr TypeMatcher kMat2X3Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchMat2X3(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildMat2X3(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "mat2x3<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type mat2x4'
+constexpr TypeMatcher kMat2X4Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchMat2X4(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildMat2X4(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "mat2x4<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type mat3x2'
+constexpr TypeMatcher kMat3X2Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchMat3X2(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildMat3X2(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "mat3x2<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type mat3x3'
+constexpr TypeMatcher kMat3X3Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchMat3X3(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildMat3X3(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "mat3x3<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type mat3x4'
+constexpr TypeMatcher kMat3X4Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchMat3X4(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildMat3X4(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "mat3x4<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type mat4x2'
+constexpr TypeMatcher kMat4X2Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchMat4X2(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildMat4X2(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "mat4x2<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type mat4x3'
+constexpr TypeMatcher kMat4X3Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchMat4X3(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildMat4X3(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "mat4x3<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type mat4x4'
+constexpr TypeMatcher kMat4X4Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchMat4X4(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildMat4X4(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "mat4x4<" + 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);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string N = state->NumName();
+  const std::string T = state->TypeName();
+    StringStream ss;
+    ss << "vec" << N << "<" << T << ">";
+    return ss.str();
+  }
+};
+
+
+/// TypeMatcher for 'type mat'
+constexpr TypeMatcher kMatMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  Number N = Number::invalid;
+  Number M = Number::invalid;
+  const Type* T = nullptr;
+    if (!MatchMat(state, ty, N, M, T)) {
+      return nullptr;
+    }
+    N = state.Num(N);
+    if (!N.IsValid()) {
+      return nullptr;
+    }
+    M = state.Num(M);
+    if (!M.IsValid()) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildMat(state, ty, N, M, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string N = state->NumName();
+  const std::string M = state->NumName();
+  const std::string T = state->TypeName();
+    StringStream ss;
+    ss << "mat" << N << "x" << M << "<" << T << ">";
+    return ss.str();
+  }
+};
+
+
+/// TypeMatcher for 'type ptr'
+constexpr TypeMatcher kPtrMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  Number S = Number::invalid;
+  const Type* T = nullptr;
+  Number A = Number::invalid;
+    if (!MatchPtr(state, ty, S, T, A)) {
+      return nullptr;
+    }
+    S = state.Num(S);
+    if (!S.IsValid()) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    A = state.Num(A);
+    if (!A.IsValid()) {
+      return nullptr;
+    }
+    return BuildPtr(state, ty, S, T, A);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string S = state->NumName();
+  const std::string T = state->TypeName();
+  const std::string A = state->NumName();
+    return "ptr<" + S + ", " + T + ", " + A + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type atomic'
+constexpr TypeMatcher kAtomicMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchAtomic(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildAtomic(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "atomic<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type array'
+constexpr TypeMatcher kArrayMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchArray(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildArray(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "array<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type sampler'
+constexpr TypeMatcher kSamplerMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (!MatchSampler(state, ty)) {
+      return nullptr;
+    }
+    return BuildSampler(state, ty);
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "sampler";
+  }
+};
+
+
+/// TypeMatcher for 'type sampler_comparison'
+constexpr TypeMatcher kSamplerComparisonMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (!MatchSamplerComparison(state, ty)) {
+      return nullptr;
+    }
+    return BuildSamplerComparison(state, ty);
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "sampler_comparison";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_1d'
+constexpr TypeMatcher kTexture1DMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchTexture1D(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildTexture1D(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "texture_1d<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_2d'
+constexpr TypeMatcher kTexture2DMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchTexture2D(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildTexture2D(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "texture_2d<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_2d_array'
+constexpr TypeMatcher kTexture2DArrayMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchTexture2DArray(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildTexture2DArray(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "texture_2d_array<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_3d'
+constexpr TypeMatcher kTexture3DMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchTexture3D(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildTexture3D(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "texture_3d<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_cube'
+constexpr TypeMatcher kTextureCubeMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchTextureCube(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildTextureCube(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "texture_cube<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_cube_array'
+constexpr TypeMatcher kTextureCubeArrayMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchTextureCubeArray(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildTextureCubeArray(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "texture_cube_array<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_multisampled_2d'
+constexpr TypeMatcher kTextureMultisampled2DMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchTextureMultisampled2D(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildTextureMultisampled2D(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "texture_multisampled_2d<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_depth_2d'
+constexpr TypeMatcher kTextureDepth2DMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (!MatchTextureDepth2D(state, ty)) {
+      return nullptr;
+    }
+    return BuildTextureDepth2D(state, ty);
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "texture_depth_2d";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_depth_2d_array'
+constexpr TypeMatcher kTextureDepth2DArrayMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (!MatchTextureDepth2DArray(state, ty)) {
+      return nullptr;
+    }
+    return BuildTextureDepth2DArray(state, ty);
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "texture_depth_2d_array";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_depth_cube'
+constexpr TypeMatcher kTextureDepthCubeMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (!MatchTextureDepthCube(state, ty)) {
+      return nullptr;
+    }
+    return BuildTextureDepthCube(state, ty);
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "texture_depth_cube";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_depth_cube_array'
+constexpr TypeMatcher kTextureDepthCubeArrayMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (!MatchTextureDepthCubeArray(state, ty)) {
+      return nullptr;
+    }
+    return BuildTextureDepthCubeArray(state, ty);
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "texture_depth_cube_array";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_depth_multisampled_2d'
+constexpr TypeMatcher kTextureDepthMultisampled2DMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (!MatchTextureDepthMultisampled2D(state, ty)) {
+      return nullptr;
+    }
+    return BuildTextureDepthMultisampled2D(state, ty);
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "texture_depth_multisampled_2d";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_storage_1d'
+constexpr TypeMatcher kTextureStorage1DMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  Number F = Number::invalid;
+  Number A = Number::invalid;
+    if (!MatchTextureStorage1D(state, ty, F, A)) {
+      return nullptr;
+    }
+    F = state.Num(F);
+    if (!F.IsValid()) {
+      return nullptr;
+    }
+    A = state.Num(A);
+    if (!A.IsValid()) {
+      return nullptr;
+    }
+    return BuildTextureStorage1D(state, ty, F, A);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string F = state->NumName();
+  const std::string A = state->NumName();
+    return "texture_storage_1d<" + F + ", " + A + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_storage_2d'
+constexpr TypeMatcher kTextureStorage2DMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  Number F = Number::invalid;
+  Number A = Number::invalid;
+    if (!MatchTextureStorage2D(state, ty, F, A)) {
+      return nullptr;
+    }
+    F = state.Num(F);
+    if (!F.IsValid()) {
+      return nullptr;
+    }
+    A = state.Num(A);
+    if (!A.IsValid()) {
+      return nullptr;
+    }
+    return BuildTextureStorage2D(state, ty, F, A);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string F = state->NumName();
+  const std::string A = state->NumName();
+    return "texture_storage_2d<" + F + ", " + A + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_storage_2d_array'
+constexpr TypeMatcher kTextureStorage2DArrayMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  Number F = Number::invalid;
+  Number A = Number::invalid;
+    if (!MatchTextureStorage2DArray(state, ty, F, A)) {
+      return nullptr;
+    }
+    F = state.Num(F);
+    if (!F.IsValid()) {
+      return nullptr;
+    }
+    A = state.Num(A);
+    if (!A.IsValid()) {
+      return nullptr;
+    }
+    return BuildTextureStorage2DArray(state, ty, F, A);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string F = state->NumName();
+  const std::string A = state->NumName();
+    return "texture_storage_2d_array<" + F + ", " + A + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_storage_3d'
+constexpr TypeMatcher kTextureStorage3DMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  Number F = Number::invalid;
+  Number A = Number::invalid;
+    if (!MatchTextureStorage3D(state, ty, F, A)) {
+      return nullptr;
+    }
+    F = state.Num(F);
+    if (!F.IsValid()) {
+      return nullptr;
+    }
+    A = state.Num(A);
+    if (!A.IsValid()) {
+      return nullptr;
+    }
+    return BuildTextureStorage3D(state, ty, F, A);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string F = state->NumName();
+  const std::string A = state->NumName();
+    return "texture_storage_3d<" + F + ", " + A + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type texture_external'
+constexpr TypeMatcher kTextureExternalMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (!MatchTextureExternal(state, ty)) {
+      return nullptr;
+    }
+    return BuildTextureExternal(state, ty);
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "texture_external";
+  }
+};
+
+
+/// TypeMatcher for 'type packedVec3'
+constexpr TypeMatcher kPackedVec3Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchPackedVec3(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildPackedVec3(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "packedVec3<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'type __modf_result'
+constexpr TypeMatcher kModfResultMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchModfResult(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildModfResult(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    StringStream ss;
+    ss << "__modf_result_" << T;
+    return ss.str();
+  }
+};
+
+
+/// TypeMatcher for 'type __modf_result_vec'
+constexpr TypeMatcher kModfResultVecMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  Number N = Number::invalid;
+  const Type* T = nullptr;
+    if (!MatchModfResultVec(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 BuildModfResultVec(state, ty, N, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string N = state->NumName();
+  const std::string T = state->TypeName();
+    StringStream ss;
+    ss << "__modf_result_vec" << N << "_" << T;
+    return ss.str();
+  }
+};
+
+
+/// TypeMatcher for 'type __frexp_result'
+constexpr TypeMatcher kFrexpResultMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchFrexpResult(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildFrexpResult(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    StringStream ss;
+    ss << "__frexp_result_" << T;
+    return ss.str();
+  }
+};
+
+
+/// TypeMatcher for 'type __frexp_result_vec'
+constexpr TypeMatcher kFrexpResultVecMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  Number N = Number::invalid;
+  const Type* T = nullptr;
+    if (!MatchFrexpResultVec(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 BuildFrexpResultVec(state, ty, N, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string N = state->NumName();
+  const std::string T = state->TypeName();
+    StringStream ss;
+    ss << "__frexp_result_vec" << N << "_" << T;
+    return ss.str();
+  }
+};
+
+
+/// TypeMatcher for 'type __atomic_compare_exchange_result'
+constexpr TypeMatcher kAtomicCompareExchangeResultMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+  const Type* T = nullptr;
+    if (!MatchAtomicCompareExchangeResult(state, ty, T)) {
+      return nullptr;
+    }
+    T = state.Type(T);
+    if (T == nullptr) {
+      return nullptr;
+    }
+    return BuildAtomicCompareExchangeResult(state, ty, T);
+  },
+/* string */ [](MatchState* state) -> std::string {
+  const std::string T = state->TypeName();
+    return "__atomic_compare_exchange_result<" + T + ">";
+  }
+};
+
+
+/// TypeMatcher for 'match scalar'
+constexpr TypeMatcher kScalarMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchIa(state, ty)) {
+      return BuildIa(state, ty);
+    }
+    if (MatchFa(state, ty)) {
+      return BuildFa(state, ty);
+    }
+    if (MatchI32(state, ty)) {
+      return BuildI32(state, ty);
+    }
+    if (MatchU32(state, ty)) {
+      return BuildU32(state, ty);
+    }
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    if (MatchF16(state, ty)) {
+      return BuildF16(state, ty);
+    }
+    if (MatchBool(state, ty)) {
+      return BuildBool(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kIaMatcher.string(nullptr) << ", " << kFaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match concrete_scalar'
+constexpr TypeMatcher kConcreteScalarMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchI32(state, ty)) {
+      return BuildI32(state, ty);
+    }
+    if (MatchU32(state, ty)) {
+      return BuildU32(state, ty);
+    }
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    if (MatchF16(state, ty)) {
+      return BuildF16(state, ty);
+    }
+    if (MatchBool(state, ty)) {
+      return BuildBool(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kF32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match scalar_no_f32'
+constexpr TypeMatcher kScalarNoF32Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchIa(state, ty)) {
+      return BuildIa(state, ty);
+    }
+    if (MatchFa(state, ty)) {
+      return BuildFa(state, ty);
+    }
+    if (MatchI32(state, ty)) {
+      return BuildI32(state, ty);
+    }
+    if (MatchU32(state, ty)) {
+      return BuildU32(state, ty);
+    }
+    if (MatchF16(state, ty)) {
+      return BuildF16(state, ty);
+    }
+    if (MatchBool(state, ty)) {
+      return BuildBool(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kIaMatcher.string(nullptr) << ", " << kFaMatcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match scalar_no_f16'
+constexpr TypeMatcher kScalarNoF16Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchIa(state, ty)) {
+      return BuildIa(state, ty);
+    }
+    if (MatchFa(state, ty)) {
+      return BuildFa(state, ty);
+    }
+    if (MatchI32(state, ty)) {
+      return BuildI32(state, ty);
+    }
+    if (MatchU32(state, ty)) {
+      return BuildU32(state, ty);
+    }
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    if (MatchBool(state, ty)) {
+      return BuildBool(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kIaMatcher.string(nullptr) << ", " << kFaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match scalar_no_i32'
+constexpr TypeMatcher kScalarNoI32Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchIa(state, ty)) {
+      return BuildIa(state, ty);
+    }
+    if (MatchFa(state, ty)) {
+      return BuildFa(state, ty);
+    }
+    if (MatchU32(state, ty)) {
+      return BuildU32(state, ty);
+    }
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    if (MatchF16(state, ty)) {
+      return BuildF16(state, ty);
+    }
+    if (MatchBool(state, ty)) {
+      return BuildBool(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kIaMatcher.string(nullptr) << ", " << kFaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match scalar_no_u32'
+constexpr TypeMatcher kScalarNoU32Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchIa(state, ty)) {
+      return BuildIa(state, ty);
+    }
+    if (MatchFa(state, ty)) {
+      return BuildFa(state, ty);
+    }
+    if (MatchI32(state, ty)) {
+      return BuildI32(state, ty);
+    }
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    if (MatchF16(state, ty)) {
+      return BuildF16(state, ty);
+    }
+    if (MatchBool(state, ty)) {
+      return BuildBool(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kIaMatcher.string(nullptr) << ", " << kFaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kBoolMatcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match scalar_no_bool'
+constexpr TypeMatcher kScalarNoBoolMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchIa(state, ty)) {
+      return BuildIa(state, ty);
+    }
+    if (MatchFa(state, ty)) {
+      return BuildFa(state, ty);
+    }
+    if (MatchI32(state, ty)) {
+      return BuildI32(state, ty);
+    }
+    if (MatchU32(state, ty)) {
+      return BuildU32(state, ty);
+    }
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    if (MatchF16(state, ty)) {
+      return BuildF16(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kIaMatcher.string(nullptr) << ", " << kFaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kF16Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kU32Matcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match fia_fiu32_f16'
+constexpr TypeMatcher kFiaFiu32F16Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchIa(state, ty)) {
+      return BuildIa(state, ty);
+    }
+    if (MatchFa(state, ty)) {
+      return BuildFa(state, ty);
+    }
+    if (MatchI32(state, ty)) {
+      return BuildI32(state, ty);
+    }
+    if (MatchU32(state, ty)) {
+      return BuildU32(state, ty);
+    }
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    if (MatchF16(state, ty)) {
+      return BuildF16(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kFaMatcher.string(nullptr) << ", " << kIaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match fia_fi32_f16'
+constexpr TypeMatcher kFiaFi32F16Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchIa(state, ty)) {
+      return BuildIa(state, ty);
+    }
+    if (MatchFa(state, ty)) {
+      return BuildFa(state, ty);
+    }
+    if (MatchI32(state, ty)) {
+      return BuildI32(state, ty);
+    }
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    if (MatchF16(state, ty)) {
+      return BuildF16(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kFaMatcher.string(nullptr) << ", " << kIaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match fia_fiu32'
+constexpr TypeMatcher kFiaFiu32Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchIa(state, ty)) {
+      return BuildIa(state, ty);
+    }
+    if (MatchFa(state, ty)) {
+      return BuildFa(state, ty);
+    }
+    if (MatchI32(state, ty)) {
+      return BuildI32(state, ty);
+    }
+    if (MatchU32(state, ty)) {
+      return BuildU32(state, ty);
+    }
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kFaMatcher.string(nullptr) << ", " << kIaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kU32Matcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match fa_f32'
+constexpr TypeMatcher kFaF32Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchFa(state, ty)) {
+      return BuildFa(state, ty);
+    }
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kFaMatcher.string(nullptr) << " or " << kF32Matcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match fa_f32_f16'
+constexpr TypeMatcher kFaF32F16Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchFa(state, ty)) {
+      return BuildFa(state, ty);
+    }
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    if (MatchF16(state, ty)) {
+      return BuildF16(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kFaMatcher.string(nullptr) << ", " << kF32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match ia_iu32'
+constexpr TypeMatcher kIaIu32Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchIa(state, ty)) {
+      return BuildIa(state, ty);
+    }
+    if (MatchI32(state, ty)) {
+      return BuildI32(state, ty);
+    }
+    if (MatchU32(state, ty)) {
+      return BuildU32(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kIaMatcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kU32Matcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match ia_i32'
+constexpr TypeMatcher kIaI32Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchIa(state, ty)) {
+      return BuildIa(state, ty);
+    }
+    if (MatchI32(state, ty)) {
+      return BuildI32(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kIaMatcher.string(nullptr) << " or " << kI32Matcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match fiu32_f16'
+constexpr TypeMatcher kFiu32F16Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchI32(state, ty)) {
+      return BuildI32(state, ty);
+    }
+    if (MatchU32(state, ty)) {
+      return BuildU32(state, ty);
+    }
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    if (MatchF16(state, ty)) {
+      return BuildF16(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << ", " << kU32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match fiu32'
+constexpr TypeMatcher kFiu32Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchI32(state, ty)) {
+      return BuildI32(state, ty);
+    }
+    if (MatchU32(state, ty)) {
+      return BuildU32(state, ty);
+    }
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kU32Matcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match fi32_f16'
+constexpr TypeMatcher kFi32F16Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchI32(state, ty)) {
+      return BuildI32(state, ty);
+    }
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    if (MatchF16(state, ty)) {
+      return BuildF16(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kF32Matcher.string(nullptr) << ", " << kI32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match fi32'
+constexpr TypeMatcher kFi32Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchI32(state, ty)) {
+      return BuildI32(state, ty);
+    }
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kF32Matcher.string(nullptr) << " or " << kI32Matcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// TypeMatcher for 'match f32_f16'
+constexpr TypeMatcher kF32F16Matcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (MatchF32(state, ty)) {
+      return BuildF32(state, ty);
+    }
+    if (MatchF16(state, ty)) {
+      return BuildF16(state, ty);
+    }
+    return nullptr;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kF32Matcher.string(nullptr) << " or " << kF16Matcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// 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;
+  },
+/* string */ [](MatchState*) -> std::string {
+    StringStream ss;
+    // Note: We pass nullptr to the TypeMatcher::String() functions, as 'matcher's do not support
+    // template arguments, nor can they match sub-types. As such, they have no use for the MatchState.
+    ss << kI32Matcher.string(nullptr) << " or " << kU32Matcher.string(nullptr);
+    return ss.str();
+  }
+};
+
+/// EnumMatcher for 'match f32_texel_format'
+constexpr NumberMatcher kF32TexelFormatMatcher {
+/* match */ [](MatchState&, Number number) -> Number {
+    switch (static_cast<core::TexelFormat>(number.Value())) {
+      case core::TexelFormat::kBgra8Unorm:
+      case core::TexelFormat::kRgba8Unorm:
+      case core::TexelFormat::kRgba8Snorm:
+      case core::TexelFormat::kRgba16Float:
+      case core::TexelFormat::kR32Float:
+      case core::TexelFormat::kRg32Float:
+      case core::TexelFormat::kRgba32Float:
+        return number;
+      default:
+        return Number::invalid;
+    }
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "bgra8unorm, rgba8unorm, rgba8snorm, rgba16float, r32float, rg32float or rgba32float";
+  }
+};
+
+/// EnumMatcher for 'match i32_texel_format'
+constexpr NumberMatcher kI32TexelFormatMatcher {
+/* match */ [](MatchState&, Number number) -> Number {
+    switch (static_cast<core::TexelFormat>(number.Value())) {
+      case core::TexelFormat::kRgba8Sint:
+      case core::TexelFormat::kRgba16Sint:
+      case core::TexelFormat::kR32Sint:
+      case core::TexelFormat::kRg32Sint:
+      case core::TexelFormat::kRgba32Sint:
+        return number;
+      default:
+        return Number::invalid;
+    }
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "rgba8sint, rgba16sint, r32sint, rg32sint or rgba32sint";
+  }
+};
+
+/// EnumMatcher for 'match u32_texel_format'
+constexpr NumberMatcher kU32TexelFormatMatcher {
+/* match */ [](MatchState&, Number number) -> Number {
+    switch (static_cast<core::TexelFormat>(number.Value())) {
+      case core::TexelFormat::kRgba8Uint:
+      case core::TexelFormat::kRgba16Uint:
+      case core::TexelFormat::kR32Uint:
+      case core::TexelFormat::kRg32Uint:
+      case core::TexelFormat::kRgba32Uint:
+        return number;
+      default:
+        return Number::invalid;
+    }
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "rgba8uint, rgba16uint, r32uint, rg32uint or rgba32uint";
+  }
+};
+
+/// EnumMatcher for 'match write'
+constexpr NumberMatcher kWriteMatcher {
+/* match */ [](MatchState&, Number number) -> Number {
+    if (number.IsAny() || number.Value() == static_cast<uint32_t>(core::Access::kWrite)) {
+      return Number(static_cast<uint32_t>(core::Access::kWrite));
+    }
+    return Number::invalid;
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "write";
+  }
+};
+
+/// EnumMatcher for 'match read_write'
+constexpr NumberMatcher kReadWriteMatcher {
+/* match */ [](MatchState&, Number number) -> Number {
+    if (number.IsAny() || number.Value() == static_cast<uint32_t>(core::Access::kReadWrite)) {
+      return Number(static_cast<uint32_t>(core::Access::kReadWrite));
+    }
+    return Number::invalid;
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "read_write";
+  }
+};
+
+/// EnumMatcher for 'match readable'
+constexpr NumberMatcher kReadableMatcher {
+/* match */ [](MatchState&, Number number) -> Number {
+    switch (static_cast<core::Access>(number.Value())) {
+      case core::Access::kRead:
+      case core::Access::kReadWrite:
+        return number;
+      default:
+        return Number::invalid;
+    }
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "read or read_write";
+  }
+};
+
+/// EnumMatcher for 'match writable'
+constexpr NumberMatcher kWritableMatcher {
+/* match */ [](MatchState&, Number number) -> Number {
+    switch (static_cast<core::Access>(number.Value())) {
+      case core::Access::kWrite:
+      case core::Access::kReadWrite:
+        return number;
+      default:
+        return Number::invalid;
+    }
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "write or read_write";
+  }
+};
+
+/// EnumMatcher for 'match function_private_workgroup'
+constexpr NumberMatcher kFunctionPrivateWorkgroupMatcher {
+/* match */ [](MatchState&, Number number) -> Number {
+    switch (static_cast<core::AddressSpace>(number.Value())) {
+      case core::AddressSpace::kFunction:
+      case core::AddressSpace::kPrivate:
+      case core::AddressSpace::kWorkgroup:
+        return number;
+      default:
+        return Number::invalid;
+    }
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "function, private or workgroup";
+  }
+};
+
+/// EnumMatcher for 'match workgroup_or_storage'
+constexpr NumberMatcher kWorkgroupOrStorageMatcher {
+/* match */ [](MatchState&, Number number) -> Number {
+    switch (static_cast<core::AddressSpace>(number.Value())) {
+      case core::AddressSpace::kWorkgroup:
+      case core::AddressSpace::kStorage:
+        return number;
+      default:
+        return Number::invalid;
+    }
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "workgroup or storage";
+  }
+};
+
+/// EnumMatcher for 'match storage'
+constexpr NumberMatcher kStorageMatcher {
+/* match */ [](MatchState&, Number number) -> Number {
+    if (number.IsAny() || number.Value() == static_cast<uint32_t>(core::AddressSpace::kStorage)) {
+      return Number(static_cast<uint32_t>(core::AddressSpace::kStorage));
+    }
+    return Number::invalid;
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "storage";
+  }
+};
+
+/// EnumMatcher for 'match workgroup'
+constexpr NumberMatcher kWorkgroupMatcher {
+/* match */ [](MatchState&, Number number) -> Number {
+    if (number.IsAny() || number.Value() == static_cast<uint32_t>(core::AddressSpace::kWorkgroup)) {
+      return Number(static_cast<uint32_t>(core::AddressSpace::kWorkgroup));
+    }
+    return Number::invalid;
+  },
+/* string */ [](MatchState*) -> std::string {
+    return "workgroup";
+  }
+};
+
+/// Type and number matchers
+
+/// The template types, types, and type matchers
+constexpr TypeMatcher kTypeMatchers[] = {
+  /* [0] */ TemplateTypeMatcher<0>::matcher,
+  /* [1] */ TemplateTypeMatcher<1>::matcher,
+  /* [2] */ TemplateTypeMatcher<2>::matcher,
+  /* [3] */ TemplateTypeMatcher<3>::matcher,
+  /* [4] */ kBoolMatcher,
+  /* [5] */ kIaMatcher,
+  /* [6] */ kFaMatcher,
+  /* [7] */ kI32Matcher,
+  /* [8] */ kU32Matcher,
+  /* [9] */ kF32Matcher,
+  /* [10] */ kF16Matcher,
+  /* [11] */ kVec2Matcher,
+  /* [12] */ kVec3Matcher,
+  /* [13] */ kVec4Matcher,
+  /* [14] */ kMat2X2Matcher,
+  /* [15] */ kMat2X3Matcher,
+  /* [16] */ kMat2X4Matcher,
+  /* [17] */ kMat3X2Matcher,
+  /* [18] */ kMat3X3Matcher,
+  /* [19] */ kMat3X4Matcher,
+  /* [20] */ kMat4X2Matcher,
+  /* [21] */ kMat4X3Matcher,
+  /* [22] */ kMat4X4Matcher,
+  /* [23] */ kVecMatcher,
+  /* [24] */ kMatMatcher,
+  /* [25] */ kPtrMatcher,
+  /* [26] */ kAtomicMatcher,
+  /* [27] */ kArrayMatcher,
+  /* [28] */ kSamplerMatcher,
+  /* [29] */ kSamplerComparisonMatcher,
+  /* [30] */ kTexture1DMatcher,
+  /* [31] */ kTexture2DMatcher,
+  /* [32] */ kTexture2DArrayMatcher,
+  /* [33] */ kTexture3DMatcher,
+  /* [34] */ kTextureCubeMatcher,
+  /* [35] */ kTextureCubeArrayMatcher,
+  /* [36] */ kTextureMultisampled2DMatcher,
+  /* [37] */ kTextureDepth2DMatcher,
+  /* [38] */ kTextureDepth2DArrayMatcher,
+  /* [39] */ kTextureDepthCubeMatcher,
+  /* [40] */ kTextureDepthCubeArrayMatcher,
+  /* [41] */ kTextureDepthMultisampled2DMatcher,
+  /* [42] */ kTextureStorage1DMatcher,
+  /* [43] */ kTextureStorage2DMatcher,
+  /* [44] */ kTextureStorage2DArrayMatcher,
+  /* [45] */ kTextureStorage3DMatcher,
+  /* [46] */ kTextureExternalMatcher,
+  /* [47] */ kPackedVec3Matcher,
+  /* [48] */ kModfResultMatcher,
+  /* [49] */ kModfResultVecMatcher,
+  /* [50] */ kFrexpResultMatcher,
+  /* [51] */ kFrexpResultVecMatcher,
+  /* [52] */ kAtomicCompareExchangeResultMatcher,
+  /* [53] */ kScalarMatcher,
+  /* [54] */ kConcreteScalarMatcher,
+  /* [55] */ kScalarNoF32Matcher,
+  /* [56] */ kScalarNoF16Matcher,
+  /* [57] */ kScalarNoI32Matcher,
+  /* [58] */ kScalarNoU32Matcher,
+  /* [59] */ kScalarNoBoolMatcher,
+  /* [60] */ kFiaFiu32F16Matcher,
+  /* [61] */ kFiaFi32F16Matcher,
+  /* [62] */ kFiaFiu32Matcher,
+  /* [63] */ kFaF32Matcher,
+  /* [64] */ kFaF32F16Matcher,
+  /* [65] */ kIaIu32Matcher,
+  /* [66] */ kIaI32Matcher,
+  /* [67] */ kFiu32F16Matcher,
+  /* [68] */ kFiu32Matcher,
+  /* [69] */ kFi32F16Matcher,
+  /* [70] */ kFi32Matcher,
+  /* [71] */ kF32F16Matcher,
+  /* [72] */ kIu32Matcher,
+};
+
+/// The template numbers, and number matchers
+constexpr NumberMatcher kNumberMatchers[] = {
+  /* [0] */ TemplateNumberMatcher<0>::matcher,
+  /* [1] */ TemplateNumberMatcher<1>::matcher,
+  /* [2] */ TemplateNumberMatcher<2>::matcher,
+  /* [3] */ kF32TexelFormatMatcher,
+  /* [4] */ kI32TexelFormatMatcher,
+  /* [5] */ kU32TexelFormatMatcher,
+  /* [6] */ kWriteMatcher,
+  /* [7] */ kReadWriteMatcher,
+  /* [8] */ kReadableMatcher,
+  /* [9] */ kWritableMatcher,
+  /* [10] */ kFunctionPrivateWorkgroupMatcher,
+  /* [11] */ kWorkgroupOrStorageMatcher,
+  /* [12] */ kStorageMatcher,
+  /* [13] */ kWorkgroupMatcher,
+};
+
+constexpr TypeMatcherIndex kTypeMatcherIndices[] = {
+  /* [0] */ TypeMatcherIndex(25),
+  /* [1] */ TypeMatcherIndex(27),
+  /* [2] */ TypeMatcherIndex(0),
+  /* [3] */ TypeMatcherIndex(25),
+  /* [4] */ TypeMatcherIndex(26),
+  /* [5] */ TypeMatcherIndex(0),
+  /* [6] */ TypeMatcherIndex(23),
+  /* [7] */ TypeMatcherIndex(0),
+  /* [8] */ TypeMatcherIndex(23),
+  /* [9] */ TypeMatcherIndex(4),
+  /* [10] */ TypeMatcherIndex(12),
+  /* [11] */ TypeMatcherIndex(0),
+  /* [12] */ TypeMatcherIndex(24),
+  /* [13] */ TypeMatcherIndex(0),
+  /* [14] */ TypeMatcherIndex(23),
+  /* [15] */ TypeMatcherIndex(9),
+  /* [16] */ TypeMatcherIndex(50),
+  /* [17] */ TypeMatcherIndex(0),
+  /* [18] */ TypeMatcherIndex(51),
+  /* [19] */ TypeMatcherIndex(0),
+  /* [20] */ TypeMatcherIndex(23),
+  /* [21] */ TypeMatcherIndex(1),
+  /* [22] */ TypeMatcherIndex(48),
+  /* [23] */ TypeMatcherIndex(0),
+  /* [24] */ TypeMatcherIndex(49),
+  /* [25] */ TypeMatcherIndex(0),
+  /* [26] */ TypeMatcherIndex(11),
+  /* [27] */ TypeMatcherIndex(9),
+  /* [28] */ TypeMatcherIndex(13),
+  /* [29] */ TypeMatcherIndex(9),
+  /* [30] */ TypeMatcherIndex(25),
+  /* [31] */ TypeMatcherIndex(0),
+  /* [32] */ TypeMatcherIndex(30),
+  /* [33] */ TypeMatcherIndex(0),
+  /* [34] */ TypeMatcherIndex(11),
+  /* [35] */ TypeMatcherIndex(8),
+  /* [36] */ TypeMatcherIndex(31),
+  /* [37] */ TypeMatcherIndex(0),
+  /* [38] */ TypeMatcherIndex(32),
+  /* [39] */ TypeMatcherIndex(0),
+  /* [40] */ TypeMatcherIndex(12),
+  /* [41] */ TypeMatcherIndex(8),
+  /* [42] */ TypeMatcherIndex(33),
+  /* [43] */ TypeMatcherIndex(0),
+  /* [44] */ TypeMatcherIndex(34),
+  /* [45] */ TypeMatcherIndex(0),
+  /* [46] */ TypeMatcherIndex(35),
+  /* [47] */ TypeMatcherIndex(0),
+  /* [48] */ TypeMatcherIndex(36),
+  /* [49] */ TypeMatcherIndex(0),
+  /* [50] */ TypeMatcherIndex(13),
+  /* [51] */ TypeMatcherIndex(0),
+  /* [52] */ TypeMatcherIndex(11),
+  /* [53] */ TypeMatcherIndex(7),
+  /* [54] */ TypeMatcherIndex(12),
+  /* [55] */ TypeMatcherIndex(9),
+  /* [56] */ TypeMatcherIndex(30),
+  /* [57] */ TypeMatcherIndex(9),
+  /* [58] */ TypeMatcherIndex(31),
+  /* [59] */ TypeMatcherIndex(9),
+  /* [60] */ TypeMatcherIndex(32),
+  /* [61] */ TypeMatcherIndex(9),
+  /* [62] */ TypeMatcherIndex(33),
+  /* [63] */ TypeMatcherIndex(9),
+  /* [64] */ TypeMatcherIndex(12),
+  /* [65] */ TypeMatcherIndex(7),
+  /* [66] */ TypeMatcherIndex(34),
+  /* [67] */ TypeMatcherIndex(9),
+  /* [68] */ TypeMatcherIndex(35),
+  /* [69] */ TypeMatcherIndex(9),
+  /* [70] */ TypeMatcherIndex(11),
+  /* [71] */ TypeMatcherIndex(0),
+  /* [72] */ TypeMatcherIndex(13),
+  /* [73] */ TypeMatcherIndex(7),
+  /* [74] */ TypeMatcherIndex(13),
+  /* [75] */ TypeMatcherIndex(8),
+  /* [76] */ TypeMatcherIndex(11),
+  /* [77] */ TypeMatcherIndex(1),
+  /* [78] */ TypeMatcherIndex(12),
+  /* [79] */ TypeMatcherIndex(1),
+  /* [80] */ TypeMatcherIndex(52),
+  /* [81] */ TypeMatcherIndex(0),
+  /* [82] */ TypeMatcherIndex(23),
+  /* [83] */ TypeMatcherIndex(8),
+  /* [84] */ TypeMatcherIndex(11),
+  /* [85] */ TypeMatcherIndex(5),
+  /* [86] */ TypeMatcherIndex(11),
+  /* [87] */ TypeMatcherIndex(10),
+  /* [88] */ TypeMatcherIndex(11),
+  /* [89] */ TypeMatcherIndex(4),
+  /* [90] */ TypeMatcherIndex(12),
+  /* [91] */ TypeMatcherIndex(5),
+  /* [92] */ TypeMatcherIndex(12),
+  /* [93] */ TypeMatcherIndex(10),
+  /* [94] */ TypeMatcherIndex(12),
+  /* [95] */ TypeMatcherIndex(4),
+  /* [96] */ TypeMatcherIndex(13),
+  /* [97] */ TypeMatcherIndex(5),
+  /* [98] */ TypeMatcherIndex(13),
+  /* [99] */ TypeMatcherIndex(1),
+  /* [100] */ TypeMatcherIndex(13),
+  /* [101] */ TypeMatcherIndex(10),
+  /* [102] */ TypeMatcherIndex(13),
+  /* [103] */ TypeMatcherIndex(4),
+  /* [104] */ TypeMatcherIndex(14),
+  /* [105] */ TypeMatcherIndex(0),
+  /* [106] */ TypeMatcherIndex(14),
+  /* [107] */ TypeMatcherIndex(10),
+  /* [108] */ TypeMatcherIndex(14),
+  /* [109] */ TypeMatcherIndex(9),
+  /* [110] */ TypeMatcherIndex(15),
+  /* [111] */ TypeMatcherIndex(0),
+  /* [112] */ TypeMatcherIndex(15),
+  /* [113] */ TypeMatcherIndex(10),
+  /* [114] */ TypeMatcherIndex(15),
+  /* [115] */ TypeMatcherIndex(9),
+  /* [116] */ TypeMatcherIndex(16),
+  /* [117] */ TypeMatcherIndex(0),
+  /* [118] */ TypeMatcherIndex(16),
+  /* [119] */ TypeMatcherIndex(10),
+  /* [120] */ TypeMatcherIndex(16),
+  /* [121] */ TypeMatcherIndex(9),
+  /* [122] */ TypeMatcherIndex(17),
+  /* [123] */ TypeMatcherIndex(0),
+  /* [124] */ TypeMatcherIndex(17),
+  /* [125] */ TypeMatcherIndex(10),
+  /* [126] */ TypeMatcherIndex(17),
+  /* [127] */ TypeMatcherIndex(9),
+  /* [128] */ TypeMatcherIndex(18),
+  /* [129] */ TypeMatcherIndex(0),
+  /* [130] */ TypeMatcherIndex(18),
+  /* [131] */ TypeMatcherIndex(10),
+  /* [132] */ TypeMatcherIndex(18),
+  /* [133] */ TypeMatcherIndex(9),
+  /* [134] */ TypeMatcherIndex(19),
+  /* [135] */ TypeMatcherIndex(0),
+  /* [136] */ TypeMatcherIndex(19),
+  /* [137] */ TypeMatcherIndex(10),
+  /* [138] */ TypeMatcherIndex(19),
+  /* [139] */ TypeMatcherIndex(9),
+  /* [140] */ TypeMatcherIndex(20),
+  /* [141] */ TypeMatcherIndex(0),
+  /* [142] */ TypeMatcherIndex(20),
+  /* [143] */ TypeMatcherIndex(10),
+  /* [144] */ TypeMatcherIndex(20),
+  /* [145] */ TypeMatcherIndex(9),
+  /* [146] */ TypeMatcherIndex(21),
+  /* [147] */ TypeMatcherIndex(0),
+  /* [148] */ TypeMatcherIndex(21),
+  /* [149] */ TypeMatcherIndex(10),
+  /* [150] */ TypeMatcherIndex(21),
+  /* [151] */ TypeMatcherIndex(9),
+  /* [152] */ TypeMatcherIndex(22),
+  /* [153] */ TypeMatcherIndex(0),
+  /* [154] */ TypeMatcherIndex(22),
+  /* [155] */ TypeMatcherIndex(10),
+  /* [156] */ TypeMatcherIndex(22),
+  /* [157] */ TypeMatcherIndex(9),
+  /* [158] */ TypeMatcherIndex(47),
+  /* [159] */ TypeMatcherIndex(0),
+  /* [160] */ TypeMatcherIndex(37),
+  /* [161] */ TypeMatcherIndex(38),
+  /* [162] */ TypeMatcherIndex(39),
+  /* [163] */ TypeMatcherIndex(40),
+  /* [164] */ TypeMatcherIndex(41),
+  /* [165] */ TypeMatcherIndex(42),
+  /* [166] */ TypeMatcherIndex(43),
+  /* [167] */ TypeMatcherIndex(44),
+  /* [168] */ TypeMatcherIndex(45),
+  /* [169] */ TypeMatcherIndex(46),
+  /* [170] */ TypeMatcherIndex(28),
+  /* [171] */ TypeMatcherIndex(2),
+  /* [172] */ TypeMatcherIndex(29),
+  /* [173] */ TypeMatcherIndex(3),
+};
+
+static_assert(TypeMatcherIndex::CanIndex(kTypeMatcherIndices),
+              "TypeMatcherIndex is not large enough to index kTypeMatcherIndices");
+
+constexpr NumberMatcherIndex kNumberMatcherIndices[] = {
+  /* [0] */ NumberMatcherIndex(12),
+  /* [1] */ NumberMatcherIndex(0),
+  /* [2] */ NumberMatcherIndex(0),
+  /* [3] */ NumberMatcherIndex(1),
+  /* [4] */ NumberMatcherIndex(0),
+  /* [5] */ NumberMatcherIndex(7),
+  /* [6] */ NumberMatcherIndex(13),
+  /* [7] */ NumberMatcherIndex(7),
+  /* [8] */ NumberMatcherIndex(3),
+  /* [9] */ NumberMatcherIndex(9),
+  /* [10] */ NumberMatcherIndex(4),
+  /* [11] */ NumberMatcherIndex(9),
+  /* [12] */ NumberMatcherIndex(5),
+  /* [13] */ NumberMatcherIndex(9),
+  /* [14] */ NumberMatcherIndex(3),
+  /* [15] */ NumberMatcherIndex(8),
+  /* [16] */ NumberMatcherIndex(4),
+  /* [17] */ NumberMatcherIndex(8),
+  /* [18] */ NumberMatcherIndex(5),
+  /* [19] */ NumberMatcherIndex(8),
+  /* [20] */ NumberMatcherIndex(1),
+  /* [21] */ NumberMatcherIndex(2),
+  /* [22] */ NumberMatcherIndex(0),
+  /* [23] */ NumberMatcherIndex(2),
+};
+
+static_assert(NumberMatcherIndex::CanIndex(kNumberMatcherIndices),
+              "NumberMatcherIndex is not large enough to index kNumberMatcherIndices");
+
+constexpr ParameterInfo kParameters[] = {
+  {
+    /* [0] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(3),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(4),
+  },
+  {
+    /* [1] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [2] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [3] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [4] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [5] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [6] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [7] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [8] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [9] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [10] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [11] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [12] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [13] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [14] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [15] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [16] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [17] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [18] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [19] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(60),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [20] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [21] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [22] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [23] */
+    /* usage */ core::ParameterUsage::kDdx,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [24] */
+    /* usage */ core::ParameterUsage::kDdy,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [25] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [26] */
+    /* usage */ core::ParameterUsage::kComponent,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [27] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(38),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [28] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [29] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [30] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(171),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [31] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [32] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(161),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [33] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(172),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [34] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [35] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [36] */
+    /* usage */ core::ParameterUsage::kDepthRef,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [37] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [38] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(60),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [39] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [40] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [41] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [42] */
+    /* usage */ core::ParameterUsage::kBias,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [43] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [44] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(58),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [45] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [46] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [47] */
+    /* usage */ core::ParameterUsage::kDdx,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [48] */
+    /* usage */ core::ParameterUsage::kDdy,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [49] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [50] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(62),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [51] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [52] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [53] */
+    /* usage */ core::ParameterUsage::kDdx,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [54] */
+    /* usage */ core::ParameterUsage::kDdy,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [55] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(64),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [56] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(68),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [57] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [58] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [59] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [60] */
+    /* usage */ core::ParameterUsage::kDdx,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [61] */
+    /* usage */ core::ParameterUsage::kDdy,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [62] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(60),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [63] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [64] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [65] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [66] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [67] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [68] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(161),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [69] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [70] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [71] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [72] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [73] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [74] */
+    /* usage */ core::ParameterUsage::kComponent,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [75] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(36),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [76] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [77] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [78] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [79] */
+    /* usage */ core::ParameterUsage::kComponent,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [80] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(46),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [81] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [82] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [83] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(171),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [84] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(161),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [85] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [86] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [87] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [88] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [89] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(160),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [90] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(172),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [91] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [92] */
+    /* usage */ core::ParameterUsage::kDepthRef,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [93] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [94] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(163),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [95] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(172),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [96] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [97] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [98] */
+    /* usage */ core::ParameterUsage::kDepthRef,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [99] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(60),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [100] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [101] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [102] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [103] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [104] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(58),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [105] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [106] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [107] */
+    /* usage */ core::ParameterUsage::kBias,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [108] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [109] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(62),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [110] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [111] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [112] */
+    /* usage */ core::ParameterUsage::kBias,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [113] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(64),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [114] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(68),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [115] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [116] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [117] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [118] */
+    /* usage */ core::ParameterUsage::kBias,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [119] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(66),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [120] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [121] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [122] */
+    /* usage */ core::ParameterUsage::kDdx,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [123] */
+    /* usage */ core::ParameterUsage::kDdy,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [124] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(58),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [125] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [126] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [127] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [128] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [129] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(62),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [130] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [131] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [132] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [133] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(64),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [134] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(68),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [135] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [136] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [137] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [138] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [139] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(160),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [140] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [141] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [142] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [143] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [144] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(163),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [145] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [146] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [147] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [148] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [149] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [150] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [151] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [152] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [153] */
+    /* usage */ core::ParameterUsage::kComponent,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [154] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(44),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [155] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [156] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [157] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(160),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [158] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [159] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [160] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [161] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(162),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [162] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(172),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [163] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [164] */
+    /* usage */ core::ParameterUsage::kDepthRef,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [165] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(58),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [166] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [167] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [168] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [169] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(62),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [170] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [171] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [172] */
+    /* usage */ core::ParameterUsage::kOffset,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(64),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [173] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(66),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [174] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [175] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [176] */
+    /* usage */ core::ParameterUsage::kBias,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [177] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(66),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [178] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [179] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [180] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [181] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(162),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [182] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [183] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [184] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [185] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(167),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(8),
+  },
+  {
+    /* [186] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [187] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [188] */
+    /* usage */ core::ParameterUsage::kValue,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [189] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(167),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(10),
+  },
+  {
+    /* [190] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [191] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [192] */
+    /* usage */ core::ParameterUsage::kValue,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(72),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [193] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(167),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(12),
+  },
+  {
+    /* [194] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [195] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [196] */
+    /* usage */ core::ParameterUsage::kValue,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(74),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [197] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(38),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [198] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(76),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [199] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(171),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [200] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(173),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [201] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(161),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [202] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [203] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [204] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(171),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [205] */
+    /* usage */ core::ParameterUsage::kX,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [206] */
+    /* usage */ core::ParameterUsage::kY,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [207] */
+    /* usage */ core::ParameterUsage::kZ,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [208] */
+    /* usage */ core::ParameterUsage::kW,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [209] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [210] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [211] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [212] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [213] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [214] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [215] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [216] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [217] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [218] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [219] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [220] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [221] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [222] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [223] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [224] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [225] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [226] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [227] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [228] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [229] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [230] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [231] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [232] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [233] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(8),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [234] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(8),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [235] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(56),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [236] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [237] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [238] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(169),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [239] */
+    /* usage */ core::ParameterUsage::kSampler,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(170),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [240] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [241] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(165),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(8),
+  },
+  {
+    /* [242] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [243] */
+    /* usage */ core::ParameterUsage::kValue,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [244] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(166),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(8),
+  },
+  {
+    /* [245] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [246] */
+    /* usage */ core::ParameterUsage::kValue,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [247] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(168),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(8),
+  },
+  {
+    /* [248] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [249] */
+    /* usage */ core::ParameterUsage::kValue,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [250] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(165),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(10),
+  },
+  {
+    /* [251] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [252] */
+    /* usage */ core::ParameterUsage::kValue,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(72),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [253] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(166),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(10),
+  },
+  {
+    /* [254] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [255] */
+    /* usage */ core::ParameterUsage::kValue,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(72),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [256] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(168),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(10),
+  },
+  {
+    /* [257] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [258] */
+    /* usage */ core::ParameterUsage::kValue,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(72),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [259] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(165),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(12),
+  },
+  {
+    /* [260] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [261] */
+    /* usage */ core::ParameterUsage::kValue,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(74),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [262] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(166),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(12),
+  },
+  {
+    /* [263] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [264] */
+    /* usage */ core::ParameterUsage::kValue,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(74),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [265] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(168),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(12),
+  },
+  {
+    /* [266] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [267] */
+    /* usage */ core::ParameterUsage::kValue,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(74),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [268] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(32),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [269] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [270] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(171),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [271] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(36),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [272] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(76),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [273] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(171),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [274] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(42),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [275] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(78),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [276] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(171),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [277] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(48),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [278] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(76),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [279] */
+    /* usage */ core::ParameterUsage::kSampleIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(171),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [280] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(160),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [281] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [282] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [283] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(164),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [284] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [285] */
+    /* usage */ core::ParameterUsage::kSampleIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [286] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(167),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(14),
+  },
+  {
+    /* [287] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [288] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [289] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(167),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(16),
+  },
+  {
+    /* [290] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [291] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [292] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(167),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(18),
+  },
+  {
+    /* [293] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [294] */
+    /* usage */ core::ParameterUsage::kArrayIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [295] */
+    /* usage */ core::ParameterUsage::kXy,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [296] */
+    /* usage */ core::ParameterUsage::kZ,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [297] */
+    /* usage */ core::ParameterUsage::kW,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [298] */
+    /* usage */ core::ParameterUsage::kX,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [299] */
+    /* usage */ core::ParameterUsage::kYz,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [300] */
+    /* usage */ core::ParameterUsage::kW,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [301] */
+    /* usage */ core::ParameterUsage::kX,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [302] */
+    /* usage */ core::ParameterUsage::kY,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [303] */
+    /* usage */ core::ParameterUsage::kZw,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [304] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [305] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [306] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [307] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(20),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [308] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(32),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [309] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [310] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(36),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [311] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [312] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(38),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [313] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [314] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(42),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [315] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [316] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(44),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [317] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [318] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(46),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [319] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(21),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [320] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(160),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [321] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [322] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(161),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [323] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [324] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(162),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [325] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [326] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(163),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [327] */
+    /* usage */ core::ParameterUsage::kLevel,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [328] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(169),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [329] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [330] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(165),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(14),
+  },
+  {
+    /* [331] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [332] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(165),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(16),
+  },
+  {
+    /* [333] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [334] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(165),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(18),
+  },
+  {
+    /* [335] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [336] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(166),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(14),
+  },
+  {
+    /* [337] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [338] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(166),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(16),
+  },
+  {
+    /* [339] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [340] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(166),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(18),
+  },
+  {
+    /* [341] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [342] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(168),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(14),
+  },
+  {
+    /* [343] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [344] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(168),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(16),
+  },
+  {
+    /* [345] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [346] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(168),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(18),
+  },
+  {
+    /* [347] */
+    /* usage */ core::ParameterUsage::kCoords,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [348] */
+    /* usage */ core::ParameterUsage::kValue,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [349] */
+    /* usage */ core::ParameterUsage::kSourceLaneIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [350] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [351] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [352] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(82),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [353] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
+  },
+  {
+    /* [354] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
+  },
+  {
+    /* [355] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [356] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
+  },
+  {
+    /* [357] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [358] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(3),
+  },
+  {
+    /* [359] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
+  },
+  {
+    /* [360] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(22),
+  },
+  {
+    /* [361] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(3),
+  },
+  {
+    /* [362] */
+    /* usage */ core::ParameterUsage::kXy,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [363] */
+    /* usage */ core::ParameterUsage::kZw,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [364] */
+    /* usage */ core::ParameterUsage::kXyz,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [365] */
+    /* usage */ core::ParameterUsage::kW,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [366] */
+    /* usage */ core::ParameterUsage::kX,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [367] */
+    /* usage */ core::ParameterUsage::kZyw,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [368] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(0),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(0),
+  },
+  {
+    /* [369] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [370] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [371] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(14),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [372] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [373] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [374] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(30),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(6),
+  },
+  {
+    /* [375] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(165),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
+  },
+  {
+    /* [376] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(166),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
+  },
+  {
+    /* [377] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(167),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
+  },
+  {
+    /* [378] */
+    /* usage */ core::ParameterUsage::kTexture,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(168),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
+  },
+  {
+    /* [379] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(53),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [380] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(87),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [381] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(76),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [382] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(78),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [383] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(98),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [384] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(104),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [385] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(108),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [386] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(106),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [387] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(110),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [388] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(114),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [389] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(112),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [390] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(116),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [391] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(120),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [392] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(118),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [393] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(122),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [394] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(126),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [395] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(124),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [396] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(128),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [397] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(132),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [398] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(130),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [399] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(134),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [400] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(138),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [401] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(136),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [402] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(140),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [403] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(144),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [404] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(142),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [405] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(146),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [406] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(150),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [407] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(148),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [408] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(152),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [409] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(156),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [410] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(154),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+};
+
+static_assert(ParameterIndex::CanIndex(kParameters),
+              "ParameterIndex is not large enough to index kParameters");
+
+constexpr TemplateTypeInfo kTemplateTypes[] = {
+  {
+    /* [0] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(68),
+  },
+  {
+    /* [1] */
+    /* name */ "C",
+    /* matcher_index */ TypeMatcherIndex(72),
+  },
+  {
+    /* [2] */
+    /* name */ "A",
+    /* matcher_index */ TypeMatcherIndex(72),
+  },
+  {
+    /* [3] */
+    /* name */ "L",
+    /* matcher_index */ TypeMatcherIndex(72),
+  },
+  {
+    /* [4] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(68),
+  },
+  {
+    /* [5] */
+    /* name */ "C",
+    /* matcher_index */ TypeMatcherIndex(72),
+  },
+  {
+    /* [6] */
+    /* name */ "L",
+    /* matcher_index */ TypeMatcherIndex(72),
+  },
+  {
+    /* [7] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(68),
+  },
+  {
+    /* [8] */
+    /* name */ "C",
+    /* matcher_index */ TypeMatcherIndex(72),
+  },
+  {
+    /* [9] */
+    /* name */ "S",
+    /* matcher_index */ TypeMatcherIndex(72),
+  },
+  {
+    /* [10] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(64),
+  },
+  {
+    /* [11] */
+    /* name */ "U",
+    /* matcher_index */ TypeMatcherIndex(66),
+  },
+  {
+    /* [12] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(68),
+  },
+  {
+    /* [13] */
+    /* name */ "L",
+    /* matcher_index */ TypeMatcherIndex(72),
+  },
+  {
+    /* [14] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(9),
+  },
+  {
+    /* [15] */
+    /* name */ "U",
+    /* matcher_index */ TypeMatcherIndex(55),
+  },
+  {
+    /* [16] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(10),
+  },
+  {
+    /* [17] */
+    /* name */ "U",
+    /* matcher_index */ TypeMatcherIndex(56),
+  },
+  {
+    /* [18] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(7),
+  },
+  {
+    /* [19] */
+    /* name */ "U",
+    /* matcher_index */ TypeMatcherIndex(57),
+  },
+  {
+    /* [20] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(8),
+  },
+  {
+    /* [21] */
+    /* name */ "U",
+    /* matcher_index */ TypeMatcherIndex(58),
+  },
+  {
+    /* [22] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(4),
+  },
+  {
+    /* [23] */
+    /* name */ "U",
+    /* matcher_index */ TypeMatcherIndex(59),
+  },
+  {
+    /* [24] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(60),
+  },
+  {
+    /* [25] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(/* invalid */),
+  },
+  {
+    /* [26] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(72),
+  },
+  {
+    /* [27] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(53),
+  },
+  {
+    /* [28] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(61),
+  },
+  {
+    /* [29] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(65),
+  },
+  {
+    /* [30] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(57),
+  },
+  {
+    /* [31] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(58),
+  },
+  {
+    /* [32] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(55),
+  },
+  {
+    /* [33] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(56),
+  },
+  {
+    /* [34] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(59),
+  },
+  {
+    /* [35] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(54),
+  },
+  {
+    /* [36] */
+    /* name */ "T",
+    /* matcher_index */ TypeMatcherIndex(71),
+  },
+};
+
+static_assert(TemplateTypeIndex::CanIndex(kTemplateTypes),
+              "TemplateTypeIndex is not large enough to index kTemplateTypes");
+
+constexpr TemplateNumberInfo kTemplateNumbers[] = {
+  {
+    /* [0] */
+    /* name */ "K",
+    /* matcher_index */ NumberMatcherIndex(/* invalid */),
+  },
+  {
+    /* [1] */
+    /* name */ "C",
+    /* matcher_index */ NumberMatcherIndex(/* invalid */),
+  },
+  {
+    /* [2] */
+    /* name */ "R",
+    /* matcher_index */ NumberMatcherIndex(/* invalid */),
+  },
+  {
+    /* [3] */
+    /* name */ "M",
+    /* matcher_index */ NumberMatcherIndex(/* invalid */),
+  },
+  {
+    /* [4] */
+    /* name */ "N",
+    /* matcher_index */ NumberMatcherIndex(/* invalid */),
+  },
+  {
+    /* [5] */
+    /* name */ "M",
+    /* matcher_index */ NumberMatcherIndex(/* invalid */),
+  },
+  {
+    /* [6] */
+    /* name */ "F",
+    /* matcher_index */ NumberMatcherIndex(/* invalid */),
+  },
+  {
+    /* [7] */
+    /* name */ "A",
+    /* matcher_index */ NumberMatcherIndex(/* invalid */),
+  },
+  {
+    /* [8] */
+    /* name */ "S",
+    /* matcher_index */ NumberMatcherIndex(11),
+  },
+};
+
+static_assert(TemplateNumberIndex::CanIndex(kTemplateNumbers),
+              "TemplateNumberIndex is not large enough to index kTemplateNumbers");
+
+constexpr core::constant::Eval::Function kConstEvalFunctions[] = {
+  /* [0] */ &core::constant::Eval::abs,
+  /* [1] */ &core::constant::Eval::acos,
+  /* [2] */ &core::constant::Eval::acosh,
+  /* [3] */ &core::constant::Eval::all,
+  /* [4] */ &core::constant::Eval::any,
+  /* [5] */ &core::constant::Eval::asin,
+  /* [6] */ &core::constant::Eval::asinh,
+  /* [7] */ &core::constant::Eval::atan,
+  /* [8] */ &core::constant::Eval::atan2,
+  /* [9] */ &core::constant::Eval::atanh,
+  /* [10] */ &core::constant::Eval::ceil,
+  /* [11] */ &core::constant::Eval::clamp,
+  /* [12] */ &core::constant::Eval::cos,
+  /* [13] */ &core::constant::Eval::cosh,
+  /* [14] */ &core::constant::Eval::countLeadingZeros,
+  /* [15] */ &core::constant::Eval::countOneBits,
+  /* [16] */ &core::constant::Eval::countTrailingZeros,
+  /* [17] */ &core::constant::Eval::cross,
+  /* [18] */ &core::constant::Eval::degrees,
+  /* [19] */ &core::constant::Eval::determinant,
+  /* [20] */ &core::constant::Eval::distance,
+  /* [21] */ &core::constant::Eval::dot,
+  /* [22] */ &core::constant::Eval::exp,
+  /* [23] */ &core::constant::Eval::exp2,
+  /* [24] */ &core::constant::Eval::extractBits,
+  /* [25] */ &core::constant::Eval::faceForward,
+  /* [26] */ &core::constant::Eval::firstLeadingBit,
+  /* [27] */ &core::constant::Eval::firstTrailingBit,
+  /* [28] */ &core::constant::Eval::floor,
+  /* [29] */ &core::constant::Eval::fma,
+  /* [30] */ &core::constant::Eval::fract,
+  /* [31] */ &core::constant::Eval::frexp,
+  /* [32] */ &core::constant::Eval::insertBits,
+  /* [33] */ &core::constant::Eval::inverseSqrt,
+  /* [34] */ &core::constant::Eval::ldexp,
+  /* [35] */ &core::constant::Eval::length,
+  /* [36] */ &core::constant::Eval::log,
+  /* [37] */ &core::constant::Eval::log2,
+  /* [38] */ &core::constant::Eval::max,
+  /* [39] */ &core::constant::Eval::min,
+  /* [40] */ &core::constant::Eval::mix,
+  /* [41] */ &core::constant::Eval::modf,
+  /* [42] */ &core::constant::Eval::normalize,
+  /* [43] */ &core::constant::Eval::pack2x16float,
+  /* [44] */ &core::constant::Eval::pack2x16snorm,
+  /* [45] */ &core::constant::Eval::pack2x16unorm,
+  /* [46] */ &core::constant::Eval::pack4x8snorm,
+  /* [47] */ &core::constant::Eval::pack4x8unorm,
+  /* [48] */ &core::constant::Eval::pow,
+  /* [49] */ &core::constant::Eval::quantizeToF16,
+  /* [50] */ &core::constant::Eval::radians,
+  /* [51] */ &core::constant::Eval::reflect,
+  /* [52] */ &core::constant::Eval::refract,
+  /* [53] */ &core::constant::Eval::reverseBits,
+  /* [54] */ &core::constant::Eval::round,
+  /* [55] */ &core::constant::Eval::saturate,
+  /* [56] */ &core::constant::Eval::select_bool,
+  /* [57] */ &core::constant::Eval::select_boolvec,
+  /* [58] */ &core::constant::Eval::sign,
+  /* [59] */ &core::constant::Eval::sin,
+  /* [60] */ &core::constant::Eval::sinh,
+  /* [61] */ &core::constant::Eval::smoothstep,
+  /* [62] */ &core::constant::Eval::sqrt,
+  /* [63] */ &core::constant::Eval::step,
+  /* [64] */ &core::constant::Eval::tan,
+  /* [65] */ &core::constant::Eval::tanh,
+  /* [66] */ &core::constant::Eval::transpose,
+  /* [67] */ &core::constant::Eval::trunc,
+  /* [68] */ &core::constant::Eval::unpack2x16float,
+  /* [69] */ &core::constant::Eval::unpack2x16snorm,
+  /* [70] */ &core::constant::Eval::unpack2x16unorm,
+  /* [71] */ &core::constant::Eval::unpack4x8snorm,
+  /* [72] */ &core::constant::Eval::unpack4x8unorm,
+  /* [73] */ &core::constant::Eval::Identity,
+  /* [74] */ &core::constant::Eval::Not,
+  /* [75] */ &core::constant::Eval::Complement,
+  /* [76] */ &core::constant::Eval::UnaryMinus,
+  /* [77] */ &core::constant::Eval::Plus,
+  /* [78] */ &core::constant::Eval::Minus,
+  /* [79] */ &core::constant::Eval::Multiply,
+  /* [80] */ &core::constant::Eval::MultiplyMatVec,
+  /* [81] */ &core::constant::Eval::MultiplyVecMat,
+  /* [82] */ &core::constant::Eval::MultiplyMatMat,
+  /* [83] */ &core::constant::Eval::Divide,
+  /* [84] */ &core::constant::Eval::Modulo,
+  /* [85] */ &core::constant::Eval::Xor,
+  /* [86] */ &core::constant::Eval::And,
+  /* [87] */ &core::constant::Eval::Or,
+  /* [88] */ &core::constant::Eval::LogicalAnd,
+  /* [89] */ &core::constant::Eval::LogicalOr,
+  /* [90] */ &core::constant::Eval::Equal,
+  /* [91] */ &core::constant::Eval::NotEqual,
+  /* [92] */ &core::constant::Eval::LessThan,
+  /* [93] */ &core::constant::Eval::GreaterThan,
+  /* [94] */ &core::constant::Eval::LessThanEqual,
+  /* [95] */ &core::constant::Eval::GreaterThanEqual,
+  /* [96] */ &core::constant::Eval::ShiftLeft,
+  /* [97] */ &core::constant::Eval::ShiftRight,
+  /* [98] */ &core::constant::Eval::Zero,
+  /* [99] */ &core::constant::Eval::Conv,
+  /* [100] */ &core::constant::Eval::VecSplat,
+  /* [101] */ &core::constant::Eval::VecInitS,
+  /* [102] */ &core::constant::Eval::VecInitM,
+  /* [103] */ &core::constant::Eval::MatInitS,
+  /* [104] */ &core::constant::Eval::MatInitV,
+};
+
+static_assert(ConstEvalFunctionIndex::CanIndex(kConstEvalFunctions),
+              "ConstEvalFunctionIndex is not large enough to index kConstEvalFunctions");
+
+constexpr OverloadInfo kOverloads[] = {
+  {
+    /* [0] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(268),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [1] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(12),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(308),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [2] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(75),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [3] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(12),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(310),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [4] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(27),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [5] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(12),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(312),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [6] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(274),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(40),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [7] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(12),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(314),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(40),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [8] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(154),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [9] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(12),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(316),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [10] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(80),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [11] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(12),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(318),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [12] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(277),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [13] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(89),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [14] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(3),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(320),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [15] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(32),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [16] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(3),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(322),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [17] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(161),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [18] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(3),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(324),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [19] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(94),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [20] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(3),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(326),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [21] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(283),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [22] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 2,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(6),
+    /* parameters */ ParameterIndex(375),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [23] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 2,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(6),
+    /* parameters */ ParameterIndex(376),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [24] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 2,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(6),
+    /* parameters */ ParameterIndex(377),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [25] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 2,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(6),
+    /* parameters */ ParameterIndex(378),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(40),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [26] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(238),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [27] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 3,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(4),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(268),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [28] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 3,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(4),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(271),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [29] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 4,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(197),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [30] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 3,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(4),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(274),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [31] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 3,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(7),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(277),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [32] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(5),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(280),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [33] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 3,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(201),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [34] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(8),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(283),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [35] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(328),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [36] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(330),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [37] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(332),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(72),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [38] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(334),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(74),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [39] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(336),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [40] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(338),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(72),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [41] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(340),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(74),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [42] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(286),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [43] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(289),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(72),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [44] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(292),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(74),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [45] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(342),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [46] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(344),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(72),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [47] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(346),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(74),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [48] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(96),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [49] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(35),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [50] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(217),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [51] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(100),
+  },
+  {
+    /* [52] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(205),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(101),
+  },
+  {
+    /* [53] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(295),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(102),
+  },
+  {
+    /* [54] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(298),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(102),
+  },
+  {
+    /* [55] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(301),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(102),
+  },
+  {
+    /* [56] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(362),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(102),
+  },
+  {
+    /* [57] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(364),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(102),
+  },
+  {
+    /* [58] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(366),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(102),
+  },
+  {
+    /* [59] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(14),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(383),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [60] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(16),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(383),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(100),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [61] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(18),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(383),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(72),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [62] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(20),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(383),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(74),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [63] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(22),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(383),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(102),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [64] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(235),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [65] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(44),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [66] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(165),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [67] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(19),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [68] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(99),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [69] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(50),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [70] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(169),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [71] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(119),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [72] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(56),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [73] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(139),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [74] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(157),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [75] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(68),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [76] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(84),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [77] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(181),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [78] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(144),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [79] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(124),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [80] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(124),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [81] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(62),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [82] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 6,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(62),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [83] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(129),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [84] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(129),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [85] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(177),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [86] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(134),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [87] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(3),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(139),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [88] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(3),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(139),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [89] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(68),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [90] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 6,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(68),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [91] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(3),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(181),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [92] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(144),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [93] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(74),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [94] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(74),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [95] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 3,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(26),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [96] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 6,
+    /* num_template_types */ 3,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(26),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [97] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(153),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [98] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 3,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(79),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(50),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [99] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(139),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [100] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(157),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [101] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(68),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [102] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(84),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [103] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(181),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [104] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(144),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [105] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(241),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(/* invalid */),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [106] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(244),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(/* invalid */),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [107] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 4,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(185),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(/* invalid */),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [108] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(247),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(/* invalid */),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [109] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(250),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(/* invalid */),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [110] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(253),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(/* invalid */),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [111] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 4,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(189),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(/* invalid */),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [112] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(256),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(/* invalid */),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [113] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(259),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(/* invalid */),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [114] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(262),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(/* invalid */),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [115] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 4,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(193),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(/* invalid */),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [116] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(1),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(265),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(/* invalid */),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [117] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(90),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [118] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(35),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [119] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(213),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [120] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(100),
+  },
+  {
+    /* [121] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(205),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(101),
+  },
+  {
+    /* [122] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(295),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(102),
+  },
+  {
+    /* [123] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(298),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(102),
+  },
+  {
+    /* [124] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(14),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(382),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(54),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [125] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(16),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(382),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(92),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [126] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(18),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(382),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(64),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [127] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(20),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(382),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(40),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [128] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(22),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(382),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(94),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [129] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(268),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [130] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(75),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [131] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(27),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [132] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(274),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [133] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(154),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [134] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(80),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [135] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(89),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [136] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(32),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [137] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(161),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [138] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(94),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [139] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(84),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [140] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(35),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [141] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(209),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [142] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(100),
+  },
+  {
+    /* [143] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(205),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(70),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(101),
+  },
+  {
+    /* [144] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(14),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(381),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [145] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(16),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(381),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(86),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [146] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(18),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(381),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(52),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [147] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(20),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(381),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(34),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [148] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(22),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(381),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(88),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [149] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(79),
+  },
+  {
+    /* [150] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(79),
+  },
+  {
+    /* [151] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(223),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(79),
+  },
+  {
+    /* [152] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(350),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(79),
+  },
+  {
+    /* [153] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 2,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(355),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(2),
+    /* const_eval_fn */ ConstEvalFunctionIndex(79),
+  },
+  {
+    /* [154] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 2,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(354),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(2),
+    /* const_eval_fn */ ConstEvalFunctionIndex(79),
+  },
+  {
+    /* [155] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 2,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(1),
+    /* parameters */ ParameterIndex(356),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(3),
+    /* const_eval_fn */ ConstEvalFunctionIndex(80),
+  },
+  {
+    /* [156] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 2,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(1),
+    /* parameters */ ParameterIndex(358),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(81),
+  },
+  {
+    /* [157] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 3,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(0),
+    /* parameters */ ParameterIndex(360),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(20),
+    /* const_eval_fn */ ConstEvalFunctionIndex(82),
+  },
+  {
+    /* [158] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(104),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [159] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(104),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [160] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(38),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [161] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 6,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(38),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [162] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(109),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [163] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(109),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [164] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(173),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [165] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(114),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [166] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(44),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [167] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 6,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(44),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [168] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 6,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(19),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [169] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 7,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(19),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [170] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(50),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [171] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 6,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(50),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [172] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(119),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [173] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 6,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(56),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [174] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(89),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [175] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(89),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [176] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(32),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [177] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 6,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(32),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [178] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(161),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [179] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(94),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [180] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(89),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [181] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(89),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [182] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(32),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [183] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 6,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(32),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [184] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(161),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [185] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(94),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [186] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(89),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [187] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(89),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [188] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(32),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [189] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 6,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(32),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [190] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(161),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [191] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 5,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(2),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(94),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [192] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(104),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [193] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(384),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(104),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [194] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(104),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(103),
+  },
+  {
+    /* [195] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(209),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(104),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(104),
+  },
+  {
+    /* [196] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(16),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(385),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(106),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [197] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(14),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(386),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(108),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [198] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(110),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [199] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(387),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(110),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [200] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 6,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(110),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(103),
+  },
+  {
+    /* [201] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(213),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(110),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(104),
+  },
+  {
+    /* [202] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(16),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(388),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(112),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [203] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(14),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(389),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(114),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [204] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(116),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [205] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(390),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(116),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [206] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 8,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(116),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(103),
+  },
+  {
+    /* [207] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(217),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(116),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(104),
+  },
+  {
+    /* [208] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(16),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(391),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(118),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [209] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(14),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(392),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(120),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [210] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(122),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [211] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(393),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(122),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [212] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 6,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(122),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(103),
+  },
+  {
+    /* [213] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(209),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(122),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(104),
+  },
+  {
+    /* [214] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(16),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(394),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(124),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [215] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(14),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(395),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(126),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [216] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(128),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [217] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(396),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(128),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [218] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 9,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(128),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(103),
+  },
+  {
+    /* [219] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(213),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(128),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(104),
+  },
+  {
+    /* [220] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(16),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(397),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(130),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [221] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(14),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(398),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(132),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [222] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(134),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [223] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(399),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(134),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [224] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 12,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(134),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(103),
+  },
+  {
+    /* [225] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(217),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(134),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(104),
+  },
+  {
+    /* [226] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(16),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(400),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(136),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [227] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(14),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(401),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(138),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [228] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(140),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [229] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(402),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(140),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [230] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 8,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(140),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(103),
+  },
+  {
+    /* [231] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(209),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(140),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(104),
+  },
+  {
+    /* [232] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(16),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(403),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(142),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [233] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(14),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(404),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(144),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [234] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(146),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [235] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(405),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(146),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [236] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 12,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(146),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(103),
+  },
+  {
+    /* [237] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(213),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(146),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(104),
+  },
+  {
+    /* [238] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(16),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(406),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(148),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [239] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(14),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(407),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(150),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [240] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(152),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [241] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(36),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(408),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(152),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [242] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 16,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(152),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(103),
+  },
+  {
+    /* [243] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(217),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(152),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(104),
+  },
+  {
+    /* [244] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(16),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(409),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(154),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [245] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(14),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(410),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(156),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [246] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(27),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [247] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(80),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [248] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(32),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [249] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(94),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [250] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 2,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(6),
+    /* parameters */ ParameterIndex(377),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [251] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(77),
+  },
+  {
+    /* [252] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(77),
+  },
+  {
+    /* [253] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(223),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(77),
+  },
+  {
+    /* [254] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(350),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(77),
+  },
+  {
+    /* [255] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 2,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(353),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(2),
+    /* const_eval_fn */ ConstEvalFunctionIndex(77),
+  },
+  {
+    /* [256] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(78),
+  },
+  {
+    /* [257] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(78),
+  },
+  {
+    /* [258] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(223),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(78),
+  },
+  {
+    /* [259] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(350),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(78),
+  },
+  {
+    /* [260] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 2,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(353),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(2),
+    /* const_eval_fn */ ConstEvalFunctionIndex(78),
+  },
+  {
+    /* [261] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(83),
+  },
+  {
+    /* [262] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(83),
+  },
+  {
+    /* [263] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(223),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(83),
+  },
+  {
+    /* [264] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(350),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(83),
+  },
+  {
+    /* [265] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(84),
+  },
+  {
+    /* [266] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(84),
+  },
+  {
+    /* [267] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(223),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(84),
+  },
+  {
+    /* [268] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(350),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(84),
+  },
+  {
+    /* [269] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(226),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(86),
+  },
+  {
+    /* [270] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(233),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(8),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(86),
+  },
+  {
+    /* [271] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(29),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(86),
+  },
+  {
+    /* [272] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(29),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(86),
+  },
+  {
+    /* [273] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(226),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(87),
+  },
+  {
+    /* [274] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(233),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(8),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(87),
+  },
+  {
+    /* [275] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(29),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(87),
+  },
+  {
+    /* [276] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(29),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(87),
+  },
+  {
+    /* [277] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(40),
+  },
+  {
+    /* [278] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(221),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(40),
+  },
+  {
+    /* [279] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(222),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(40),
+  },
+  {
+    /* [280] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(224),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(56),
+  },
+  {
+    /* [281] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(228),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(56),
+  },
+  {
+    /* [282] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(231),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(57),
+  },
+  {
+    /* [283] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(53),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [284] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(379),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(53),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [285] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(30),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(53),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [286] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [287] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(17),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [288] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(31),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [289] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [290] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(370),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [291] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(32),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [292] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(87),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [293] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(380),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(87),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [294] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(33),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(87),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [295] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(98),
+  },
+  {
+    /* [296] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConstructor, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(226),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [297] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(34),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [298] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(0),
+  },
+  {
+    /* [299] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(0),
+  },
+  {
+    /* [300] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(1),
+  },
+  {
+    /* [301] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(1),
+  },
+  {
+    /* [302] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(2),
+  },
+  {
+    /* [303] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(2),
+  },
+  {
+    /* [304] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(226),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(3),
+  },
+  {
+    /* [305] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(233),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(3),
+  },
+  {
+    /* [306] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(226),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(4),
+  },
+  {
+    /* [307] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(233),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(4),
+  },
+  {
+    /* [308] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(5),
+  },
+  {
+    /* [309] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(5),
+  },
+  {
+    /* [310] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(6),
+  },
+  {
+    /* [311] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(6),
+  },
+  {
+    /* [312] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(7),
+  },
+  {
+    /* [313] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(7),
+  },
+  {
+    /* [314] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(8),
+  },
+  {
+    /* [315] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(8),
+  },
+  {
+    /* [316] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(9),
+  },
+  {
+    /* [317] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(9),
+  },
+  {
+    /* [318] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(10),
+  },
+  {
+    /* [319] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(10),
+  },
+  {
+    /* [320] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(11),
+  },
+  {
+    /* [321] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(221),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(11),
+  },
+  {
+    /* [322] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(12),
+  },
+  {
+    /* [323] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(12),
+  },
+  {
+    /* [324] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(13),
+  },
+  {
+    /* [325] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(13),
+  },
+  {
+    /* [326] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(14),
+  },
+  {
+    /* [327] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(14),
+  },
+  {
+    /* [328] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(15),
+  },
+  {
+    /* [329] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(15),
+  },
+  {
+    /* [330] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(16),
+  },
+  {
+    /* [331] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(16),
+  },
+  {
+    /* [332] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(18),
+  },
+  {
+    /* [333] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(18),
+  },
+  {
+    /* [334] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(20),
+  },
+  {
+    /* [335] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(20),
+  },
+  {
+    /* [336] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(370),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [337] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(371),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(14),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [338] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(22),
+  },
+  {
+    /* [339] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(22),
+  },
+  {
+    /* [340] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(23),
+  },
+  {
+    /* [341] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(23),
+  },
+  {
+    /* [342] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(16),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(24),
+  },
+  {
+    /* [343] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(150),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(24),
+  },
+  {
+    /* [344] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(26),
+  },
+  {
+    /* [345] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(26),
+  },
+  {
+    /* [346] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(27),
+  },
+  {
+    /* [347] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(27),
+  },
+  {
+    /* [348] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(28),
+  },
+  {
+    /* [349] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(28),
+  },
+  {
+    /* [350] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(29),
+  },
+  {
+    /* [351] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(221),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(29),
+  },
+  {
+    /* [352] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(30),
+  },
+  {
+    /* [353] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(30),
+  },
+  {
+    /* [354] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(16),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(31),
+  },
+  {
+    /* [355] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(18),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(31),
+  },
+  {
+    /* [356] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(15),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(32),
+  },
+  {
+    /* [357] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 4,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(32),
+  },
+  {
+    /* [358] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(33),
+  },
+  {
+    /* [359] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(33),
+  },
+  {
+    /* [360] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(304),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(34),
+  },
+  {
+    /* [361] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 2,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(306),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(34),
+  },
+  {
+    /* [362] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(35),
+  },
+  {
+    /* [363] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(35),
+  },
+  {
+    /* [364] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(36),
+  },
+  {
+    /* [365] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(36),
+  },
+  {
+    /* [366] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(37),
+  },
+  {
+    /* [367] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(37),
+  },
+  {
+    /* [368] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(38),
+  },
+  {
+    /* [369] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(38),
+  },
+  {
+    /* [370] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(39),
+  },
+  {
+    /* [371] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(39),
+  },
+  {
+    /* [372] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(22),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(41),
+  },
+  {
+    /* [373] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(24),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(41),
+  },
+  {
+    /* [374] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(48),
+  },
+  {
+    /* [375] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(48),
+  },
+  {
+    /* [376] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(370),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(49),
+  },
+  {
+    /* [377] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(371),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(14),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(49),
+  },
+  {
+    /* [378] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(50),
+  },
+  {
+    /* [379] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(50),
+  },
+  {
+    /* [380] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(53),
+  },
+  {
+    /* [381] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(53),
+  },
+  {
+    /* [382] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(54),
+  },
+  {
+    /* [383] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(54),
+  },
+  {
+    /* [384] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(55),
+  },
+  {
+    /* [385] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(55),
+  },
+  {
+    /* [386] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(28),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(58),
+  },
+  {
+    /* [387] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(28),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(58),
+  },
+  {
+    /* [388] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(59),
+  },
+  {
+    /* [389] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(59),
+  },
+  {
+    /* [390] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(60),
+  },
+  {
+    /* [391] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(60),
+  },
+  {
+    /* [392] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(61),
+  },
+  {
+    /* [393] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(221),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(61),
+  },
+  {
+    /* [394] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(62),
+  },
+  {
+    /* [395] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(62),
+  },
+  {
+    /* [396] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(63),
+  },
+  {
+    /* [397] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(63),
+  },
+  {
+    /* [398] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(64),
+  },
+  {
+    /* [399] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(64),
+  },
+  {
+    /* [400] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(65),
+  },
+  {
+    /* [401] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(65),
+  },
+  {
+    /* [402] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(67),
+  },
+  {
+    /* [403] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(67),
+  },
+  {
+    /* [404] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(277),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [405] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(283),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [406] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(44),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [407] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(238),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [408] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(226),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(74),
+  },
+  {
+    /* [409] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(233),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(8),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(74),
+  },
+  {
+    /* [410] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(29),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(75),
+  },
+  {
+    /* [411] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(29),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(75),
+  },
+  {
+    /* [412] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(28),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(76),
+  },
+  {
+    /* [413] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(28),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(76),
+  },
+  {
+    /* [414] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(29),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(85),
+  },
+  {
+    /* [415] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(29),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(85),
+  },
+  {
+    /* [416] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(90),
+  },
+  {
+    /* [417] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(8),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(90),
+  },
+  {
+    /* [418] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(91),
+  },
+  {
+    /* [419] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(27),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(8),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(91),
+  },
+  {
+    /* [420] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(92),
+  },
+  {
+    /* [421] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(8),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(92),
+  },
+  {
+    /* [422] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(93),
+  },
+  {
+    /* [423] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(8),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(93),
+  },
+  {
+    /* [424] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(94),
+  },
+  {
+    /* [425] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(8),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(94),
+  },
+  {
+    /* [426] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(95),
+  },
+  {
+    /* [427] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(8),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(95),
+  },
+  {
+    /* [428] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(29),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(16),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(96),
+  },
+  {
+    /* [429] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(29),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(351),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(96),
+  },
+  {
+    /* [430] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(29),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(16),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(97),
+  },
+  {
+    /* [431] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(29),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(351),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(97),
+  },
+  {
+    /* [432] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(25),
+    /* template_numbers */ TemplateNumberIndex(7),
+    /* parameters */ ParameterIndex(368),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [433] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(213),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(10),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(17),
+  },
+  {
+    /* [434] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(369),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(19),
+  },
+  {
+    /* [435] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(21),
+  },
+  {
+    /* [436] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(17),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(53),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [437] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(17),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [438] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(221),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(25),
+  },
+  {
+    /* [439] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(42),
+  },
+  {
+    /* [440] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(372),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(43),
+  },
+  {
+    /* [441] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(372),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(44),
+  },
+  {
+    /* [442] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(372),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(45),
+  },
+  {
+    /* [443] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(373),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(46),
+  },
+  {
+    /* [444] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(373),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(35),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(47),
+  },
+  {
+    /* [445] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(51),
+  },
+  {
+    /* [446] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(222),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(52),
+  },
+  {
+    /* [447] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 0,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(/* invalid */),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [448] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 2,
+    /* template_types */ TemplateTypeIndex(10),
+    /* template_numbers */ TemplateNumberIndex(3),
+    /* parameters */ ParameterIndex(353),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(3),
+    /* const_eval_fn */ ConstEvalFunctionIndex(66),
+  },
+  {
+    /* [449] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(17),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(68),
+  },
+  {
+    /* [450] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(17),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(69),
+  },
+  {
+    /* [451] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(17),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(26),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(70),
+  },
+  {
+    /* [452] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(17),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(71),
+  },
+  {
+    /* [453] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(17),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(72),
+  },
+  {
+    /* [454] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(25),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(374),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [455] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(8),
+    /* parameters */ ParameterIndex(0),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [456] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(8),
+    /* parameters */ ParameterIndex(0),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(/* invalid */),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [457] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(8),
+    /* parameters */ ParameterIndex(0),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [458] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 3,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 1,
+    /* template_types */ TemplateTypeIndex(26),
+    /* template_numbers */ TemplateNumberIndex(8),
+    /* parameters */ ParameterIndex(0),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(80),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [459] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 0,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(/* invalid */),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(74),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [460] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(0),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(348),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [461] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(25),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(73),
+  },
+  {
+    /* [462] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(226),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(88),
+  },
+  {
+    /* [463] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 2,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(226),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(89),
+  },
+  {
+    /* [464] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* num_parameters */ 1,
+    /* num_template_types */ 1,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(35),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(213),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(158),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+};
+
+static_assert(OverloadIndex::CanIndex(kOverloads),
+              "OverloadIndex is not large enough to index kOverloads");
+
+constexpr IntrinsicInfo kBuiltins[] = {
+  {
+    /* [0] */
+    /* fn abs<T : fia_fiu32_f16>(T) -> T */
+    /* fn abs<N : num, T : fia_fiu32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(298),
+  },
+  {
+    /* [1] */
+    /* fn acos<T : fa_f32_f16>(@test_value(0.96891242171) T) -> T */
+    /* fn acos<N : num, T : fa_f32_f16>(@test_value(0.96891242171) vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(300),
+  },
+  {
+    /* [2] */
+    /* fn acosh<T : fa_f32_f16>(@test_value(1.5430806348) T) -> T */
+    /* fn acosh<N : num, T : fa_f32_f16>(@test_value(1.5430806348) vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(302),
+  },
+  {
+    /* [3] */
+    /* fn all(bool) -> bool */
+    /* fn all<N : num>(vec<N, bool>) -> bool */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(304),
+  },
+  {
+    /* [4] */
+    /* fn any(bool) -> bool */
+    /* fn any<N : num>(vec<N, bool>) -> bool */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(306),
+  },
+  {
+    /* [5] */
+    /* fn arrayLength<T, A : access>(ptr<storage, array<T>, A>) -> u32 */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(432),
+  },
+  {
+    /* [6] */
+    /* fn asin<T : fa_f32_f16>(@test_value(0.479425538604) T) -> T */
+    /* fn asin<N : num, T : fa_f32_f16>(@test_value(0.479425538604) vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(308),
+  },
+  {
+    /* [7] */
+    /* fn asinh<T : fa_f32_f16>(T) -> T */
+    /* fn asinh<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(310),
+  },
+  {
+    /* [8] */
+    /* fn atan<T : fa_f32_f16>(T) -> T */
+    /* fn atan<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(312),
+  },
+  {
+    /* [9] */
+    /* fn atan2<T : fa_f32_f16>(T, T) -> T */
+    /* fn atan2<T : fa_f32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(314),
+  },
+  {
+    /* [10] */
+    /* fn atanh<T : fa_f32_f16>(@test_value(0.5) T) -> T */
+    /* fn atanh<N : num, T : fa_f32_f16>(@test_value(0.5) vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(316),
+  },
+  {
+    /* [11] */
+    /* fn ceil<T : fa_f32_f16>(@test_value(1.5) T) -> T */
+    /* fn ceil<N : num, T : fa_f32_f16>(@test_value(1.5) vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(318),
+  },
+  {
+    /* [12] */
+    /* fn clamp<T : fia_fiu32_f16>(T, T, T) -> T */
+    /* fn clamp<T : fia_fiu32_f16, N : num>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(320),
+  },
+  {
+    /* [13] */
+    /* fn cos<T : fa_f32_f16>(@test_value(0) T) -> T */
+    /* fn cos<N : num, T : fa_f32_f16>(@test_value(0) vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(322),
+  },
+  {
+    /* [14] */
+    /* fn cosh<T : fa_f32_f16>(@test_value(0) T) -> T */
+    /* fn cosh<N : num, T : fa_f32_f16>(@test_value(0) vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(324),
+  },
+  {
+    /* [15] */
+    /* fn countLeadingZeros<T : iu32>(T) -> T */
+    /* fn countLeadingZeros<N : num, T : iu32>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(326),
+  },
+  {
+    /* [16] */
+    /* fn countOneBits<T : iu32>(T) -> T */
+    /* fn countOneBits<N : num, T : iu32>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(328),
+  },
+  {
+    /* [17] */
+    /* fn countTrailingZeros<T : iu32>(T) -> T */
+    /* fn countTrailingZeros<N : num, T : iu32>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(330),
+  },
+  {
+    /* [18] */
+    /* fn cross<T : fa_f32_f16>(vec3<T>, vec3<T>) -> vec3<T> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(433),
+  },
+  {
+    /* [19] */
+    /* fn degrees<T : fa_f32_f16>(T) -> T */
+    /* fn degrees<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(332),
+  },
+  {
+    /* [20] */
+    /* fn determinant<N : num, T : fa_f32_f16>(mat<N, N, T>) -> T */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(434),
+  },
+  {
+    /* [21] */
+    /* fn distance<T : fa_f32_f16>(T, T) -> T */
+    /* fn distance<N : num, T : fa_f32_f16>(vec<N, T>, vec<N, T>) -> T */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(334),
+  },
+  {
+    /* [22] */
+    /* fn dot<N : num, T : fia_fiu32_f16>(vec<N, T>, vec<N, T>) -> T */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(435),
+  },
+  {
+    /* [23] */
+    /* fn dot4I8Packed(u32, u32) -> i32 */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(436),
+  },
+  {
+    /* [24] */
+    /* fn dot4U8Packed(u32, u32) -> u32 */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(437),
+  },
+  {
+    /* [25] */
+    /* fn dpdx(f32) -> f32 */
+    /* fn dpdx<N : num>(vec<N, f32>) -> vec<N, f32> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(336),
+  },
+  {
+    /* [26] */
+    /* fn dpdxCoarse(f32) -> f32 */
+    /* fn dpdxCoarse<N : num>(vec<N, f32>) -> vec<N, f32> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(336),
+  },
+  {
+    /* [27] */
+    /* fn dpdxFine(f32) -> f32 */
+    /* fn dpdxFine<N : num>(vec<N, f32>) -> vec<N, f32> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(336),
+  },
+  {
+    /* [28] */
+    /* fn dpdy(f32) -> f32 */
+    /* fn dpdy<N : num>(vec<N, f32>) -> vec<N, f32> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(336),
+  },
+  {
+    /* [29] */
+    /* fn dpdyCoarse(f32) -> f32 */
+    /* fn dpdyCoarse<N : num>(vec<N, f32>) -> vec<N, f32> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(336),
+  },
+  {
+    /* [30] */
+    /* fn dpdyFine(f32) -> f32 */
+    /* fn dpdyFine<N : num>(vec<N, f32>) -> vec<N, f32> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(336),
+  },
+  {
+    /* [31] */
+    /* fn exp<T : fa_f32_f16>(T) -> T */
+    /* fn exp<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(338),
+  },
+  {
+    /* [32] */
+    /* fn exp2<T : fa_f32_f16>(T) -> T */
+    /* fn exp2<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(340),
+  },
+  {
+    /* [33] */
+    /* fn extractBits<T : iu32>(T, u32, u32) -> T */
+    /* fn extractBits<N : num, T : iu32>(vec<N, T>, u32, u32) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(342),
+  },
+  {
+    /* [34] */
+    /* fn faceForward<N : num, T : fa_f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(438),
+  },
+  {
+    /* [35] */
+    /* fn firstLeadingBit<T : iu32>(T) -> T */
+    /* fn firstLeadingBit<N : num, T : iu32>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(344),
+  },
+  {
+    /* [36] */
+    /* fn firstTrailingBit<T : iu32>(T) -> T */
+    /* fn firstTrailingBit<N : num, T : iu32>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(346),
+  },
+  {
+    /* [37] */
+    /* fn floor<T : fa_f32_f16>(@test_value(1.5) T) -> T */
+    /* fn floor<N : num, T : fa_f32_f16>(@test_value(1.5) vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(348),
+  },
+  {
+    /* [38] */
+    /* fn fma<T : fa_f32_f16>(T, T, T) -> T */
+    /* fn fma<N : num, T : fa_f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(350),
+  },
+  {
+    /* [39] */
+    /* fn fract<T : fa_f32_f16>(@test_value(1.25) T) -> T */
+    /* fn fract<N : num, T : fa_f32_f16>(@test_value(1.25) vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(352),
+  },
+  {
+    /* [40] */
+    /* fn frexp<T : fa_f32_f16>(T) -> __frexp_result<T> */
+    /* fn frexp<N : num, T : fa_f32_f16>(vec<N, T>) -> __frexp_result_vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(354),
+  },
+  {
+    /* [41] */
+    /* fn fwidth(f32) -> f32 */
+    /* fn fwidth<N : num>(vec<N, f32>) -> vec<N, f32> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(336),
+  },
+  {
+    /* [42] */
+    /* fn fwidthCoarse(f32) -> f32 */
+    /* fn fwidthCoarse<N : num>(vec<N, f32>) -> vec<N, f32> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(336),
+  },
+  {
+    /* [43] */
+    /* fn fwidthFine(f32) -> f32 */
+    /* fn fwidthFine<N : num>(vec<N, f32>) -> vec<N, f32> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(336),
+  },
+  {
+    /* [44] */
+    /* fn insertBits<T : iu32>(T, T, u32, u32) -> T */
+    /* fn insertBits<N : num, T : iu32>(vec<N, T>, vec<N, T>, u32, u32) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(356),
+  },
+  {
+    /* [45] */
+    /* fn inverseSqrt<T : fa_f32_f16>(T) -> T */
+    /* fn inverseSqrt<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(358),
+  },
+  {
+    /* [46] */
+    /* fn ldexp<T : fa_f32_f16, U : ia_i32>(T, U) -> T */
+    /* fn ldexp<N : num, T : fa_f32_f16, U : ia_i32>(vec<N, T>, vec<N, U>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(360),
+  },
+  {
+    /* [47] */
+    /* fn length<T : fa_f32_f16>(@test_value(0) T) -> T */
+    /* fn length<N : num, T : fa_f32_f16>(@test_value(0) vec<N, T>) -> T */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(362),
+  },
+  {
+    /* [48] */
+    /* fn log<T : fa_f32_f16>(T) -> T */
+    /* fn log<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(364),
+  },
+  {
+    /* [49] */
+    /* fn log2<T : fa_f32_f16>(T) -> T */
+    /* fn log2<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(366),
+  },
+  {
+    /* [50] */
+    /* fn max<T : fia_fiu32_f16>(T, T) -> T */
+    /* fn max<N : num, T : fia_fiu32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(368),
+  },
+  {
+    /* [51] */
+    /* fn min<T : fia_fiu32_f16>(T, T) -> T */
+    /* fn min<N : num, T : fia_fiu32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(370),
+  },
+  {
+    /* [52] */
+    /* fn mix<T : fa_f32_f16>(T, T, T) -> T */
+    /* fn mix<N : num, T : fa_f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* fn mix<N : num, T : fa_f32_f16>(vec<N, T>, vec<N, T>, T) -> vec<N, T> */
+    /* num overloads */ 3,
+    /* overloads */ OverloadIndex(277),
+  },
+  {
+    /* [53] */
+    /* fn modf<T : fa_f32_f16>(@test_value(-1.5) T) -> __modf_result<T> */
+    /* fn modf<N : num, T : fa_f32_f16>(@test_value(-1.5) vec<N, T>) -> __modf_result_vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(372),
+  },
+  {
+    /* [54] */
+    /* fn normalize<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(439),
+  },
+  {
+    /* [55] */
+    /* fn pack2x16float(vec2<f32>) -> u32 */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(440),
+  },
+  {
+    /* [56] */
+    /* fn pack2x16snorm(vec2<f32>) -> u32 */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(441),
+  },
+  {
+    /* [57] */
+    /* fn pack2x16unorm(vec2<f32>) -> u32 */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(442),
+  },
+  {
+    /* [58] */
+    /* fn pack4x8snorm(vec4<f32>) -> u32 */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(443),
+  },
+  {
+    /* [59] */
+    /* fn pack4x8unorm(vec4<f32>) -> u32 */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(444),
+  },
+  {
+    /* [60] */
+    /* fn pow<T : fa_f32_f16>(T, T) -> T */
+    /* fn pow<N : num, T : fa_f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(374),
+  },
+  {
+    /* [61] */
+    /* fn quantizeToF16(f32) -> f32 */
+    /* fn quantizeToF16<N : num>(vec<N, f32>) -> vec<N, f32> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(376),
+  },
+  {
+    /* [62] */
+    /* fn radians<T : fa_f32_f16>(T) -> T */
+    /* fn radians<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(378),
+  },
+  {
+    /* [63] */
+    /* fn reflect<N : num, T : fa_f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(445),
+  },
+  {
+    /* [64] */
+    /* fn refract<N : num, T : fa_f32_f16>(vec<N, T>, vec<N, T>, T) -> vec<N, T> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(446),
+  },
+  {
+    /* [65] */
+    /* fn reverseBits<T : iu32>(T) -> T */
+    /* fn reverseBits<N : num, T : iu32>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(380),
+  },
+  {
+    /* [66] */
+    /* fn round<T : fa_f32_f16>(@test_value(3.5) T) -> T */
+    /* fn round<N : num, T : fa_f32_f16>(@test_value(3.5) vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(382),
+  },
+  {
+    /* [67] */
+    /* fn saturate<T : fa_f32_f16>(@test_value(2) T) -> T */
+    /* fn saturate<T : fa_f32_f16, N : num>(@test_value(2) vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(384),
+  },
+  {
+    /* [68] */
+    /* fn select<T : scalar>(T, T, bool) -> T */
+    /* fn select<T : scalar, N : num>(vec<N, T>, vec<N, T>, bool) -> vec<N, T> */
+    /* fn select<N : num, T : scalar>(vec<N, T>, vec<N, T>, vec<N, bool>) -> vec<N, T> */
+    /* num overloads */ 3,
+    /* overloads */ OverloadIndex(280),
+  },
+  {
+    /* [69] */
+    /* fn sign<T : fia_fi32_f16>(T) -> T */
+    /* fn sign<N : num, T : fia_fi32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(386),
+  },
+  {
+    /* [70] */
+    /* fn sin<T : fa_f32_f16>(@test_value(1.57079632679) T) -> T */
+    /* fn sin<N : num, T : fa_f32_f16>(@test_value(1.57079632679) vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(388),
+  },
+  {
+    /* [71] */
+    /* fn sinh<T : fa_f32_f16>(T) -> T */
+    /* fn sinh<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(390),
+  },
+  {
+    /* [72] */
+    /* fn smoothstep<T : fa_f32_f16>(@test_value(2) T, @test_value(4) T, @test_value(3) T) -> T */
+    /* fn smoothstep<N : num, T : fa_f32_f16>(@test_value(2) vec<N, T>, @test_value(4) vec<N, T>, @test_value(3) vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(392),
+  },
+  {
+    /* [73] */
+    /* fn sqrt<T : fa_f32_f16>(T) -> T */
+    /* fn sqrt<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(394),
+  },
+  {
+    /* [74] */
+    /* fn step<T : fa_f32_f16>(T, T) -> T */
+    /* fn step<N : num, T : fa_f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(396),
+  },
+  {
+    /* [75] */
+    /* fn storageBarrier() */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(447),
+  },
+  {
+    /* [76] */
+    /* fn tan<T : fa_f32_f16>(T) -> T */
+    /* fn tan<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(398),
+  },
+  {
+    /* [77] */
+    /* fn tanh<T : fa_f32_f16>(T) -> T */
+    /* fn tanh<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(400),
+  },
+  {
+    /* [78] */
+    /* fn transpose<M : num, N : num, T : fa_f32_f16>(mat<M, N, T>) -> mat<N, M, T> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(448),
+  },
+  {
+    /* [79] */
+    /* fn trunc<T : fa_f32_f16>(@test_value(1.5) T) -> T */
+    /* fn trunc<N : num, T : fa_f32_f16>(@test_value(1.5) vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(402),
+  },
+  {
+    /* [80] */
+    /* fn unpack2x16float(u32) -> vec2<f32> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(449),
+  },
+  {
+    /* [81] */
+    /* fn unpack2x16snorm(u32) -> vec2<f32> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(450),
+  },
+  {
+    /* [82] */
+    /* fn unpack2x16unorm(u32) -> vec2<f32> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(451),
+  },
+  {
+    /* [83] */
+    /* fn unpack4x8snorm(u32) -> vec4<f32> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(452),
+  },
+  {
+    /* [84] */
+    /* fn unpack4x8unorm(u32) -> vec4<f32> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(453),
+  },
+  {
+    /* [85] */
+    /* fn workgroupBarrier() */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(447),
+  },
+  {
+    /* [86] */
+    /* fn workgroupUniformLoad<T>(ptr<workgroup, T, read_write>) -> T */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(454),
+  },
+  {
+    /* [87] */
+    /* fn textureBarrier() */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(447),
+  },
+  {
+    /* [88] */
+    /* fn textureDimensions<T : fiu32>(texture: texture_1d<T>) -> u32 */
+    /* fn textureDimensions<T : fiu32, L : iu32>(texture: texture_1d<T>, level: L) -> u32 */
+    /* fn textureDimensions<T : fiu32>(texture: texture_2d<T>) -> vec2<u32> */
+    /* fn textureDimensions<T : fiu32, L : iu32>(texture: texture_2d<T>, level: L) -> vec2<u32> */
+    /* fn textureDimensions<T : fiu32>(texture: texture_2d_array<T>) -> vec2<u32> */
+    /* fn textureDimensions<T : fiu32, L : iu32>(texture: texture_2d_array<T>, level: L) -> vec2<u32> */
+    /* fn textureDimensions<T : fiu32>(texture: texture_3d<T>) -> vec3<u32> */
+    /* fn textureDimensions<T : fiu32, L : iu32>(texture: texture_3d<T>, level: L) -> vec3<u32> */
+    /* fn textureDimensions<T : fiu32>(texture: texture_cube<T>) -> vec2<u32> */
+    /* fn textureDimensions<T : fiu32, L : iu32>(texture: texture_cube<T>, level: L) -> vec2<u32> */
+    /* fn textureDimensions<T : fiu32>(texture: texture_cube_array<T>) -> vec2<u32> */
+    /* fn textureDimensions<T : fiu32, L : iu32>(texture: texture_cube_array<T>, level: L) -> vec2<u32> */
+    /* fn textureDimensions<T : fiu32>(texture: texture_multisampled_2d<T>) -> vec2<u32> */
+    /* fn textureDimensions(texture: texture_depth_2d) -> vec2<u32> */
+    /* fn textureDimensions<L : iu32>(texture: texture_depth_2d, level: L) -> vec2<u32> */
+    /* fn textureDimensions(texture: texture_depth_2d_array) -> vec2<u32> */
+    /* fn textureDimensions<L : iu32>(texture: texture_depth_2d_array, level: L) -> vec2<u32> */
+    /* fn textureDimensions(texture: texture_depth_cube) -> vec2<u32> */
+    /* fn textureDimensions<L : iu32>(texture: texture_depth_cube, level: L) -> vec2<u32> */
+    /* fn textureDimensions(texture: texture_depth_cube_array) -> vec2<u32> */
+    /* fn textureDimensions<L : iu32>(texture: texture_depth_cube_array, level: L) -> vec2<u32> */
+    /* fn textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<u32> */
+    /* fn textureDimensions<F : texel_format, A : access>(texture: texture_storage_1d<F, A>) -> u32 */
+    /* fn textureDimensions<F : texel_format, A : access>(texture: texture_storage_2d<F, A>) -> vec2<u32> */
+    /* fn textureDimensions<F : texel_format, A : access>(texture: texture_storage_2d_array<F, A>) -> vec2<u32> */
+    /* fn textureDimensions<F : texel_format, A : access>(texture: texture_storage_3d<F, A>) -> vec3<u32> */
+    /* fn textureDimensions(texture: texture_external) -> vec2<u32> */
+    /* num overloads */ 27,
+    /* overloads */ OverloadIndex(0),
+  },
+  {
+    /* [89] */
+    /* fn textureGather<T : fiu32, C : iu32>(@const component: C, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>) -> vec4<T> */
+    /* fn textureGather<T : fiu32, C : iu32>(@const component: C, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<T> */
+    /* fn textureGather<T : fiu32, C : iu32, A : iu32>(@const component: C, texture: texture_2d_array<T>, sampler: sampler, coords: vec2<f32>, array_index: A) -> vec4<T> */
+    /* fn textureGather<T : fiu32, C : iu32, A : iu32>(@const component: C, texture: texture_2d_array<T>, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> vec4<T> */
+    /* fn textureGather<T : fiu32, C : iu32>(@const component: C, texture: texture_cube<T>, sampler: sampler, coords: vec3<f32>) -> vec4<T> */
+    /* fn textureGather<T : fiu32, C : iu32, A : iu32>(@const component: C, texture: texture_cube_array<T>, sampler: sampler, coords: vec3<f32>, array_index: A) -> vec4<T> */
+    /* fn textureGather(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>) -> vec4<f32> */
+    /* fn textureGather(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32> */
+    /* fn textureGather<A : iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A) -> vec4<f32> */
+    /* fn textureGather<A : iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> vec4<f32> */
+    /* fn textureGather(texture: texture_depth_cube, sampler: sampler, coords: vec3<f32>) -> vec4<f32> */
+    /* fn textureGather<A : iu32>(texture: texture_depth_cube_array, sampler: sampler, coords: vec3<f32>, array_index: A) -> vec4<f32> */
+    /* num overloads */ 12,
+    /* overloads */ OverloadIndex(93),
+  },
+  {
+    /* [90] */
+    /* fn textureGatherCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32) -> vec4<f32> */
+    /* fn textureGatherCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32, @const offset: vec2<i32>) -> vec4<f32> */
+    /* fn textureGatherCompare<A : iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32) -> vec4<f32> */
+    /* fn textureGatherCompare<A : iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32, @const offset: vec2<i32>) -> vec4<f32> */
+    /* fn textureGatherCompare(texture: texture_depth_cube, sampler: sampler_comparison, coords: vec3<f32>, depth_ref: f32) -> vec4<f32> */
+    /* fn textureGatherCompare<A : iu32>(texture: texture_depth_cube_array, sampler: sampler_comparison, coords: vec3<f32>, array_index: A, depth_ref: f32) -> vec4<f32> */
+    /* num overloads */ 6,
+    /* overloads */ OverloadIndex(174),
+  },
+  {
+    /* [91] */
+    /* fn textureNumLayers<T : fiu32>(texture: texture_2d_array<T>) -> u32 */
+    /* fn textureNumLayers<T : fiu32>(texture: texture_cube_array<T>) -> u32 */
+    /* fn textureNumLayers(texture: texture_depth_2d_array) -> u32 */
+    /* fn textureNumLayers(texture: texture_depth_cube_array) -> u32 */
+    /* fn textureNumLayers<F : texel_format, A : access>(texture: texture_storage_2d_array<F, A>) -> u32 */
+    /* num overloads */ 5,
+    /* overloads */ OverloadIndex(246),
+  },
+  {
+    /* [92] */
+    /* fn textureNumLevels<T : fiu32>(texture: texture_1d<T>) -> u32 */
+    /* fn textureNumLevels<T : fiu32>(texture: texture_2d<T>) -> u32 */
+    /* fn textureNumLevels<T : fiu32>(texture: texture_2d_array<T>) -> u32 */
+    /* fn textureNumLevels<T : fiu32>(texture: texture_3d<T>) -> u32 */
+    /* fn textureNumLevels<T : fiu32>(texture: texture_cube<T>) -> u32 */
+    /* fn textureNumLevels<T : fiu32>(texture: texture_cube_array<T>) -> u32 */
+    /* fn textureNumLevels(texture: texture_depth_2d) -> u32 */
+    /* fn textureNumLevels(texture: texture_depth_2d_array) -> u32 */
+    /* fn textureNumLevels(texture: texture_depth_cube) -> u32 */
+    /* fn textureNumLevels(texture: texture_depth_cube_array) -> u32 */
+    /* num overloads */ 10,
+    /* overloads */ OverloadIndex(129),
+  },
+  {
+    /* [93] */
+    /* fn textureNumSamples<T : fiu32>(texture: texture_multisampled_2d<T>) -> u32 */
+    /* fn textureNumSamples(texture: texture_depth_multisampled_2d) -> u32 */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(404),
+  },
+  {
+    /* [94] */
+    /* fn textureSample(texture: texture_1d<f32>, sampler: sampler, coords: f32) -> vec4<f32> */
+    /* fn textureSample(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>) -> vec4<f32> */
+    /* fn textureSample(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32> */
+    /* fn textureSample<A : iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A) -> vec4<f32> */
+    /* fn textureSample<A : iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> vec4<f32> */
+    /* fn textureSample(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>) -> vec4<f32> */
+    /* fn textureSample(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, @const offset: vec3<i32>) -> vec4<f32> */
+    /* fn textureSample(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>) -> vec4<f32> */
+    /* fn textureSample<A : iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A) -> vec4<f32> */
+    /* fn textureSample(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>) -> f32 */
+    /* fn textureSample(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> f32 */
+    /* fn textureSample<A : iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A) -> f32 */
+    /* fn textureSample<A : iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> f32 */
+    /* fn textureSample(texture: texture_depth_cube, sampler: sampler, coords: vec3<f32>) -> f32 */
+    /* fn textureSample<A : iu32>(texture: texture_depth_cube_array, sampler: sampler, coords: vec3<f32>, array_index: A) -> f32 */
+    /* num overloads */ 15,
+    /* overloads */ OverloadIndex(64),
+  },
+  {
+    /* [95] */
+    /* fn textureSampleBias(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, bias: f32) -> vec4<f32> */
+    /* fn textureSampleBias(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, bias: f32, @const offset: vec2<i32>) -> vec4<f32> */
+    /* fn textureSampleBias<A : iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, bias: f32) -> vec4<f32> */
+    /* fn textureSampleBias<A : iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, bias: f32, @const offset: vec2<i32>) -> vec4<f32> */
+    /* fn textureSampleBias(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, bias: f32) -> vec4<f32> */
+    /* fn textureSampleBias(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, bias: f32, @const offset: vec3<i32>) -> vec4<f32> */
+    /* fn textureSampleBias(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>, bias: f32) -> vec4<f32> */
+    /* fn textureSampleBias<A : iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A, bias: f32) -> vec4<f32> */
+    /* num overloads */ 8,
+    /* overloads */ OverloadIndex(158),
+  },
+  {
+    /* [96] */
+    /* fn textureSampleCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32) -> f32 */
+    /* fn textureSampleCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32, @const offset: vec2<i32>) -> f32 */
+    /* fn textureSampleCompare<A : iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32) -> f32 */
+    /* fn textureSampleCompare<A : iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32, @const offset: vec2<i32>) -> f32 */
+    /* fn textureSampleCompare(texture: texture_depth_cube, sampler: sampler_comparison, coords: vec3<f32>, depth_ref: f32) -> f32 */
+    /* fn textureSampleCompare<A : iu32>(texture: texture_depth_cube_array, sampler: sampler_comparison, coords: vec3<f32>, array_index: A, depth_ref: f32) -> f32 */
+    /* num overloads */ 6,
+    /* overloads */ OverloadIndex(180),
+  },
+  {
+    /* [97] */
+    /* fn textureSampleCompareLevel(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32) -> f32 */
+    /* fn textureSampleCompareLevel(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32, @const offset: vec2<i32>) -> f32 */
+    /* fn textureSampleCompareLevel<A : iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32) -> f32 */
+    /* fn textureSampleCompareLevel<A : iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32, @const offset: vec2<i32>) -> f32 */
+    /* fn textureSampleCompareLevel(texture: texture_depth_cube, sampler: sampler_comparison, coords: vec3<f32>, depth_ref: f32) -> f32 */
+    /* fn textureSampleCompareLevel<A : iu32>(texture: texture_depth_cube_array, sampler: sampler_comparison, coords: vec3<f32>, array_index: A, depth_ref: f32) -> f32 */
+    /* num overloads */ 6,
+    /* overloads */ OverloadIndex(186),
+  },
+  {
+    /* [98] */
+    /* fn textureSampleGrad(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, ddx: vec2<f32>, ddy: vec2<f32>) -> vec4<f32> */
+    /* fn textureSampleGrad(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, ddx: vec2<f32>, ddy: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32> */
+    /* fn textureSampleGrad<A : iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, ddx: vec2<f32>, ddy: vec2<f32>) -> vec4<f32> */
+    /* fn textureSampleGrad<A : iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, ddx: vec2<f32>, ddy: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32> */
+    /* fn textureSampleGrad(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, ddx: vec3<f32>, ddy: vec3<f32>) -> vec4<f32> */
+    /* fn textureSampleGrad(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, ddx: vec3<f32>, ddy: vec3<f32>, @const offset: vec3<i32>) -> vec4<f32> */
+    /* fn textureSampleGrad(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>, ddx: vec3<f32>, ddy: vec3<f32>) -> vec4<f32> */
+    /* fn textureSampleGrad<A : iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A, ddx: vec3<f32>, ddy: vec3<f32>) -> vec4<f32> */
+    /* num overloads */ 8,
+    /* overloads */ OverloadIndex(166),
+  },
+  {
+    /* [99] */
+    /* fn textureSampleLevel(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, level: f32) -> vec4<f32> */
+    /* fn textureSampleLevel(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, level: f32, @const offset: vec2<i32>) -> vec4<f32> */
+    /* fn textureSampleLevel<A : iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, level: f32) -> vec4<f32> */
+    /* fn textureSampleLevel<A : iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, level: f32, @const offset: vec2<i32>) -> vec4<f32> */
+    /* fn textureSampleLevel(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, level: f32) -> vec4<f32> */
+    /* fn textureSampleLevel(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, level: f32, @const offset: vec3<i32>) -> vec4<f32> */
+    /* fn textureSampleLevel(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>, level: f32) -> vec4<f32> */
+    /* fn textureSampleLevel<A : iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A, level: f32) -> vec4<f32> */
+    /* fn textureSampleLevel<L : iu32>(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, level: L) -> f32 */
+    /* fn textureSampleLevel<L : iu32>(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, level: L, @const offset: vec2<i32>) -> f32 */
+    /* fn textureSampleLevel<A : iu32, L : iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, level: L) -> f32 */
+    /* fn textureSampleLevel<A : iu32, L : iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, level: L, @const offset: vec2<i32>) -> f32 */
+    /* fn textureSampleLevel<L : iu32>(texture: texture_depth_cube, sampler: sampler, coords: vec3<f32>, level: L) -> f32 */
+    /* fn textureSampleLevel<A : iu32, L : iu32>(texture: texture_depth_cube_array, sampler: sampler, coords: vec3<f32>, array_index: A, level: L) -> f32 */
+    /* num overloads */ 14,
+    /* overloads */ OverloadIndex(79),
+  },
+  {
+    /* [100] */
+    /* fn textureSampleBaseClampToEdge(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>) -> vec4<f32> */
+    /* fn textureSampleBaseClampToEdge(texture: texture_external, sampler: sampler, coords: vec2<f32>) -> vec4<f32> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(406),
+  },
+  {
+    /* [101] */
+    /* fn textureStore<C : iu32>(texture: texture_storage_1d<f32_texel_format, writable>, coords: C, value: vec4<f32>) */
+    /* fn textureStore<C : iu32>(texture: texture_storage_2d<f32_texel_format, writable>, coords: vec2<C>, value: vec4<f32>) */
+    /* fn textureStore<C : iu32, A : iu32>(texture: texture_storage_2d_array<f32_texel_format, writable>, coords: vec2<C>, array_index: A, value: vec4<f32>) */
+    /* fn textureStore<C : iu32>(texture: texture_storage_3d<f32_texel_format, writable>, coords: vec3<C>, value: vec4<f32>) */
+    /* fn textureStore<C : iu32>(texture: texture_storage_1d<i32_texel_format, writable>, coords: C, value: vec4<i32>) */
+    /* fn textureStore<C : iu32>(texture: texture_storage_2d<i32_texel_format, writable>, coords: vec2<C>, value: vec4<i32>) */
+    /* fn textureStore<C : iu32, A : iu32>(texture: texture_storage_2d_array<i32_texel_format, writable>, coords: vec2<C>, array_index: A, value: vec4<i32>) */
+    /* fn textureStore<C : iu32>(texture: texture_storage_3d<i32_texel_format, writable>, coords: vec3<C>, value: vec4<i32>) */
+    /* fn textureStore<C : iu32>(texture: texture_storage_1d<u32_texel_format, writable>, coords: C, value: vec4<u32>) */
+    /* fn textureStore<C : iu32>(texture: texture_storage_2d<u32_texel_format, writable>, coords: vec2<C>, value: vec4<u32>) */
+    /* fn textureStore<C : iu32, A : iu32>(texture: texture_storage_2d_array<u32_texel_format, writable>, coords: vec2<C>, array_index: A, value: vec4<u32>) */
+    /* fn textureStore<C : iu32>(texture: texture_storage_3d<u32_texel_format, writable>, coords: vec3<C>, value: vec4<u32>) */
+    /* num overloads */ 12,
+    /* overloads */ OverloadIndex(105),
+  },
+  {
+    /* [102] */
+    /* fn textureLoad<T : fiu32, C : iu32, L : iu32>(texture: texture_1d<T>, coords: C, level: L) -> vec4<T> */
+    /* fn textureLoad<T : fiu32, C : iu32, L : iu32>(texture: texture_2d<T>, coords: vec2<C>, level: L) -> vec4<T> */
+    /* fn textureLoad<T : fiu32, C : iu32, A : iu32, L : iu32>(texture: texture_2d_array<T>, coords: vec2<C>, array_index: A, level: L) -> vec4<T> */
+    /* fn textureLoad<T : fiu32, C : iu32, L : iu32>(texture: texture_3d<T>, coords: vec3<C>, level: L) -> vec4<T> */
+    /* fn textureLoad<T : fiu32, C : iu32, S : iu32>(texture: texture_multisampled_2d<T>, coords: vec2<C>, sample_index: S) -> vec4<T> */
+    /* fn textureLoad<C : iu32, L : iu32>(texture: texture_depth_2d, coords: vec2<C>, level: L) -> f32 */
+    /* fn textureLoad<C : iu32, A : iu32, L : iu32>(texture: texture_depth_2d_array, coords: vec2<C>, array_index: A, level: L) -> f32 */
+    /* fn textureLoad<C : iu32, S : iu32>(texture: texture_depth_multisampled_2d, coords: vec2<C>, sample_index: S) -> f32 */
+    /* fn textureLoad<C : iu32>(texture: texture_external, coords: vec2<C>) -> vec4<f32> */
+    /* fn textureLoad<C : iu32>(texture: texture_storage_1d<f32_texel_format, readable>, coords: C) -> vec4<f32> */
+    /* fn textureLoad<C : iu32>(texture: texture_storage_1d<i32_texel_format, readable>, coords: C) -> vec4<i32> */
+    /* fn textureLoad<C : iu32>(texture: texture_storage_1d<u32_texel_format, readable>, coords: C) -> vec4<u32> */
+    /* fn textureLoad<C : iu32>(texture: texture_storage_2d<f32_texel_format, readable>, coords: vec2<C>) -> vec4<f32> */
+    /* fn textureLoad<C : iu32>(texture: texture_storage_2d<i32_texel_format, readable>, coords: vec2<C>) -> vec4<i32> */
+    /* fn textureLoad<C : iu32>(texture: texture_storage_2d<u32_texel_format, readable>, coords: vec2<C>) -> vec4<u32> */
+    /* fn textureLoad<C : iu32, A : iu32>(texture: texture_storage_2d_array<f32_texel_format, readable>, coords: vec2<C>, array_index: A) -> vec4<f32> */
+    /* fn textureLoad<C : iu32, A : iu32>(texture: texture_storage_2d_array<i32_texel_format, readable>, coords: vec2<C>, array_index: A) -> vec4<i32> */
+    /* fn textureLoad<C : iu32, A : iu32>(texture: texture_storage_2d_array<u32_texel_format, readable>, coords: vec2<C>, array_index: A) -> vec4<u32> */
+    /* fn textureLoad<C : iu32>(texture: texture_storage_3d<f32_texel_format, readable>, coords: vec3<C>) -> vec4<f32> */
+    /* fn textureLoad<C : iu32>(texture: texture_storage_3d<i32_texel_format, readable>, coords: vec3<C>) -> vec4<i32> */
+    /* fn textureLoad<C : iu32>(texture: texture_storage_3d<u32_texel_format, readable>, coords: vec3<C>) -> vec4<u32> */
+    /* num overloads */ 21,
+    /* overloads */ OverloadIndex(27),
+  },
+  {
+    /* [103] */
+    /* fn atomicLoad<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>) -> T */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(455),
+  },
+  {
+    /* [104] */
+    /* fn atomicStore<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(456),
+  },
+  {
+    /* [105] */
+    /* fn atomicAdd<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(457),
+  },
+  {
+    /* [106] */
+    /* fn atomicSub<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(457),
+  },
+  {
+    /* [107] */
+    /* fn atomicMax<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(457),
+  },
+  {
+    /* [108] */
+    /* fn atomicMin<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(457),
+  },
+  {
+    /* [109] */
+    /* fn atomicAnd<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(457),
+  },
+  {
+    /* [110] */
+    /* fn atomicOr<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(457),
+  },
+  {
+    /* [111] */
+    /* fn atomicXor<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(457),
+  },
+  {
+    /* [112] */
+    /* fn atomicExchange<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(457),
+  },
+  {
+    /* [113] */
+    /* fn atomicCompareExchangeWeak<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T, T) -> __atomic_compare_exchange_result<T> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(458),
+  },
+  {
+    /* [114] */
+    /* fn subgroupBallot() -> vec4<u32> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(459),
+  },
+  {
+    /* [115] */
+    /* fn subgroupBroadcast<T : fiu32>(value: T, @const sourceLaneIndex: u32) -> T */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(460),
+  },
+  {
+    /* [116] */
+    /* fn _tint_materialize<T>(T) -> T */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(461),
+  },
+};
+
+constexpr IntrinsicInfo kUnaryOperators[] = {
+  {
+    /* [0] */
+    /* op !(bool) -> bool */
+    /* op !<N : num>(vec<N, bool>) -> vec<N, bool> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(408),
+  },
+  {
+    /* [1] */
+    /* op ~<T : ia_iu32>(T) -> T */
+    /* op ~<T : ia_iu32, N : num>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(410),
+  },
+  {
+    /* [2] */
+    /* op -<T : fia_fi32_f16>(T) -> T */
+    /* op -<T : fia_fi32_f16, N : num>(vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(412),
+  },
+};
+constexpr uint8_t kUnaryOperatorNot = 0;
+constexpr uint8_t kUnaryOperatorComplement = 1;
+constexpr uint8_t kUnaryOperatorMinus = 2;
+
+constexpr IntrinsicInfo kBinaryOperators[] = {
+  {
+    /* [0] */
+    /* op +<T : fia_fiu32_f16>(T, T) -> T */
+    /* op +<T : fia_fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* op +<T : fia_fiu32_f16, N : num>(vec<N, T>, T) -> vec<N, T> */
+    /* op +<T : fia_fiu32_f16, N : num>(T, vec<N, T>) -> vec<N, T> */
+    /* op +<T : fa_f32_f16, N : num, M : num>(mat<N, M, T>, mat<N, M, T>) -> mat<N, M, T> */
+    /* num overloads */ 5,
+    /* overloads */ OverloadIndex(251),
+  },
+  {
+    /* [1] */
+    /* op -<T : fia_fiu32_f16>(T, T) -> T */
+    /* op -<T : fia_fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* op -<T : fia_fiu32_f16, N : num>(vec<N, T>, T) -> vec<N, T> */
+    /* op -<T : fia_fiu32_f16, N : num>(T, vec<N, T>) -> vec<N, T> */
+    /* op -<T : fa_f32_f16, N : num, M : num>(mat<N, M, T>, mat<N, M, T>) -> mat<N, M, T> */
+    /* num overloads */ 5,
+    /* overloads */ OverloadIndex(256),
+  },
+  {
+    /* [2] */
+    /* op *<T : fia_fiu32_f16>(T, T) -> T */
+    /* op *<T : fia_fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* op *<T : fia_fiu32_f16, N : num>(vec<N, T>, T) -> vec<N, T> */
+    /* op *<T : fia_fiu32_f16, N : num>(T, vec<N, T>) -> vec<N, T> */
+    /* op *<T : fa_f32_f16, N : num, M : num>(T, mat<N, M, T>) -> mat<N, M, T> */
+    /* op *<T : fa_f32_f16, N : num, M : num>(mat<N, M, T>, T) -> mat<N, M, T> */
+    /* op *<T : fa_f32_f16, C : num, R : num>(mat<C, R, T>, vec<C, T>) -> vec<R, T> */
+    /* op *<T : fa_f32_f16, C : num, R : num>(vec<R, T>, mat<C, R, T>) -> vec<C, T> */
+    /* op *<T : fa_f32_f16, K : num, C : num, R : num>(mat<K, R, T>, mat<C, K, T>) -> mat<C, R, T> */
+    /* num overloads */ 9,
+    /* overloads */ OverloadIndex(149),
+  },
+  {
+    /* [3] */
+    /* op /<T : fia_fiu32_f16>(T, T) -> T */
+    /* op /<T : fia_fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* op /<T : fia_fiu32_f16, N : num>(vec<N, T>, T) -> vec<N, T> */
+    /* op /<T : fia_fiu32_f16, N : num>(T, vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 4,
+    /* overloads */ OverloadIndex(261),
+  },
+  {
+    /* [4] */
+    /* op %<T : fia_fiu32_f16>(T, T) -> T */
+    /* op %<T : fia_fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* op %<T : fia_fiu32_f16, N : num>(vec<N, T>, T) -> vec<N, T> */
+    /* op %<T : fia_fiu32_f16, N : num>(T, vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 4,
+    /* overloads */ OverloadIndex(265),
+  },
+  {
+    /* [5] */
+    /* op ^<T : ia_iu32>(T, T) -> T */
+    /* op ^<T : ia_iu32, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(414),
+  },
+  {
+    /* [6] */
+    /* op &(bool, bool) -> bool */
+    /* op &<N : num>(vec<N, bool>, vec<N, bool>) -> vec<N, bool> */
+    /* op &<T : ia_iu32>(T, T) -> T */
+    /* op &<T : ia_iu32, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 4,
+    /* overloads */ OverloadIndex(269),
+  },
+  {
+    /* [7] */
+    /* op |(bool, bool) -> bool */
+    /* op |<N : num>(vec<N, bool>, vec<N, bool>) -> vec<N, bool> */
+    /* op |<T : ia_iu32>(T, T) -> T */
+    /* op |<T : ia_iu32, N : num>(vec<N, T>, vec<N, T>) -> vec<N, T> */
+    /* num overloads */ 4,
+    /* overloads */ OverloadIndex(273),
+  },
+  {
+    /* [8] */
+    /* op &&(bool, bool) -> bool */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(462),
+  },
+  {
+    /* [9] */
+    /* op ||(bool, bool) -> bool */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(463),
+  },
+  {
+    /* [10] */
+    /* op ==<T : scalar>(T, T) -> bool */
+    /* op ==<T : scalar, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(416),
+  },
+  {
+    /* [11] */
+    /* op !=<T : scalar>(T, T) -> bool */
+    /* op !=<T : scalar, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(418),
+  },
+  {
+    /* [12] */
+    /* op <<T : fia_fiu32_f16>(T, T) -> bool */
+    /* op <<T : fia_fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(420),
+  },
+  {
+    /* [13] */
+    /* op ><T : fia_fiu32_f16>(T, T) -> bool */
+    /* op ><T : fia_fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(422),
+  },
+  {
+    /* [14] */
+    /* op <=<T : fia_fiu32_f16>(T, T) -> bool */
+    /* op <=<T : fia_fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(424),
+  },
+  {
+    /* [15] */
+    /* op >=<T : fia_fiu32_f16>(T, T) -> bool */
+    /* op >=<T : fia_fiu32_f16, N : num>(vec<N, T>, vec<N, T>) -> vec<N, bool> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(426),
+  },
+  {
+    /* [16] */
+    /* op <<<T : ia_iu32>(T, u32) -> T */
+    /* op <<<T : ia_iu32, N : num>(vec<N, T>, vec<N, u32>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(428),
+  },
+  {
+    /* [17] */
+    /* op >><T : ia_iu32>(T, u32) -> T */
+    /* op >><T : ia_iu32, N : num>(vec<N, T>, vec<N, u32>) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(430),
+  },
+};
+constexpr uint8_t kBinaryOperatorPlus = 0;
+constexpr uint8_t kBinaryOperatorMinus = 1;
+constexpr uint8_t kBinaryOperatorStar = 2;
+constexpr uint8_t kBinaryOperatorDivide = 3;
+constexpr uint8_t kBinaryOperatorModulo = 4;
+constexpr uint8_t kBinaryOperatorXor = 5;
+constexpr uint8_t kBinaryOperatorAnd = 6;
+constexpr uint8_t kBinaryOperatorOr = 7;
+constexpr uint8_t kBinaryOperatorLogicalAnd = 8;
+constexpr uint8_t kBinaryOperatorLogicalOr = 9;
+constexpr uint8_t kBinaryOperatorEqual = 10;
+constexpr uint8_t kBinaryOperatorNotEqual = 11;
+constexpr uint8_t kBinaryOperatorLessThan = 12;
+constexpr uint8_t kBinaryOperatorGreaterThan = 13;
+constexpr uint8_t kBinaryOperatorLessThanEqual = 14;
+constexpr uint8_t kBinaryOperatorGreaterThanEqual = 15;
+constexpr uint8_t kBinaryOperatorShiftLeft = 16;
+constexpr uint8_t kBinaryOperatorShiftRight = 17;
+
+constexpr IntrinsicInfo kConstructorsAndConverters[] = {
+  {
+    /* [0] */
+    /* ctor i32() -> i32 */
+    /* ctor i32(i32) -> i32 */
+    /* conv i32<T : scalar_no_i32>(T) -> i32 */
+    /* num overloads */ 3,
+    /* overloads */ OverloadIndex(283),
+  },
+  {
+    /* [1] */
+    /* ctor u32() -> u32 */
+    /* ctor u32(u32) -> u32 */
+    /* conv u32<T : scalar_no_u32>(T) -> u32 */
+    /* num overloads */ 3,
+    /* overloads */ OverloadIndex(286),
+  },
+  {
+    /* [2] */
+    /* ctor f32() -> f32 */
+    /* ctor f32(f32) -> f32 */
+    /* conv f32<T : scalar_no_f32>(T) -> f32 */
+    /* num overloads */ 3,
+    /* overloads */ OverloadIndex(289),
+  },
+  {
+    /* [3] */
+    /* ctor f16() -> f16 */
+    /* ctor f16(f16) -> f16 */
+    /* conv f16<T : scalar_no_f16>(T) -> f16 */
+    /* num overloads */ 3,
+    /* overloads */ OverloadIndex(292),
+  },
+  {
+    /* [4] */
+    /* ctor bool() -> bool */
+    /* ctor bool(bool) -> bool */
+    /* conv bool<T : scalar_no_bool>(T) -> bool */
+    /* num overloads */ 3,
+    /* overloads */ OverloadIndex(295),
+  },
+  {
+    /* [5] */
+    /* ctor vec2() -> vec2<ia> */
+    /* ctor vec2<T : concrete_scalar>() -> vec2<T> */
+    /* ctor vec2<T : scalar>(vec2<T>) -> vec2<T> */
+    /* ctor vec2<T : scalar>(T) -> vec2<T> */
+    /* ctor vec2<T : scalar>(x: T, y: T) -> vec2<T> */
+    /* conv vec2<T : f32, U : scalar_no_f32>(vec2<U>) -> vec2<f32> */
+    /* conv vec2<T : f16, U : scalar_no_f16>(vec2<U>) -> vec2<f16> */
+    /* conv vec2<T : i32, U : scalar_no_i32>(vec2<U>) -> vec2<i32> */
+    /* conv vec2<T : u32, U : scalar_no_u32>(vec2<U>) -> vec2<u32> */
+    /* conv vec2<T : bool, U : scalar_no_bool>(vec2<U>) -> vec2<bool> */
+    /* num overloads */ 10,
+    /* overloads */ OverloadIndex(139),
+  },
+  {
+    /* [6] */
+    /* ctor vec3() -> vec3<ia> */
+    /* ctor vec3<T : concrete_scalar>() -> vec3<T> */
+    /* ctor vec3<T : scalar>(vec3<T>) -> vec3<T> */
+    /* ctor vec3<T : scalar>(T) -> vec3<T> */
+    /* ctor vec3<T : scalar>(x: T, y: T, z: T) -> vec3<T> */
+    /* ctor vec3<T : scalar>(xy: vec2<T>, z: T) -> vec3<T> */
+    /* ctor vec3<T : scalar>(x: T, yz: vec2<T>) -> vec3<T> */
+    /* conv vec3<T : f32, U : scalar_no_f32>(vec3<U>) -> vec3<f32> */
+    /* conv vec3<T : f16, U : scalar_no_f16>(vec3<U>) -> vec3<f16> */
+    /* conv vec3<T : i32, U : scalar_no_i32>(vec3<U>) -> vec3<i32> */
+    /* conv vec3<T : u32, U : scalar_no_u32>(vec3<U>) -> vec3<u32> */
+    /* conv vec3<T : bool, U : scalar_no_bool>(vec3<U>) -> vec3<bool> */
+    /* num overloads */ 12,
+    /* overloads */ OverloadIndex(117),
+  },
+  {
+    /* [7] */
+    /* ctor vec4() -> vec4<ia> */
+    /* ctor vec4<T : concrete_scalar>() -> vec4<T> */
+    /* ctor vec4<T : scalar>(vec4<T>) -> vec4<T> */
+    /* ctor vec4<T : scalar>(T) -> vec4<T> */
+    /* ctor vec4<T : scalar>(x: T, y: T, z: T, w: T) -> vec4<T> */
+    /* ctor vec4<T : scalar>(xy: vec2<T>, z: T, w: T) -> vec4<T> */
+    /* ctor vec4<T : scalar>(x: T, yz: vec2<T>, w: T) -> vec4<T> */
+    /* ctor vec4<T : scalar>(x: T, y: T, zw: vec2<T>) -> vec4<T> */
+    /* ctor vec4<T : scalar>(xy: vec2<T>, zw: vec2<T>) -> vec4<T> */
+    /* ctor vec4<T : scalar>(xyz: vec3<T>, w: T) -> vec4<T> */
+    /* ctor vec4<T : scalar>(x: T, zyw: vec3<T>) -> vec4<T> */
+    /* conv vec4<T : f32, U : scalar_no_f32>(vec4<U>) -> vec4<f32> */
+    /* conv vec4<T : f16, U : scalar_no_f16>(vec4<U>) -> vec4<f16> */
+    /* conv vec4<T : i32, U : scalar_no_i32>(vec4<U>) -> vec4<i32> */
+    /* conv vec4<T : u32, U : scalar_no_u32>(vec4<U>) -> vec4<u32> */
+    /* conv vec4<T : bool, U : scalar_no_bool>(vec4<U>) -> vec4<bool> */
+    /* num overloads */ 16,
+    /* overloads */ OverloadIndex(48),
+  },
+  {
+    /* [8] */
+    /* ctor mat2x2<T : f32_f16>() -> mat2x2<T> */
+    /* ctor mat2x2<T : f32_f16>(mat2x2<T>) -> mat2x2<T> */
+    /* ctor mat2x2<T : fa_f32_f16>(T, T, T, T) -> mat2x2<T> */
+    /* ctor mat2x2<T : fa_f32_f16>(vec2<T>, vec2<T>) -> mat2x2<T> */
+    /* conv mat2x2<T : f16>(mat2x2<f32>) -> mat2x2<f16> */
+    /* conv mat2x2<T : f32>(mat2x2<f16>) -> mat2x2<f32> */
+    /* num overloads */ 6,
+    /* overloads */ OverloadIndex(192),
+  },
+  {
+    /* [9] */
+    /* ctor mat2x3<T : f32_f16>() -> mat2x3<T> */
+    /* ctor mat2x3<T : f32_f16>(mat2x3<T>) -> mat2x3<T> */
+    /* ctor mat2x3<T : fa_f32_f16>(T, T, T, T, T, T) -> mat2x3<T> */
+    /* ctor mat2x3<T : fa_f32_f16>(vec3<T>, vec3<T>) -> mat2x3<T> */
+    /* conv mat2x3<T : f16>(mat2x3<f32>) -> mat2x3<f16> */
+    /* conv mat2x3<T : f32>(mat2x3<f16>) -> mat2x3<f32> */
+    /* num overloads */ 6,
+    /* overloads */ OverloadIndex(198),
+  },
+  {
+    /* [10] */
+    /* ctor mat2x4<T : f32_f16>() -> mat2x4<T> */
+    /* ctor mat2x4<T : f32_f16>(mat2x4<T>) -> mat2x4<T> */
+    /* ctor mat2x4<T : fa_f32_f16>(T, T, T, T, T, T, T, T) -> mat2x4<T> */
+    /* ctor mat2x4<T : fa_f32_f16>(vec4<T>, vec4<T>) -> mat2x4<T> */
+    /* conv mat2x4<T : f16>(mat2x4<f32>) -> mat2x4<f16> */
+    /* conv mat2x4<T : f32>(mat2x4<f16>) -> mat2x4<f32> */
+    /* num overloads */ 6,
+    /* overloads */ OverloadIndex(204),
+  },
+  {
+    /* [11] */
+    /* ctor mat3x2<T : f32_f16>() -> mat3x2<T> */
+    /* ctor mat3x2<T : f32_f16>(mat3x2<T>) -> mat3x2<T> */
+    /* ctor mat3x2<T : fa_f32_f16>(T, T, T, T, T, T) -> mat3x2<T> */
+    /* ctor mat3x2<T : fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>) -> mat3x2<T> */
+    /* conv mat3x2<T : f16>(mat3x2<f32>) -> mat3x2<f16> */
+    /* conv mat3x2<T : f32>(mat3x2<f16>) -> mat3x2<f32> */
+    /* num overloads */ 6,
+    /* overloads */ OverloadIndex(210),
+  },
+  {
+    /* [12] */
+    /* ctor mat3x3<T : f32_f16>() -> mat3x3<T> */
+    /* ctor mat3x3<T : f32_f16>(mat3x3<T>) -> mat3x3<T> */
+    /* ctor mat3x3<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T) -> mat3x3<T> */
+    /* ctor mat3x3<T : fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>) -> mat3x3<T> */
+    /* conv mat3x3<T : f16>(mat3x3<f32>) -> mat3x3<f16> */
+    /* conv mat3x3<T : f32>(mat3x3<f16>) -> mat3x3<f32> */
+    /* num overloads */ 6,
+    /* overloads */ OverloadIndex(216),
+  },
+  {
+    /* [13] */
+    /* ctor mat3x4<T : f32_f16>() -> mat3x4<T> */
+    /* ctor mat3x4<T : f32_f16>(mat3x4<T>) -> mat3x4<T> */
+    /* ctor mat3x4<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T, T, T, T) -> mat3x4<T> */
+    /* ctor mat3x4<T : fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>) -> mat3x4<T> */
+    /* conv mat3x4<T : f16>(mat3x4<f32>) -> mat3x4<f16> */
+    /* conv mat3x4<T : f32>(mat3x4<f16>) -> mat3x4<f32> */
+    /* num overloads */ 6,
+    /* overloads */ OverloadIndex(222),
+  },
+  {
+    /* [14] */
+    /* ctor mat4x2<T : f32_f16>() -> mat4x2<T> */
+    /* ctor mat4x2<T : f32_f16>(mat4x2<T>) -> mat4x2<T> */
+    /* ctor mat4x2<T : fa_f32_f16>(T, T, T, T, T, T, T, T) -> mat4x2<T> */
+    /* ctor mat4x2<T : fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>, vec2<T>) -> mat4x2<T> */
+    /* conv mat4x2<T : f16>(mat4x2<f32>) -> mat4x2<f16> */
+    /* conv mat4x2<T : f32>(mat4x2<f16>) -> mat4x2<f32> */
+    /* num overloads */ 6,
+    /* overloads */ OverloadIndex(228),
+  },
+  {
+    /* [15] */
+    /* ctor mat4x3<T : f32_f16>() -> mat4x3<T> */
+    /* ctor mat4x3<T : f32_f16>(mat4x3<T>) -> mat4x3<T> */
+    /* ctor mat4x3<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T, T, T, T) -> mat4x3<T> */
+    /* ctor mat4x3<T : fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>, vec3<T>) -> mat4x3<T> */
+    /* conv mat4x3<T : f16>(mat4x3<f32>) -> mat4x3<f16> */
+    /* conv mat4x3<T : f32>(mat4x3<f16>) -> mat4x3<f32> */
+    /* num overloads */ 6,
+    /* overloads */ OverloadIndex(234),
+  },
+  {
+    /* [16] */
+    /* ctor mat4x4<T : f32_f16>() -> mat4x4<T> */
+    /* ctor mat4x4<T : f32_f16>(mat4x4<T>) -> mat4x4<T> */
+    /* ctor mat4x4<T : fa_f32_f16>(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) -> mat4x4<T> */
+    /* ctor mat4x4<T : fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>, vec4<T>) -> mat4x4<T> */
+    /* conv mat4x4<T : f16>(mat4x4<f32>) -> mat4x4<f16> */
+    /* conv mat4x4<T : f32>(mat4x4<f16>) -> mat4x4<f32> */
+    /* num overloads */ 6,
+    /* overloads */ OverloadIndex(240),
+  },
+  {
+    /* [17] */
+    /* conv packedVec3<T : concrete_scalar>(vec3<T>) -> packedVec3<T> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(464),
+  },
+};
+
+// clang-format on
+
+}  // anonymous namespace
+
+const core::intrinsic::TableData kData{
+    /* template_types */ kTemplateTypes,
+    /* template_numbers */ kTemplateNumbers,
+    /* type_matcher_indices */ kTypeMatcherIndices,
+    /* number_matcher_indices */ kNumberMatcherIndices,
+    /* type_matchers */ kTypeMatchers,
+    /* number_matchers */ kNumberMatchers,
+    /* parameters */ kParameters,
+    /* overloads */ kOverloads,
+    /* const_eval_functions */ kConstEvalFunctions,
+    /* ctor_conv */ kConstructorsAndConverters,
+    /* builtins */ kBuiltins,
+    /* binary '+' */ kBinaryOperators[kBinaryOperatorPlus],
+    /* binary '-' */ kBinaryOperators[kBinaryOperatorMinus],
+    /* binary '*' */ kBinaryOperators[kBinaryOperatorStar],
+    /* binary '/' */ kBinaryOperators[kBinaryOperatorDivide],
+    /* binary '%' */ kBinaryOperators[kBinaryOperatorModulo],
+    /* binary '^' */ kBinaryOperators[kBinaryOperatorXor],
+    /* binary '&' */ kBinaryOperators[kBinaryOperatorAnd],
+    /* binary '|' */ kBinaryOperators[kBinaryOperatorOr],
+    /* binary '&&' */ kBinaryOperators[kBinaryOperatorLogicalAnd],
+    /* binary '||' */ kBinaryOperators[kBinaryOperatorLogicalOr],
+    /* binary '==' */ kBinaryOperators[kBinaryOperatorEqual],
+    /* binary '!=' */ kBinaryOperators[kBinaryOperatorNotEqual],
+    /* binary '<' */ kBinaryOperators[kBinaryOperatorLessThan],
+    /* binary '>' */ kBinaryOperators[kBinaryOperatorGreaterThan],
+    /* binary '<=' */ kBinaryOperators[kBinaryOperatorLessThanEqual],
+    /* binary '>=' */ kBinaryOperators[kBinaryOperatorGreaterThanEqual],
+    /* binary '<<' */ kBinaryOperators[kBinaryOperatorShiftLeft],
+    /* binary '>>' */ kBinaryOperators[kBinaryOperatorShiftRight],
+    /* unary '!' */ kUnaryOperators[kUnaryOperatorNot],
+    /* unary '~' */ kUnaryOperators[kUnaryOperatorComplement],
+    /* unary '-' */ kUnaryOperators[kUnaryOperatorMinus],
+};
+
+}  // namespace tint::wgsl::intrinsic::data
diff --git a/src/tint/lang/wgsl/intrinsic/data/data.cc.tmpl b/src/tint/lang/wgsl/intrinsic/data/data.cc.tmpl
new file mode 100644
index 0000000..5692ef5
--- /dev/null
+++ b/src/tint/lang/wgsl/intrinsic/data/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/wgsl/wgsl.def" -}}
+
+#include <limits>
+#include <string>
+
+#include "src/tint/lang/core/intrinsic/data/type_matchers.h"
+#include "src/tint/lang/wgsl/intrinsic/data/data.h"
+#include "src/tint/utils/text/string_stream.h"
+
+namespace tint::wgsl::intrinsic::data {
+
+using namespace tint::core::intrinsic::data;  // NOLINT(build/namespaces)
+
+{{ Eval "Data"
+  "Intrinsics" $I
+  "Name"       "kData" -}}
+
+}  // namespace tint::wgsl::intrinsic::data
diff --git a/src/tint/lang/wgsl/intrinsic/data/data.h b/src/tint/lang/wgsl/intrinsic/data/data.h
new file mode 100644
index 0000000..74faeb3
--- /dev/null
+++ b/src/tint/lang/wgsl/intrinsic/data/data.h
@@ -0,0 +1,26 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_LANG_WGSL_INTRINSIC_DATA_DATA_H_
+#define SRC_TINT_LANG_WGSL_INTRINSIC_DATA_DATA_H_
+
+#include "src/tint/lang/core/intrinsic/table_data.h"
+
+namespace tint::wgsl::intrinsic::data {
+
+extern const core::intrinsic::TableData kData;
+
+}  // namespace tint::wgsl::intrinsic::data
+
+#endif  // SRC_TINT_LANG_WGSL_INTRINSIC_DATA_DATA_H_
diff --git a/src/tint/lang/wgsl/ir/BUILD.bazel b/src/tint/lang/wgsl/ir/BUILD.bazel
new file mode 100644
index 0000000..cc09dc5
--- /dev/null
+++ b/src/tint/lang/wgsl/ir/BUILD.bazel
@@ -0,0 +1,60 @@
+# Copyright 2023 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# 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/wgsl",
+    "//src/tint/lang/wgsl/intrinsic/data",
+    "//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/wgsl/ir/BUILD.cmake b/src/tint/lang/wgsl/ir/BUILD.cmake
new file mode 100644
index 0000000..72ba88a
--- /dev/null
+++ b/src/tint/lang/wgsl/ir/BUILD.cmake
@@ -0,0 +1,55 @@
+# Copyright 2023 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# 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_wgsl_ir
+# Kind:      lib
+################################################################################
+tint_add_target(tint_lang_wgsl_ir lib
+  lang/wgsl/ir/builtin_call.cc
+  lang/wgsl/ir/builtin_call.h
+)
+
+tint_target_add_dependencies(tint_lang_wgsl_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_wgsl
+  tint_lang_wgsl_intrinsic_data
+  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/wgsl/ir/BUILD.gn b/src/tint/lang/wgsl/ir/BUILD.gn
new file mode 100644
index 0000000..7be98a4
--- /dev/null
+++ b/src/tint/lang/wgsl/ir/BUILD.gn
@@ -0,0 +1,56 @@
+# Copyright 2023 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# 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("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/wgsl",
+    "${tint_src_dir}/lang/wgsl/intrinsic/data",
+    "${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/wgsl/ir/builtin_call.cc b/src/tint/lang/wgsl/ir/builtin_call.cc
new file mode 100644
index 0000000..4511787
--- /dev/null
+++ b/src/tint/lang/wgsl/ir/builtin_call.cc
@@ -0,0 +1,42 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/lang/wgsl/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::wgsl::ir::BuiltinCall);
+
+namespace tint::wgsl::ir {
+
+BuiltinCall::BuiltinCall(core::ir::InstructionResult* result,
+                         BuiltinFn fn,
+                         VectorRef<core::ir::Value*> arguments)
+    : Base(result, arguments), fn_(fn) {
+    TINT_ASSERT(fn != BuiltinFn::kNone);
+}
+
+BuiltinCall::~BuiltinCall() = default;
+
+BuiltinCall* BuiltinCall::Clone(core::ir::CloneContext& ctx) {
+    auto* new_result = ctx.Clone(Result());
+    auto new_args = ctx.Clone<BuiltinCall::kDefaultNumOperands>(Args());
+    return ctx.ir.instructions.Create<BuiltinCall>(new_result, fn_, new_args);
+}
+
+}  // namespace tint::wgsl::ir
diff --git a/src/tint/lang/wgsl/ir/builtin_call.h b/src/tint/lang/wgsl/ir/builtin_call.h
new file mode 100644
index 0000000..6e1d413
--- /dev/null
+++ b/src/tint/lang/wgsl/ir/builtin_call.h
@@ -0,0 +1,61 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_LANG_WGSL_IR_BUILTIN_CALL_H_
+#define SRC_TINT_LANG_WGSL_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/wgsl/builtin_fn.h"
+#include "src/tint/lang/wgsl/intrinsic/data/data.h"
+#include "src/tint/utils/rtti/castable.h"
+
+namespace tint::wgsl::ir {
+
+/// A WGSL builtin call instruction in the IR.
+class BuiltinCall : public Castable<BuiltinCall, core::ir::BuiltinCall> {
+  public:
+    /// Constructor
+    /// @param result the result value
+    /// @param fn the builtin function
+    /// @param args the conversion arguments
+    BuiltinCall(core::ir::InstructionResult* result,
+                BuiltinFn fn,
+                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() { return fn_; }
+
+    /// @returns the identifier for the function
+    size_t FuncId() override { return static_cast<size_t>(fn_); }
+
+    /// @returns the friendly name for the instruction
+    std::string FriendlyName() override { return std::string("wgsl.") + str(fn_); }
+
+    /// @returns the table data to validate this builtin
+    const core::intrinsic::TableData& TableData() override { return intrinsic::data::kData; }
+
+  private:
+    BuiltinFn fn_;
+};
+
+}  // namespace tint::wgsl::ir
+
+#endif  // SRC_TINT_LANG_WGSL_IR_BUILTIN_CALL_H_
diff --git a/src/tint/lang/wgsl/ir_roundtrip_test.cc b/src/tint/lang/wgsl/ir_roundtrip_test.cc
index bbca278..3585594 100644
--- a/src/tint/lang/wgsl/ir_roundtrip_test.cc
+++ b/src/tint/lang/wgsl/ir_roundtrip_test.cc
@@ -31,29 +31,19 @@
     void Test(std::string_view input_wgsl, std::string_view expected_wgsl) {
         auto input = tint::TrimSpace(input_wgsl);
         Source::File file("test.wgsl", std::string(input));
-        auto input_program = wgsl::reader::Parse(&file);
-        ASSERT_TRUE(input_program.IsValid()) << input_program.Diagnostics();
-
-        auto ir_module = wgsl::reader::ProgramToIR(input_program);
-        ASSERT_TRUE(ir_module) << (ir_module ? "" : ir_module.Failure());
+        auto ir_module = wgsl::reader::WgslToIR(&file);
+        ASSERT_TRUE(ir_module) << ir_module;
 
         tint::core::ir::Disassembler d{ir_module.Get()};
         auto disassembly = d.Disassemble();
 
-        auto output_program = wgsl::writer::IRToProgram(ir_module.Get());
-        if (!output_program.IsValid()) {
-            FAIL() << output_program.Diagnostics() << std::endl  //
-                   << "IR:" << std::endl                         //
-                   << disassembly << std::endl                   //
-                   << "AST:" << std::endl                        //
-                   << Program::printer(output_program) << std::endl;
+        auto output = wgsl::writer::WgslFromIR(ir_module.Get());
+        if (!output) {
+            FAIL() << output.Failure() << std::endl  //
+                   << "IR:" << std::endl             //
+                   << disassembly << std::endl;
         }
 
-        ASSERT_TRUE(output_program.IsValid()) << output_program.Diagnostics();
-
-        auto output = wgsl::writer::Generate(output_program, {});
-        ASSERT_TRUE(output) << output.Failure();
-
         auto expected = expected_wgsl.empty() ? input : tint::TrimSpace(expected_wgsl);
         auto got = tint::TrimSpace(output->wgsl);
         EXPECT_EQ(expected, got) << "IR:" << std::endl << disassembly;
diff --git a/src/tint/lang/wgsl/reader/BUILD.bazel b/src/tint/lang/wgsl/reader/BUILD.bazel
index 43922a8..116874d 100644
--- a/src/tint/lang/wgsl/reader/BUILD.bazel
+++ b/src/tint/lang/wgsl/reader/BUILD.bazel
@@ -35,11 +35,14 @@
     "//src/tint/api/common",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
     "//src/tint/lang/wgsl/program",
+    "//src/tint/lang/wgsl/reader/lower",
     "//src/tint/lang/wgsl/reader/parser",
+    "//src/tint/lang/wgsl/reader/program_to_ir",
     "//src/tint/lang/wgsl/resolver",
     "//src/tint/lang/wgsl/sem",
     "//src/tint/utils/containers",
@@ -65,9 +68,11 @@
     "reader_bench.cc",
   ],
   deps = [
+    "//src/tint/api/common",
     "//src/tint/cmd/bench",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
@@ -81,6 +86,7 @@
     "//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",
diff --git a/src/tint/lang/wgsl/reader/BUILD.cmake b/src/tint/lang/wgsl/reader/BUILD.cmake
index 9848c4b..2d94eb5 100644
--- a/src/tint/lang/wgsl/reader/BUILD.cmake
+++ b/src/tint/lang/wgsl/reader/BUILD.cmake
@@ -21,6 +21,7 @@
 #                       Do not modify this file directly
 ################################################################################
 
+include(lang/wgsl/reader/lower/BUILD.cmake)
 include(lang/wgsl/reader/parser/BUILD.cmake)
 include(lang/wgsl/reader/program_to_ir/BUILD.cmake)
 
@@ -37,11 +38,14 @@
   tint_api_common
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
   tint_lang_wgsl_program
+  tint_lang_wgsl_reader_lower
   tint_lang_wgsl_reader_parser
+  tint_lang_wgsl_reader_program_to_ir
   tint_lang_wgsl_resolver
   tint_lang_wgsl_sem
   tint_utils_containers
@@ -68,9 +72,11 @@
 )
 
 tint_target_add_dependencies(tint_lang_wgsl_reader_bench bench
+  tint_api_common
   tint_cmd_bench
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
@@ -84,6 +90,7 @@
   tint_utils_macros
   tint_utils_math
   tint_utils_memory
+  tint_utils_reflection
   tint_utils_result
   tint_utils_rtti
   tint_utils_symbol
diff --git a/src/tint/lang/wgsl/reader/BUILD.gn b/src/tint/lang/wgsl/reader/BUILD.gn
index 7c450ca..7962250 100644
--- a/src/tint/lang/wgsl/reader/BUILD.gn
+++ b/src/tint/lang/wgsl/reader/BUILD.gn
@@ -34,11 +34,14 @@
     "${tint_src_dir}/api/common",
     "${tint_src_dir}/lang/core",
     "${tint_src_dir}/lang/core/constant",
+    "${tint_src_dir}/lang/core/ir",
     "${tint_src_dir}/lang/core/type",
     "${tint_src_dir}/lang/wgsl",
     "${tint_src_dir}/lang/wgsl/ast",
     "${tint_src_dir}/lang/wgsl/program",
+    "${tint_src_dir}/lang/wgsl/reader/lower",
     "${tint_src_dir}/lang/wgsl/reader/parser",
+    "${tint_src_dir}/lang/wgsl/reader/program_to_ir",
     "${tint_src_dir}/lang/wgsl/resolver",
     "${tint_src_dir}/lang/wgsl/sem",
     "${tint_src_dir}/utils/containers",
diff --git a/src/tint/lang/wgsl/reader/lower/BUILD.bazel b/src/tint/lang/wgsl/reader/lower/BUILD.bazel
new file mode 100644
index 0000000..4ff3379
--- /dev/null
+++ b/src/tint/lang/wgsl/reader/lower/BUILD.bazel
@@ -0,0 +1,99 @@
+# Copyright 2023 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# 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 = "lower",
+  srcs = [
+    "lower.cc",
+  ],
+  hdrs = [
+    "lower.h",
+  ],
+  deps = [
+    "//src/tint/api/common",
+    "//src/tint/lang/core",
+    "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/intrinsic",
+    "//src/tint/lang/core/intrinsic/data",
+    "//src/tint/lang/core/ir",
+    "//src/tint/lang/core/type",
+    "//src/tint/lang/wgsl",
+    "//src/tint/lang/wgsl/intrinsic/data",
+    "//src/tint/lang/wgsl/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",
+  ],
+  copts = COPTS,
+  visibility = ["//visibility:public"],
+)
+cc_library(
+  name = "test",
+  alwayslink = True,
+  srcs = [
+    "lower_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/intrinsic/data",
+    "//src/tint/lang/core/ir",
+    "//src/tint/lang/core/ir/transform:test",
+    "//src/tint/lang/core/type",
+    "//src/tint/lang/wgsl",
+    "//src/tint/lang/wgsl/intrinsic/data",
+    "//src/tint/lang/wgsl/ir",
+    "//src/tint/lang/wgsl/reader/lower",
+    "//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/wgsl/reader/lower/BUILD.cmake b/src/tint/lang/wgsl/reader/lower/BUILD.cmake
new file mode 100644
index 0000000..3bc145f
--- /dev/null
+++ b/src/tint/lang/wgsl/reader/lower/BUILD.cmake
@@ -0,0 +1,97 @@
+# Copyright 2023 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# 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_wgsl_reader_lower
+# Kind:      lib
+################################################################################
+tint_add_target(tint_lang_wgsl_reader_lower lib
+  lang/wgsl/reader/lower/lower.cc
+  lang/wgsl/reader/lower/lower.h
+)
+
+tint_target_add_dependencies(tint_lang_wgsl_reader_lower lib
+  tint_api_common
+  tint_lang_core
+  tint_lang_core_constant
+  tint_lang_core_intrinsic
+  tint_lang_core_intrinsic_data
+  tint_lang_core_ir
+  tint_lang_core_type
+  tint_lang_wgsl
+  tint_lang_wgsl_intrinsic_data
+  tint_lang_wgsl_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
+)
+
+################################################################################
+# Target:    tint_lang_wgsl_reader_lower_test
+# Kind:      test
+################################################################################
+tint_add_target(tint_lang_wgsl_reader_lower_test test
+  lang/wgsl/reader/lower/lower_test.cc
+)
+
+tint_target_add_dependencies(tint_lang_wgsl_reader_lower_test test
+  tint_api_common
+  tint_lang_core
+  tint_lang_core_constant
+  tint_lang_core_intrinsic
+  tint_lang_core_intrinsic_data
+  tint_lang_core_ir
+  tint_lang_core_ir_transform_test
+  tint_lang_core_type
+  tint_lang_wgsl
+  tint_lang_wgsl_intrinsic_data
+  tint_lang_wgsl_ir
+  tint_lang_wgsl_reader_lower
+  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_wgsl_reader_lower_test test
+  "gtest"
+)
diff --git a/src/tint/lang/wgsl/reader/lower/BUILD.gn b/src/tint/lang/wgsl/reader/lower/BUILD.gn
new file mode 100644
index 0000000..f9c38e3
--- /dev/null
+++ b/src/tint/lang/wgsl/reader/lower/BUILD.gn
@@ -0,0 +1,96 @@
+# Copyright 2023 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# 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) {
+  import("//testing/test.gni")
+}
+
+libtint_source_set("lower") {
+  sources = [
+    "lower.cc",
+    "lower.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/intrinsic/data",
+    "${tint_src_dir}/lang/core/ir",
+    "${tint_src_dir}/lang/core/type",
+    "${tint_src_dir}/lang/wgsl",
+    "${tint_src_dir}/lang/wgsl/intrinsic/data",
+    "${tint_src_dir}/lang/wgsl/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",
+  ]
+}
+if (tint_build_unittests) {
+  tint_unittests_source_set("unittests") {
+    testonly = true
+    sources = [ "lower_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/intrinsic/data",
+      "${tint_src_dir}/lang/core/ir",
+      "${tint_src_dir}/lang/core/ir/transform:unittests",
+      "${tint_src_dir}/lang/core/type",
+      "${tint_src_dir}/lang/wgsl",
+      "${tint_src_dir}/lang/wgsl/intrinsic/data",
+      "${tint_src_dir}/lang/wgsl/ir",
+      "${tint_src_dir}/lang/wgsl/reader/lower",
+      "${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/wgsl/reader/lower/lower.cc b/src/tint/lang/wgsl/reader/lower/lower.cc
new file mode 100644
index 0000000..64bef4b
--- /dev/null
+++ b/src/tint/lang/wgsl/reader/lower/lower.cc
@@ -0,0 +1,169 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/lang/wgsl/reader/lower/lower.h"
+
+#include <utility>
+
+#include "src/tint/lang/core/builtin_fn.h"
+#include "src/tint/lang/core/ir/core_builtin_call.h"
+#include "src/tint/lang/wgsl/builtin_fn.h"
+#include "src/tint/lang/wgsl/ir/builtin_call.h"
+
+namespace tint::wgsl::reader {
+namespace {
+
+core::BuiltinFn Convert(wgsl::BuiltinFn fn) {
+#define CASE(NAME)              \
+    case wgsl::BuiltinFn::NAME: \
+        return core::BuiltinFn::NAME;
+
+    switch (fn) {
+        CASE(kAbs)
+        CASE(kAcos)
+        CASE(kAcosh)
+        CASE(kAll)
+        CASE(kAny)
+        CASE(kArrayLength)
+        CASE(kAsin)
+        CASE(kAsinh)
+        CASE(kAtan)
+        CASE(kAtan2)
+        CASE(kAtanh)
+        CASE(kCeil)
+        CASE(kClamp)
+        CASE(kCos)
+        CASE(kCosh)
+        CASE(kCountLeadingZeros)
+        CASE(kCountOneBits)
+        CASE(kCountTrailingZeros)
+        CASE(kCross)
+        CASE(kDegrees)
+        CASE(kDeterminant)
+        CASE(kDistance)
+        CASE(kDot)
+        CASE(kDot4I8Packed)
+        CASE(kDot4U8Packed)
+        CASE(kDpdx)
+        CASE(kDpdxCoarse)
+        CASE(kDpdxFine)
+        CASE(kDpdy)
+        CASE(kDpdyCoarse)
+        CASE(kDpdyFine)
+        CASE(kExp)
+        CASE(kExp2)
+        CASE(kExtractBits)
+        CASE(kFaceForward)
+        CASE(kFirstLeadingBit)
+        CASE(kFirstTrailingBit)
+        CASE(kFloor)
+        CASE(kFma)
+        CASE(kFract)
+        CASE(kFrexp)
+        CASE(kFwidth)
+        CASE(kFwidthCoarse)
+        CASE(kFwidthFine)
+        CASE(kInsertBits)
+        CASE(kInverseSqrt)
+        CASE(kLdexp)
+        CASE(kLength)
+        CASE(kLog)
+        CASE(kLog2)
+        CASE(kMax)
+        CASE(kMin)
+        CASE(kMix)
+        CASE(kModf)
+        CASE(kNormalize)
+        CASE(kPack2X16Float)
+        CASE(kPack2X16Snorm)
+        CASE(kPack2X16Unorm)
+        CASE(kPack4X8Snorm)
+        CASE(kPack4X8Unorm)
+        CASE(kPow)
+        CASE(kQuantizeToF16)
+        CASE(kRadians)
+        CASE(kReflect)
+        CASE(kRefract)
+        CASE(kReverseBits)
+        CASE(kRound)
+        CASE(kSaturate)
+        CASE(kSelect)
+        CASE(kSign)
+        CASE(kSin)
+        CASE(kSinh)
+        CASE(kSmoothstep)
+        CASE(kSqrt)
+        CASE(kStep)
+        CASE(kStorageBarrier)
+        CASE(kTan)
+        CASE(kTanh)
+        CASE(kTranspose)
+        CASE(kTrunc)
+        CASE(kUnpack2X16Float)
+        CASE(kUnpack2X16Snorm)
+        CASE(kUnpack2X16Unorm)
+        CASE(kUnpack4X8Snorm)
+        CASE(kUnpack4X8Unorm)
+        CASE(kWorkgroupBarrier)
+        CASE(kWorkgroupUniformLoad)
+        CASE(kTextureBarrier)
+        CASE(kTextureDimensions)
+        CASE(kTextureGather)
+        CASE(kTextureGatherCompare)
+        CASE(kTextureNumLayers)
+        CASE(kTextureNumLevels)
+        CASE(kTextureNumSamples)
+        CASE(kTextureSample)
+        CASE(kTextureSampleBias)
+        CASE(kTextureSampleCompare)
+        CASE(kTextureSampleCompareLevel)
+        CASE(kTextureSampleGrad)
+        CASE(kTextureSampleLevel)
+        CASE(kTextureSampleBaseClampToEdge)
+        CASE(kTextureStore)
+        CASE(kTextureLoad)
+        CASE(kAtomicLoad)
+        CASE(kAtomicStore)
+        CASE(kAtomicAdd)
+        CASE(kAtomicSub)
+        CASE(kAtomicMax)
+        CASE(kAtomicMin)
+        CASE(kAtomicAnd)
+        CASE(kAtomicOr)
+        CASE(kAtomicXor)
+        CASE(kAtomicExchange)
+        CASE(kAtomicCompareExchangeWeak)
+        CASE(kSubgroupBallot)
+        CASE(kSubgroupBroadcast)
+        default:
+            TINT_ICE() << "unhandled builtin function: " << fn;
+            return core::BuiltinFn::kNone;
+    }
+}
+
+}  // namespace
+
+Result<SuccessType> Lower(core::ir::Module& mod) {
+    for (auto* inst : mod.instructions.Objects()) {
+        if (auto* call = inst->As<wgsl::ir::BuiltinCall>()) {
+            Vector<core::ir::Value*, 8> args(call->Args());
+            auto* replacement = mod.instructions.Create<core::ir::CoreBuiltinCall>(
+                call->Result(), Convert(call->Func()), std::move(args));
+            call->ReplaceWith(replacement);
+        }
+    }
+    return Success;
+}
+
+}  // namespace tint::wgsl::reader
diff --git a/src/tint/lang/wgsl/reader/lower/lower.h b/src/tint/lang/wgsl/reader/lower/lower.h
new file mode 100644
index 0000000..6817413
--- /dev/null
+++ b/src/tint/lang/wgsl/reader/lower/lower.h
@@ -0,0 +1,31 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_LANG_WGSL_READER_LOWER_LOWER_H_
+#define SRC_TINT_LANG_WGSL_READER_LOWER_LOWER_H_
+
+#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/result/result.h"
+
+namespace tint::wgsl::reader {
+
+/// Lower converts a WGSL-dialect IR module to a core-dialect IR module
+/// @param  mod the IR module
+/// @return the result of the operation
+Result<SuccessType> Lower(core::ir::Module& mod);
+
+}  // namespace tint::wgsl::reader
+
+#endif  // SRC_TINT_LANG_WGSL_READER_LOWER_LOWER_H_
diff --git a/src/tint/lang/wgsl/reader/lower/lower_test.cc b/src/tint/lang/wgsl/reader/lower/lower_test.cc
new file mode 100644
index 0000000..589a8c4
--- /dev/null
+++ b/src/tint/lang/wgsl/reader/lower/lower_test.cc
@@ -0,0 +1,68 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <utility>
+
+#include "src/tint/lang/core/ir/transform/helper_test.h"
+#include "src/tint/lang/core/type/struct.h"
+#include "src/tint/lang/wgsl/builtin_fn.h"
+#include "src/tint/lang/wgsl/ir/builtin_call.h"
+#include "src/tint/lang/wgsl/reader/lower/lower.h"
+
+namespace tint::wgsl::reader::lower {
+namespace {
+
+using namespace tint::core::fluent_types;     // NOLINT
+using namespace tint::core::number_suffixes;  // NOLINT
+
+using Wgslreader_LowerTest = core::ir::transform::TransformTest;
+
+TEST_F(Wgslreader_LowerTest, BuiltinConversion) {
+    auto* f = b.Function("f", ty.void_());
+    b.Append(f->Block(), [&] {  //
+        auto* result = b.InstructionResult(ty.i32());
+        b.Append(b.ir.instructions.Create<wgsl::ir::BuiltinCall>(result, wgsl::BuiltinFn::kMax,
+                                                                 Vector{
+                                                                     b.Value(i32(1)),
+                                                                     b.Value(i32(2)),
+                                                                 }));
+        b.Return(f);
+    });
+
+    auto* src = R"(
+%f = func():void -> %b1 {
+  %b1 = block {
+    %2:i32 = wgsl.max 1i, 2i
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():void -> %b1 {
+  %b1 = block {
+    %2:i32 = max 1i, 2i
+    ret
+  }
+}
+)";
+
+    Run(Lower);
+
+    EXPECT_EQ(expect, str());
+}
+
+}  // namespace
+}  // namespace tint::wgsl::reader::lower
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.bazel b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.bazel
index 17ea099..9f6305d 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.bazel
+++ b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.bazel
@@ -41,6 +41,8 @@
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
+    "//src/tint/lang/wgsl/intrinsic/data",
+    "//src/tint/lang/wgsl/ir",
     "//src/tint/lang/wgsl/program",
     "//src/tint/lang/wgsl/sem",
     "//src/tint/utils/containers",
@@ -89,6 +91,7 @@
     "//src/tint/lang/wgsl/helpers:test",
     "//src/tint/lang/wgsl/program",
     "//src/tint/lang/wgsl/reader",
+    "//src/tint/lang/wgsl/reader/lower",
     "//src/tint/lang/wgsl/reader/program_to_ir",
     "//src/tint/lang/wgsl/resolver",
     "//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.cmake b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.cmake
index 39a7619..812feec 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.cmake
+++ b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.cmake
@@ -40,6 +40,8 @@
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
+  tint_lang_wgsl_intrinsic_data
+  tint_lang_wgsl_ir
   tint_lang_wgsl_program
   tint_lang_wgsl_sem
   tint_utils_containers
@@ -88,6 +90,7 @@
   tint_lang_wgsl_helpers_test
   tint_lang_wgsl_program
   tint_lang_wgsl_reader
+  tint_lang_wgsl_reader_lower
   tint_lang_wgsl_reader_program_to_ir
   tint_lang_wgsl_resolver
   tint_lang_wgsl_sem
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn
index a2de875..110350a 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn
+++ b/src/tint/lang/wgsl/reader/program_to_ir/BUILD.gn
@@ -44,6 +44,8 @@
     "${tint_src_dir}/lang/core/type",
     "${tint_src_dir}/lang/wgsl",
     "${tint_src_dir}/lang/wgsl/ast",
+    "${tint_src_dir}/lang/wgsl/intrinsic/data",
+    "${tint_src_dir}/lang/wgsl/ir",
     "${tint_src_dir}/lang/wgsl/program",
     "${tint_src_dir}/lang/wgsl/sem",
     "${tint_src_dir}/utils/containers",
@@ -91,6 +93,7 @@
       "${tint_src_dir}/lang/wgsl/helpers:unittests",
       "${tint_src_dir}/lang/wgsl/program",
       "${tint_src_dir}/lang/wgsl/reader",
+      "${tint_src_dir}/lang/wgsl/reader/lower",
       "${tint_src_dir}/lang/wgsl/reader/program_to_ir",
       "${tint_src_dir}/lang/wgsl/resolver",
       "${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/accessor_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/accessor_test.cc
index b2b47d3..683e04a 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/accessor_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/accessor_test.cc
@@ -38,7 +38,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -64,7 +64,7 @@
     WrapInFunction(Decl(a), expr, expr2);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -87,7 +87,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -109,7 +109,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -132,7 +132,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -159,7 +159,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(MyStruct = struct @align(4) {
@@ -195,7 +195,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(Inner = struct @align(4) {
@@ -240,7 +240,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(Inner = struct @align(16) {
@@ -274,7 +274,7 @@
     WrapInFunction(Decl(a), assign);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -297,7 +297,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -319,7 +319,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -342,7 +342,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -373,7 +373,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(MyStruct = struct @align(16) {
@@ -403,7 +403,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -425,7 +425,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -451,7 +451,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(MyStruct = struct @align(4) {
@@ -486,7 +486,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(Inner = struct @align(4) {
@@ -530,7 +530,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(Inner = struct @align(16) {
@@ -563,7 +563,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -585,7 +585,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -607,7 +607,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -637,7 +637,7 @@
     WrapInFunction(Decl(a), expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(MyStruct = struct @align(16) {
@@ -669,7 +669,7 @@
     WrapInFunction(v, i, b);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -694,7 +694,7 @@
     WrapInFunction(v, i, b);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -719,7 +719,7 @@
     WrapInFunction(v, i, b);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/binary_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/binary_test.cc
index 1ad4372..17dbf93 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/binary_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/binary_test.cc
@@ -31,7 +31,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -54,7 +54,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %v1:ptr<private, u32, read_write> = var
@@ -77,7 +77,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %v1:ptr<private, u32, read_write> = var
@@ -100,7 +100,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -123,7 +123,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %v1:ptr<private, i32, read_write> = var
@@ -146,7 +146,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %v1:ptr<private, u32, read_write> = var
@@ -169,7 +169,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -192,7 +192,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %v1:ptr<private, u32, read_write> = var
@@ -215,7 +215,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -238,7 +238,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %v1:ptr<private, u32, read_write> = var
@@ -261,7 +261,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -284,7 +284,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %v1:ptr<private, u32, read_write> = var
@@ -307,7 +307,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -330,7 +330,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %v1:ptr<private, bool, read_write> = var
@@ -353,7 +353,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -376,7 +376,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %v1:ptr<private, bool, read_write> = var
@@ -399,7 +399,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -422,7 +422,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %v1:ptr<private, u32, read_write> = var
@@ -446,7 +446,7 @@
     WrapInFunction(let, expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():bool -> %b1 {
   %b1 = block {
@@ -482,7 +482,7 @@
     WrapInFunction(let, expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():bool -> %b1 {
   %b1 = block {
@@ -517,7 +517,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -540,7 +540,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -563,7 +563,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -586,7 +586,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -609,7 +609,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -632,7 +632,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -655,7 +655,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -678,7 +678,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %v1:ptr<private, u32, read_write> = var
@@ -701,7 +701,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -724,7 +724,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %v1:ptr<private, u32, read_write> = var
@@ -749,7 +749,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():f32 -> %b1 {
   %b1 = block {
@@ -786,7 +786,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func(%p:bool):bool -> %b1 {
   %b1 = block {
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/builtin_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/builtin_test.cc
index e3092df..ce39f3c 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/builtin_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/builtin_test.cc
@@ -31,7 +31,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %i:ptr<private, f32, read_write> = var, 1.0f
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/call_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/call_test.cc
index be35147..0fa6aea 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/call_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/call_test.cc
@@ -33,7 +33,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():f32 -> %b1 {
   %b1 = block {
@@ -58,7 +58,7 @@
          });
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%test_function = @fragment func():void -> %b1 {
   %b1 = block {
@@ -75,7 +75,7 @@
     auto* stmt = CallStmt(Call("my_func", Mul(2_a, 3_a)));
     WrapInFunction(stmt);
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func(%p:f32):void -> %b1 {
   %b1 = block {
@@ -97,7 +97,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %i:ptr<private, i32, read_write> = var, 1i
@@ -118,7 +118,7 @@
     GlobalVar("i", core::AddressSpace::kPrivate, expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %i:ptr<private, vec3<f32>, read_write> = var, vec3<f32>(0.0f)
@@ -133,7 +133,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %i:ptr<private, f32, read_write> = var, 1.0f
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/function_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/function_test.cc
index 85e02e0..24f2795 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/function_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/function_test.cc
@@ -32,7 +32,7 @@
          Vector{Builtin(core::BuiltinValue::kPosition)});
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%test = @vertex func():vec4<f32> [@position] -> %b1 {
   %b1 = block {
@@ -47,7 +47,7 @@
          Vector{Stage(ast::PipelineStage::kFragment)});
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%test = @fragment func():void -> %b1 {
   %b1 = block {
@@ -62,7 +62,7 @@
          Vector{Stage(ast::PipelineStage::kCompute), WorkgroupSize(8_i, 4_i, 2_i)});
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test = @compute @workgroup_size(8, 4, 2) func():void -> %b1 {
@@ -78,7 +78,7 @@
          tint::Empty);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%test = func():vec3<f32> -> %b1 {
   %b1 = block {
@@ -93,7 +93,7 @@
          Vector{If(true, Block(Return(0_f)), Else(Block(Return(1_f))))}, tint::Empty);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%test = func():f32 -> %b1 {
   %b1 = block {
@@ -117,7 +117,7 @@
          Vector{Builtin(core::BuiltinValue::kPosition)});
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%test = @vertex func():vec4<f32> [@position] -> %b1 {
   %b1 = block {
@@ -133,7 +133,7 @@
          Vector{Builtin(core::BuiltinValue::kPosition), Invariant()});
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test = @vertex func():vec4<f32> [@invariant, @position] -> %b1 {
@@ -149,7 +149,7 @@
          Vector{Stage(ast::PipelineStage::kFragment)}, Vector{Location(1_i)});
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test = @fragment func():vec4<f32> [@location(1)] -> %b1 {
@@ -167,7 +167,7 @@
                                            core::InterpolationSampling::kCentroid)});
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(
         Disassemble(m.Get()),
@@ -185,7 +185,7 @@
          Vector{Builtin(core::BuiltinValue::kFragDepth)});
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%test = @fragment func():f32 [@frag_depth] -> %b1 {
   %b1 = block {
@@ -201,7 +201,7 @@
          Vector{Builtin(core::BuiltinValue::kSampleMask)});
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%test = @fragment func():u32 [@sample_mask] -> %b1 {
   %b1 = block {
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/let_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/let_test.cc
index 5bcd835..d341c4e 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/let_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/let_test.cc
@@ -29,7 +29,7 @@
     WrapInFunction(Let("a", Expr(42_i)));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -45,7 +45,7 @@
     WrapInFunction(Let("a", Add(1_i, 2_i)));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -63,7 +63,7 @@
                    Let("c", Expr("b")));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/literal_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/literal_test.cc
index 52a5fa2..8784f80 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/literal_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/literal_test.cc
@@ -28,7 +28,7 @@
 namespace {
 
 core::ir::Value* GlobalVarInitializer(core::ir::Module& m) {
-    if (m.root_block->Length() == 0u) {
+    if (m.root_block->IsEmpty()) {
         ADD_FAILURE() << "m.root_block has no instruction";
         return nullptr;
     }
@@ -51,7 +51,7 @@
     GlobalVar("a", ty.bool_(), core::AddressSpace::kPrivate, expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     auto* init = GlobalVarInitializer(m.Get());
     ASSERT_TRUE(Is<core::ir::Constant>(init));
@@ -65,7 +65,7 @@
     GlobalVar("a", ty.bool_(), core::AddressSpace::kPrivate, expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     auto* init = GlobalVarInitializer(m.Get());
     ASSERT_TRUE(Is<core::ir::Constant>(init));
@@ -81,7 +81,7 @@
     GlobalVar("d", ty.bool_(), core::AddressSpace::kPrivate, Expr(false));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     auto itr = m.Get().root_block->begin();
     auto* var_a = (*itr)->As<core::ir::Var>();
@@ -109,7 +109,7 @@
     GlobalVar("a", ty.f32(), core::AddressSpace::kPrivate, expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     auto* init = GlobalVarInitializer(m.Get());
     ASSERT_TRUE(Is<core::ir::Constant>(init));
@@ -124,7 +124,7 @@
     GlobalVar("c", ty.f32(), core::AddressSpace::kPrivate, Expr(1.2_f));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     auto itr = m.Get().root_block->begin();
     auto* var_a = (*itr)->As<core::ir::Var>();
@@ -148,7 +148,7 @@
     GlobalVar("a", ty.f16(), core::AddressSpace::kPrivate, expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     auto* init = GlobalVarInitializer(m.Get());
     ASSERT_TRUE(Is<core::ir::Constant>(init));
@@ -164,7 +164,7 @@
     GlobalVar("c", ty.f16(), core::AddressSpace::kPrivate, Expr(1.2_h));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     auto itr = m.Get().root_block->begin();
     auto* var_a = (*itr)->As<core::ir::Var>();
@@ -187,7 +187,7 @@
     GlobalVar("a", ty.i32(), core::AddressSpace::kPrivate, expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     auto* init = GlobalVarInitializer(m.Get());
     ASSERT_TRUE(Is<core::ir::Constant>(init));
@@ -202,7 +202,7 @@
     GlobalVar("c", ty.i32(), core::AddressSpace::kPrivate, Expr(-2_i));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     auto itr = m.Get().root_block->begin();
     auto* var_a = (*itr)->As<core::ir::Var>();
@@ -225,7 +225,7 @@
     GlobalVar("a", ty.u32(), core::AddressSpace::kPrivate, expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     auto* init = GlobalVarInitializer(m.Get());
     ASSERT_TRUE(Is<core::ir::Constant>(init));
@@ -240,7 +240,7 @@
     GlobalVar("c", ty.u32(), core::AddressSpace::kPrivate, Expr(2_u));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     auto itr = m.Get().root_block->begin();
     auto* var_a = (*itr)->As<core::ir::Var>();
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/materialize_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/materialize_test.cc
index dcef1e4..303bc3d 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/materialize_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/materialize_test.cc
@@ -31,7 +31,7 @@
     Func("test_function", {}, ty.f32(), expr, tint::Empty);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%test_function = func():f32 -> %b1 {
   %b1 = block {
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
index fa464bb..7115650 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
@@ -84,6 +84,7 @@
 #include "src/tint/lang/wgsl/ast/var.h"
 #include "src/tint/lang/wgsl/ast/variable_decl_statement.h"
 #include "src/tint/lang/wgsl/ast/while_statement.h"
+#include "src/tint/lang/wgsl/ir/builtin_call.h"
 #include "src/tint/lang/wgsl/program/program.h"
 #include "src/tint/lang/wgsl/sem/builtin_fn.h"
 #include "src/tint/lang/wgsl/sem/call.h"
@@ -111,7 +112,7 @@
 namespace tint::wgsl::reader {
 namespace {
 
-using ResultType = tint::Result<core::ir::Module, diag::List>;
+using ResultType = tint::Result<core::ir::Module>;
 
 /// Impl is the private-implementation of FromProgram().
 class Impl {
@@ -231,7 +232,7 @@
                 [&](const ast::Variable* var) {
                     // Setup the current block to be the root block for the module. The builder
                     // will handle creating it if it doesn't exist already.
-                    TINT_SCOPED_ASSIGNMENT(current_block_, builder_.RootBlock());
+                    TINT_SCOPED_ASSIGNMENT(current_block_, mod.root_block);
                     EmitVariable(var);
                 },
                 [&](const ast::Function* func) { EmitFunction(func); },
@@ -251,10 +252,10 @@
         }
 
         if (diagnostics_.contains_errors()) {
-            return ResultType(std::move(diagnostics_));
+            return Failure{std::move(diagnostics_)};
         }
 
-        return ResultType{std::move(mod)};
+        return std::move(mod);
     }
 
     core::Interpolation ExtractInterpolation(const ast::InterpolateAttribute* interp) {
@@ -1098,7 +1099,9 @@
                 core::ir::Instruction* inst = nullptr;
                 // If this is a builtin function, emit the specific builtin value
                 if (auto* b = sem->Target()->As<sem::BuiltinFn>()) {
-                    inst = impl.builder_.Call(ty, b->Fn(), args);
+                    auto* res = impl.builder_.InstructionResult(ty);
+                    inst = impl.builder_.ir.instructions.Create<wgsl::ir::BuiltinCall>(
+                        res, b->Fn(), std::move(args));
                 } else if (sem->Target()->As<sem::ValueConstructor>()) {
                     inst = impl.builder_.Construct(ty, std::move(args));
                 } else if (sem->Target()->Is<sem::ValueConversion>()) {
@@ -1417,15 +1420,15 @@
 
 }  // namespace
 
-tint::Result<core::ir::Module, std::string> ProgramToIR(const Program& program) {
+tint::Result<core::ir::Module> ProgramToIR(const Program& program) {
     if (!program.IsValid()) {
-        return std::string("input program is not valid");
+        return Failure{program.Diagnostics()};
     }
 
     Impl b(program);
     auto r = b.Build();
     if (!r) {
-        return r.Failure().str();
+        return r.Failure();
     }
 
     return r.Move();
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h
index d51f338..c139896 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h
+++ b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h
@@ -18,6 +18,7 @@
 #include <string>
 
 #include "src/tint/lang/core/ir/module.h"
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward Declarations
@@ -27,15 +28,14 @@
 
 namespace tint::wgsl::reader {
 
-/// Builds an core::ir::Module from the given Program
+/// Builds a WGSL-dialect core::ir::Module from the given Program
 /// @param program the Program to use.
-/// @returns the `utiils::Result` of generating the IR. The result will contain the
-/// `core::ir::Module` on success, otherwise the `std::string` error.
+/// @returns the WGSL-dialect IR module.
 ///
 /// @note this assumes the `program.IsValid()`, and has had const-eval done so
 /// any abstract values have been calculated and converted into the relevant
 /// concrete types.
-tint::Result<core::ir::Module, std::string> ProgramToIR(const Program& program);
+tint::Result<core::ir::Module> ProgramToIR(const Program& program);
 
 }  // namespace tint::wgsl::reader
 
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc
index 899bd38..d80a121 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir_test.cc
@@ -60,7 +60,7 @@
     Func("f", tint::Empty, ty.void_(), tint::Empty);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     ASSERT_EQ(1u, m->functions.Length());
 
@@ -81,7 +81,7 @@
     Func("f", Vector{Param("a", ty.u32())}, ty.u32(), Vector{Return("a")});
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     ASSERT_EQ(1u, m->functions.Length());
 
@@ -103,7 +103,7 @@
          ty.void_(), tint::Empty);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     ASSERT_EQ(1u, m->functions.Length());
 
@@ -124,7 +124,7 @@
     Func("f", tint::Empty, ty.void_(), tint::Empty, Vector{Stage(ast::PipelineStage::kFragment)});
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(m->functions[0]->Stage(), core::ir::Function::PipelineStage::kFragment);
 }
@@ -134,7 +134,7 @@
     WrapInFunction(ast_if);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
 
@@ -162,7 +162,7 @@
     WrapInFunction(ast_if);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
 
@@ -187,7 +187,7 @@
     WrapInFunction(ast_if);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
 
@@ -215,7 +215,7 @@
     WrapInFunction(ast_if);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
 
@@ -244,7 +244,7 @@
     WrapInFunction(ast_if);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
 
@@ -275,7 +275,7 @@
     WrapInFunction(ast_loop);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* loop = FindSingleInstruction<core::ir::Loop>(m);
@@ -308,7 +308,7 @@
     WrapInFunction(ast_loop);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* loop = FindSingleInstruction<core::ir::Loop>(m);
@@ -346,7 +346,7 @@
     WrapInFunction(ast_loop);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* loop = FindSingleInstruction<core::ir::Loop>(m);
@@ -380,7 +380,7 @@
     WrapInFunction(ast_loop);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     EXPECT_EQ(Disassemble(m),
@@ -407,7 +407,7 @@
     WrapInFunction(ast_loop);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* loop = FindSingleInstruction<core::ir::Loop>(m);
@@ -444,7 +444,7 @@
     WrapInFunction(ast_loop, If(true, Block(Return())));
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* loop = FindSingleInstruction<core::ir::Loop>(m);
@@ -485,7 +485,7 @@
     WrapInFunction(Block(ast_loop, ast_if));
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* loop = FindSingleInstruction<core::ir::Loop>(m);
@@ -523,7 +523,7 @@
     WrapInFunction(ast_loop);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* loop = FindSingleInstruction<core::ir::Loop>(m);
@@ -573,7 +573,7 @@
     WrapInFunction(ast_loop_a);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -636,7 +636,7 @@
     WrapInFunction(ast_while);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* loop = FindSingleInstruction<core::ir::Loop>(m);
@@ -676,7 +676,7 @@
     WrapInFunction(ast_while);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* loop = FindSingleInstruction<core::ir::Loop>(m);
@@ -716,7 +716,7 @@
     WrapInFunction(ast_for);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* loop = FindSingleInstruction<core::ir::Loop>(m);
@@ -765,7 +765,7 @@
     WrapInFunction(ast_for);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* loop = FindSingleInstruction<core::ir::Loop>(m);
@@ -798,7 +798,7 @@
     WrapInFunction(ast_for);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* loop = FindSingleInstruction<core::ir::Loop>(m);
@@ -830,7 +830,7 @@
     WrapInFunction(ast_switch);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* swtch = FindSingleInstruction<core::ir::Switch>(m);
@@ -881,7 +881,7 @@
     WrapInFunction(ast_switch);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* swtch = FindSingleInstruction<core::ir::Switch>(m);
@@ -920,7 +920,7 @@
     WrapInFunction(ast_switch);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* swtch = FindSingleInstruction<core::ir::Switch>(m);
@@ -953,7 +953,7 @@
     WrapInFunction(ast_switch);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
     auto* swtch = FindSingleInstruction<core::ir::Switch>(m);
@@ -996,7 +996,7 @@
     WrapInFunction(ast_switch, ast_if);
 
     auto res = Build();
-    ASSERT_TRUE(res) << (!res ? res.Failure() : "");
+    ASSERT_TRUE(res) << (!res ? res.Failure() : Failure{});
 
     auto m = res.Move();
 
@@ -1036,7 +1036,7 @@
     WrapInFunction(Ignore(Call("b")));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%b = func():i32 -> %b1 {
@@ -1060,7 +1060,7 @@
          ty.vec4<f32>(), Vector{Return("a")}, Vector{Stage(ast::PipelineStage::kFragment)},
          Vector{Location(1_i)});
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(
         Disassemble(m.Get()),
@@ -1077,7 +1077,7 @@
          Vector{Stage(ast::PipelineStage::kFragment)}, Vector{Location(1_i)});
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%f = @fragment func(%a:f32 [@location(2)]):f32 [@location(1)] -> %b1 {
@@ -1097,7 +1097,7 @@
          Vector{Location(1_i)});
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(
         Disassemble(m.Get()),
@@ -1117,7 +1117,7 @@
          Vector{Location(1_i)});
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(
         Disassemble(m.Get()),
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/shadowing_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/shadowing_test.cc
index 96c3cb2..0ee2cc4 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/shadowing_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/shadowing_test.cc
@@ -44,7 +44,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 S = struct @align(4) {
@@ -73,7 +73,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 S = struct @align(4) {
@@ -100,7 +100,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %b1 = block {  # root
@@ -133,7 +133,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %b1 = block {  # root
@@ -166,7 +166,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %f = func():i32 -> %b1 {
@@ -206,7 +206,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %f = func():i32 -> %b1 {
@@ -241,7 +241,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %f = func():i32 -> %b1 {
@@ -288,7 +288,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %f = func():i32 -> %b1 {
@@ -332,7 +332,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %f = func():i32 -> %b1 {
@@ -376,7 +376,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %f = func():i32 -> %b1 {
@@ -420,7 +420,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %f = func():i32 -> %b1 {
@@ -468,7 +468,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %f = func():i32 -> %b1 {
@@ -519,7 +519,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %f = func():i32 -> %b1 {
@@ -574,7 +574,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %f = func():i32 -> %b1 {
@@ -628,7 +628,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %f = func():i32 -> %b1 {
@@ -679,7 +679,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %f = func():i32 -> %b1 {
@@ -729,7 +729,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %f = func():i32 -> %b1 {
@@ -778,7 +778,7 @@
 }
 )");
 
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ("\n" + Disassemble(m.Get()), R"(
 %f = func():i32 -> %b1 {
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/store_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/store_test.cc
index 6c6ba47..93de171 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/store_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/store_test.cc
@@ -32,7 +32,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %a:ptr<private, u32, read_write> = var
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/unary_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/unary_test.cc
index ef9ada9..7e908a4 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/unary_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/unary_test.cc
@@ -31,7 +31,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():bool -> %b1 {
   %b1 = block {
@@ -54,7 +54,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():vec4<bool> -> %b1 {
   %b1 = block {
@@ -77,7 +77,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():u32 -> %b1 {
   %b1 = block {
@@ -100,7 +100,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%my_func = func():i32 -> %b1 {
   %b1 = block {
@@ -124,7 +124,7 @@
     WrapInFunction(expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %v1:ptr<private, i32, read_write> = var
@@ -148,7 +148,7 @@
     WrapInFunction(stmts);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %v1:ptr<private, i32, read_write> = var
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/var_test.cc b/src/tint/lang/wgsl/reader/program_to_ir/var_test.cc
index cd43cff..e5518c5 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/var_test.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/var_test.cc
@@ -30,7 +30,7 @@
     GlobalVar("a", ty.u32(), core::AddressSpace::kPrivate);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %a:ptr<private, u32, read_write> = var
@@ -44,7 +44,7 @@
     GlobalVar("a", ty.u32(), core::AddressSpace::kPrivate, expr);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %a:ptr<private, u32, read_write> = var, 2u
@@ -57,7 +57,7 @@
     GlobalVar("a", ty.u32(), core::AddressSpace::kStorage, Vector{Group(2_u), Binding(3_u)});
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()), R"(%b1 = block {  # root
   %a:ptr<storage, u32, read> = var @binding_point(2, 3)
@@ -71,7 +71,7 @@
     WrapInFunction(a);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -89,7 +89,7 @@
     WrapInFunction(a);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -107,7 +107,7 @@
     WrapInFunction(a, b);
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -127,7 +127,7 @@
                    Assign("a", 42_i));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -164,7 +164,7 @@
         Assign(lhs, rhs));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%f = func(%p:i32):i32 -> %b1 {
@@ -210,7 +210,7 @@
                    Assign(lhs, rhs));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%f = func(%p:i32):i32 -> %b1 {
@@ -258,7 +258,7 @@
                    Assign(lhs, rhs));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%f = func(%p:i32):i32 -> %b1 {
@@ -290,7 +290,7 @@
                    CompoundAssign("a", 42_i, core::BinaryOp::kAdd));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%test_function = @compute @workgroup_size(1, 1, 1) func():void -> %b1 {
@@ -329,7 +329,7 @@
         CompoundAssign(lhs, rhs, core::BinaryOp::kAdd));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%f = func(%p:i32):i32 -> %b1 {
@@ -381,7 +381,7 @@
                    CompoundAssign(lhs, rhs, core::BinaryOp::kAdd));
 
     auto m = Build();
-    ASSERT_TRUE(m) << (!m ? m.Failure() : "");
+    ASSERT_TRUE(m) << m;
 
     EXPECT_EQ(Disassemble(m.Get()),
               R"(%f = func(%p:i32):i32 -> %b1 {
diff --git a/src/tint/lang/wgsl/reader/reader.cc b/src/tint/lang/wgsl/reader/reader.cc
index beec36b..fac4300 100644
--- a/src/tint/lang/wgsl/reader/reader.cc
+++ b/src/tint/lang/wgsl/reader/reader.cc
@@ -16,15 +16,30 @@
 
 #include <utility>
 
+#include "src/tint/lang/wgsl/reader/lower/lower.h"
 #include "src/tint/lang/wgsl/reader/parser/parser.h"
+#include "src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h"
 #include "src/tint/lang/wgsl/resolver/resolve.h"
 
 namespace tint::wgsl::reader {
 
-Program Parse(Source::File const* file) {
+Program Parse(const Source::File* file) {
     Parser parser(file);
     parser.Parse();
     return resolver::Resolve(parser.builder());
 }
 
+Result<core::ir::Module> WgslToIR(const Source::File* file) {
+    Program program = Parse(file);
+    auto module = ProgramToIR(program);
+    if (!module) {
+        return module.Failure();
+    }
+    // WGSL-dialect -> core-dialect
+    if (auto res = Lower(module.Get()); !res) {
+        return res.Failure();
+    }
+    return module;
+}
+
 }  // namespace tint::wgsl::reader
diff --git a/src/tint/lang/wgsl/reader/reader.h b/src/tint/lang/wgsl/reader/reader.h
index 4c96cb0..691b425 100644
--- a/src/tint/lang/wgsl/reader/reader.h
+++ b/src/tint/lang/wgsl/reader/reader.h
@@ -15,6 +15,7 @@
 #ifndef SRC_TINT_LANG_WGSL_READER_READER_H_
 #define SRC_TINT_LANG_WGSL_READER_READER_H_
 
+#include "src/tint/lang/core/ir/module.h"
 #include "src/tint/lang/wgsl/program/program.h"
 
 namespace tint::wgsl::reader {
@@ -25,7 +26,12 @@
 /// `program.Diagnostics()` will describe the error.
 /// @param file the source file
 /// @returns the parsed program
-Program Parse(Source::File const* file);
+Program Parse(const Source::File* file);
+
+/// Parse a WGSL program from source, and return an IR module.
+/// @param file the input WGSL file
+/// @returns the resulting IR module, or failure
+Result<core::ir::Module> WgslToIR(const Source::File* file);
 
 }  // namespace tint::wgsl::reader
 
diff --git a/src/tint/lang/wgsl/resolver/BUILD.bazel b/src/tint/lang/wgsl/resolver/BUILD.bazel
index ffcbc6c..aebd08e 100644
--- a/src/tint/lang/wgsl/resolver/BUILD.bazel
+++ b/src/tint/lang/wgsl/resolver/BUILD.bazel
@@ -136,6 +136,7 @@
     "//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/core/type:test",
     "//src/tint/lang/wgsl",
diff --git a/src/tint/lang/wgsl/resolver/BUILD.cmake b/src/tint/lang/wgsl/resolver/BUILD.cmake
index bd4bf3b..e74ab6e 100644
--- a/src/tint/lang/wgsl/resolver/BUILD.cmake
+++ b/src/tint/lang/wgsl/resolver/BUILD.cmake
@@ -135,6 +135,7 @@
   tint_lang_core
   tint_lang_core_constant
   tint_lang_core_intrinsic
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_core_type_test
   tint_lang_wgsl
diff --git a/src/tint/lang/wgsl/resolver/BUILD.gn b/src/tint/lang/wgsl/resolver/BUILD.gn
index ef3752b..9fd29ec 100644
--- a/src/tint/lang/wgsl/resolver/BUILD.gn
+++ b/src/tint/lang/wgsl/resolver/BUILD.gn
@@ -138,6 +138,7 @@
       "${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/core/type:unittests",
       "${tint_src_dir}/lang/wgsl",
diff --git a/src/tint/lang/wgsl/resolver/builtin_test.cc b/src/tint/lang/wgsl/resolver/builtin_test.cc
index f4175a8..b315974 100644
--- a/src/tint/lang/wgsl/resolver/builtin_test.cc
+++ b/src/tint/lang/wgsl/resolver/builtin_test.cc
@@ -55,7 +55,7 @@
 
 struct BuiltinData {
     const char* name;
-    core::BuiltinFn builtin;
+    wgsl::BuiltinFn builtin;
 };
 
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
@@ -78,9 +78,9 @@
     // let a = select(1_i, 2_i, true);
     // let b = select(3_i, 4_i, false);
     // let c = select(5_u, 6_u, true);
-    auto* select_a = Call(core::BuiltinFn::kSelect, 1_i, 2_i, true);
-    auto* select_b = Call(core::BuiltinFn::kSelect, 3_i, 4_i, false);
-    auto* select_c = Call(core::BuiltinFn::kSelect, 5_u, 6_u, true);
+    auto* select_a = Call(wgsl::BuiltinFn::kSelect, 1_i, 2_i, true);
+    auto* select_b = Call(wgsl::BuiltinFn::kSelect, 3_i, 4_i, false);
+    auto* select_c = Call(wgsl::BuiltinFn::kSelect, 5_u, 6_u, true);
     WrapInFunction(Decl(Let("i", Expr(42_i))),  //
                    Decl(Let("a", select_a)),    //
                    Decl(Let("b", select_b)),    //
@@ -273,7 +273,7 @@
 struct BuiltinDataWithParamNum {
     uint32_t args_number;
     const char* name;
-    core::BuiltinFn builtin;
+    wgsl::BuiltinFn builtin;
 };
 
 inline std::ostream& operator<<(std::ostream& out, BuiltinDataWithParamNum data) {
@@ -700,55 +700,55 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverTest,
     ResolverBuiltinTest_FloatBuiltin_IdenticalType,
-    testing::Values(BuiltinDataWithParamNum{1, "abs", core::BuiltinFn::kAbs},
-                    BuiltinDataWithParamNum{1, "acos", core::BuiltinFn::kAcos},
-                    BuiltinDataWithParamNum{1, "acosh", core::BuiltinFn::kAcos},
-                    BuiltinDataWithParamNum{1, "asin", core::BuiltinFn::kAsin},
-                    BuiltinDataWithParamNum{1, "asinh", core::BuiltinFn::kAsin},
-                    BuiltinDataWithParamNum{1, "atan", core::BuiltinFn::kAtan},
-                    BuiltinDataWithParamNum{1, "atanh", core::BuiltinFn::kAtan},
-                    BuiltinDataWithParamNum{2, "atan2", core::BuiltinFn::kAtan2},
-                    BuiltinDataWithParamNum{1, "ceil", core::BuiltinFn::kCeil},
-                    BuiltinDataWithParamNum{3, "clamp", core::BuiltinFn::kClamp},
-                    BuiltinDataWithParamNum{1, "cos", core::BuiltinFn::kCos},
-                    BuiltinDataWithParamNum{1, "cosh", core::BuiltinFn::kCosh},
+    testing::Values(BuiltinDataWithParamNum{1, "abs", wgsl::BuiltinFn::kAbs},
+                    BuiltinDataWithParamNum{1, "acos", wgsl::BuiltinFn::kAcos},
+                    BuiltinDataWithParamNum{1, "acosh", wgsl::BuiltinFn::kAcos},
+                    BuiltinDataWithParamNum{1, "asin", wgsl::BuiltinFn::kAsin},
+                    BuiltinDataWithParamNum{1, "asinh", wgsl::BuiltinFn::kAsin},
+                    BuiltinDataWithParamNum{1, "atan", wgsl::BuiltinFn::kAtan},
+                    BuiltinDataWithParamNum{1, "atanh", wgsl::BuiltinFn::kAtan},
+                    BuiltinDataWithParamNum{2, "atan2", wgsl::BuiltinFn::kAtan2},
+                    BuiltinDataWithParamNum{1, "ceil", wgsl::BuiltinFn::kCeil},
+                    BuiltinDataWithParamNum{3, "clamp", wgsl::BuiltinFn::kClamp},
+                    BuiltinDataWithParamNum{1, "cos", wgsl::BuiltinFn::kCos},
+                    BuiltinDataWithParamNum{1, "cosh", wgsl::BuiltinFn::kCosh},
                     // cross: (vec3<T>, vec3<T>) -> vec3<T>
-                    BuiltinDataWithParamNum{1, "degrees", core::BuiltinFn::kDegrees},
+                    BuiltinDataWithParamNum{1, "degrees", wgsl::BuiltinFn::kDegrees},
                     // distance: (T, T) -> T, (vecN<T>, vecN<T>) -> T
-                    BuiltinDataWithParamNum{1, "exp", core::BuiltinFn::kExp},
-                    BuiltinDataWithParamNum{1, "exp2", core::BuiltinFn::kExp2},
+                    BuiltinDataWithParamNum{1, "exp", wgsl::BuiltinFn::kExp},
+                    BuiltinDataWithParamNum{1, "exp2", wgsl::BuiltinFn::kExp2},
                     // faceForward: (vecN<T>, vecN<T>, vecN<T>) -> vecN<T>
-                    BuiltinDataWithParamNum{1, "floor", core::BuiltinFn::kFloor},
-                    BuiltinDataWithParamNum{3, "fma", core::BuiltinFn::kFma},
-                    BuiltinDataWithParamNum{1, "fract", core::BuiltinFn::kFract},
+                    BuiltinDataWithParamNum{1, "floor", wgsl::BuiltinFn::kFloor},
+                    BuiltinDataWithParamNum{3, "fma", wgsl::BuiltinFn::kFma},
+                    BuiltinDataWithParamNum{1, "fract", wgsl::BuiltinFn::kFract},
                     // frexp
-                    BuiltinDataWithParamNum{1, "inverseSqrt", core::BuiltinFn::kInverseSqrt},
+                    BuiltinDataWithParamNum{1, "inverseSqrt", wgsl::BuiltinFn::kInverseSqrt},
                     // ldexp: (T, i32) -> T, (vecN<T>, vecN<i32>) -> vecN<T>
                     // length: (vecN<T>) -> T
-                    BuiltinDataWithParamNum{1, "log", core::BuiltinFn::kLog},
-                    BuiltinDataWithParamNum{1, "log2", core::BuiltinFn::kLog2},
-                    BuiltinDataWithParamNum{2, "max", core::BuiltinFn::kMax},
-                    BuiltinDataWithParamNum{2, "min", core::BuiltinFn::kMin},
+                    BuiltinDataWithParamNum{1, "log", wgsl::BuiltinFn::kLog},
+                    BuiltinDataWithParamNum{1, "log2", wgsl::BuiltinFn::kLog2},
+                    BuiltinDataWithParamNum{2, "max", wgsl::BuiltinFn::kMax},
+                    BuiltinDataWithParamNum{2, "min", wgsl::BuiltinFn::kMin},
                     // Note that `mix(vecN<f32>, vecN<f32>, f32) -> vecN<f32>` is not tested here.
-                    BuiltinDataWithParamNum{3, "mix", core::BuiltinFn::kMix},
+                    BuiltinDataWithParamNum{3, "mix", wgsl::BuiltinFn::kMix},
                     // modf
                     // normalize: (vecN<T>) -> vecN<T>
-                    BuiltinDataWithParamNum{2, "pow", core::BuiltinFn::kPow},
+                    BuiltinDataWithParamNum{2, "pow", wgsl::BuiltinFn::kPow},
                     // quantizeToF16 is not implemented yet.
-                    BuiltinDataWithParamNum{1, "radians", core::BuiltinFn::kRadians},
+                    BuiltinDataWithParamNum{1, "radians", wgsl::BuiltinFn::kRadians},
                     // reflect: (vecN<T>, vecN<T>) -> vecN<T>
                     // refract: (vecN<T>, vecN<T>, T) -> vecN<T>
-                    BuiltinDataWithParamNum{1, "round", core::BuiltinFn::kRound},
+                    BuiltinDataWithParamNum{1, "round", wgsl::BuiltinFn::kRound},
                     // saturate not implemented yet.
-                    BuiltinDataWithParamNum{1, "sign", core::BuiltinFn::kSign},
-                    BuiltinDataWithParamNum{1, "sin", core::BuiltinFn::kSin},
-                    BuiltinDataWithParamNum{1, "sinh", core::BuiltinFn::kSinh},
-                    BuiltinDataWithParamNum{3, "smoothstep", core::BuiltinFn::kSmoothstep},
-                    BuiltinDataWithParamNum{1, "sqrt", core::BuiltinFn::kSqrt},
-                    BuiltinDataWithParamNum{2, "step", core::BuiltinFn::kStep},
-                    BuiltinDataWithParamNum{1, "tan", core::BuiltinFn::kTan},
-                    BuiltinDataWithParamNum{1, "tanh", core::BuiltinFn::kTanh},
-                    BuiltinDataWithParamNum{1, "trunc", core::BuiltinFn::kTrunc}));
+                    BuiltinDataWithParamNum{1, "sign", wgsl::BuiltinFn::kSign},
+                    BuiltinDataWithParamNum{1, "sin", wgsl::BuiltinFn::kSin},
+                    BuiltinDataWithParamNum{1, "sinh", wgsl::BuiltinFn::kSinh},
+                    BuiltinDataWithParamNum{3, "smoothstep", wgsl::BuiltinFn::kSmoothstep},
+                    BuiltinDataWithParamNum{1, "sqrt", wgsl::BuiltinFn::kSqrt},
+                    BuiltinDataWithParamNum{2, "step", wgsl::BuiltinFn::kStep},
+                    BuiltinDataWithParamNum{1, "tan", wgsl::BuiltinFn::kTan},
+                    BuiltinDataWithParamNum{1, "tanh", wgsl::BuiltinFn::kTanh},
+                    BuiltinDataWithParamNum{1, "trunc", wgsl::BuiltinFn::kTrunc}));
 
 using ResolverBuiltinFloatTest = ResolverTest;
 
@@ -1430,7 +1430,7 @@
 struct BuiltinDataWithParamNum {
     uint32_t args_number;
     const char* name;
-    core::BuiltinFn builtin;
+    wgsl::BuiltinFn builtin;
 };
 
 inline std::ostream& operator<<(std::ostream& out, BuiltinDataWithParamNum data) {
@@ -1826,18 +1826,18 @@
     ResolverTest,
     ResolverBuiltinTest_IntegerBuiltin_IdenticalType,
     testing::Values(
-        BuiltinDataWithParamNum{1, "abs", core::BuiltinFn::kAbs},
-        BuiltinDataWithParamNum{3, "clamp", core::BuiltinFn::kClamp},
-        BuiltinDataWithParamNum{1, "countLeadingZeros", core::BuiltinFn::kCountLeadingZeros},
-        BuiltinDataWithParamNum{1, "countOneBits", core::BuiltinFn::kCountOneBits},
-        BuiltinDataWithParamNum{1, "countTrailingZeros", core::BuiltinFn::kCountTrailingZeros},
+        BuiltinDataWithParamNum{1, "abs", wgsl::BuiltinFn::kAbs},
+        BuiltinDataWithParamNum{3, "clamp", wgsl::BuiltinFn::kClamp},
+        BuiltinDataWithParamNum{1, "countLeadingZeros", wgsl::BuiltinFn::kCountLeadingZeros},
+        BuiltinDataWithParamNum{1, "countOneBits", wgsl::BuiltinFn::kCountOneBits},
+        BuiltinDataWithParamNum{1, "countTrailingZeros", wgsl::BuiltinFn::kCountTrailingZeros},
         // extractBits: (T, u32, u32) -> T
-        BuiltinDataWithParamNum{1, "firstLeadingBit", core::BuiltinFn::kFirstLeadingBit},
-        BuiltinDataWithParamNum{1, "firstTrailingBit", core::BuiltinFn::kFirstTrailingBit},
+        BuiltinDataWithParamNum{1, "firstLeadingBit", wgsl::BuiltinFn::kFirstLeadingBit},
+        BuiltinDataWithParamNum{1, "firstTrailingBit", wgsl::BuiltinFn::kFirstTrailingBit},
         // insertBits: (T, T, u32, u32) -> T
-        BuiltinDataWithParamNum{2, "max", core::BuiltinFn::kMax},
-        BuiltinDataWithParamNum{2, "min", core::BuiltinFn::kMin},
-        BuiltinDataWithParamNum{1, "reverseBits", core::BuiltinFn::kReverseBits}));
+        BuiltinDataWithParamNum{2, "max", wgsl::BuiltinFn::kMax},
+        BuiltinDataWithParamNum{2, "min", wgsl::BuiltinFn::kMin},
+        BuiltinDataWithParamNum{1, "reverseBits", wgsl::BuiltinFn::kReverseBits}));
 
 }  // namespace integer_builtin_tests
 
@@ -2576,8 +2576,8 @@
 TEST_P(ResolverBuiltinTest_DataPacking, InferType) {
     auto param = GetParam();
 
-    bool pack4 = param.builtin == core::BuiltinFn::kPack4X8Snorm ||
-                 param.builtin == core::BuiltinFn::kPack4X8Unorm;
+    bool pack4 = param.builtin == wgsl::BuiltinFn::kPack4X8Snorm ||
+                 param.builtin == wgsl::BuiltinFn::kPack4X8Unorm;
 
     auto* call = pack4 ? Call(param.name, Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f))
                        : Call(param.name, Call<vec2<f32>>(1_f, 2_f));
@@ -2591,8 +2591,8 @@
 TEST_P(ResolverBuiltinTest_DataPacking, Error_IncorrectParamType) {
     auto param = GetParam();
 
-    bool pack4 = param.builtin == core::BuiltinFn::kPack4X8Snorm ||
-                 param.builtin == core::BuiltinFn::kPack4X8Unorm;
+    bool pack4 = param.builtin == wgsl::BuiltinFn::kPack4X8Snorm ||
+                 param.builtin == wgsl::BuiltinFn::kPack4X8Unorm;
 
     auto* call = pack4 ? Call(param.name, Call<vec4<i32>>(1_i, 2_i, 3_i, 4_i))
                        : Call(param.name, Call<vec2<i32>>(1_i, 2_i));
@@ -2617,8 +2617,8 @@
 TEST_P(ResolverBuiltinTest_DataPacking, Error_TooManyParams) {
     auto param = GetParam();
 
-    bool pack4 = param.builtin == core::BuiltinFn::kPack4X8Snorm ||
-                 param.builtin == core::BuiltinFn::kPack4X8Unorm;
+    bool pack4 = param.builtin == wgsl::BuiltinFn::kPack4X8Snorm ||
+                 param.builtin == wgsl::BuiltinFn::kPack4X8Unorm;
 
     auto* call = pack4 ? Call(param.name, Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f), 1_f)
                        : Call(param.name, Call<vec2<f32>>(1_f, 2_f), 1_f);
@@ -2632,11 +2632,11 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverTest,
     ResolverBuiltinTest_DataPacking,
-    testing::Values(BuiltinData{"pack4x8snorm", core::BuiltinFn::kPack4X8Snorm},
-                    BuiltinData{"pack4x8unorm", core::BuiltinFn::kPack4X8Unorm},
-                    BuiltinData{"pack2x16snorm", core::BuiltinFn::kPack2X16Snorm},
-                    BuiltinData{"pack2x16unorm", core::BuiltinFn::kPack2X16Unorm},
-                    BuiltinData{"pack2x16float", core::BuiltinFn::kPack2X16Float}));
+    testing::Values(BuiltinData{"pack4x8snorm", wgsl::BuiltinFn::kPack4X8Snorm},
+                    BuiltinData{"pack4x8unorm", wgsl::BuiltinFn::kPack4X8Unorm},
+                    BuiltinData{"pack2x16snorm", wgsl::BuiltinFn::kPack2X16Snorm},
+                    BuiltinData{"pack2x16unorm", wgsl::BuiltinFn::kPack2X16Unorm},
+                    BuiltinData{"pack2x16float", wgsl::BuiltinFn::kPack2X16Float}));
 
 }  // namespace data_packing_builtin_tests
 
@@ -2647,8 +2647,8 @@
 TEST_P(ResolverBuiltinTest_DataUnpacking, InferType) {
     auto param = GetParam();
 
-    bool pack4 = param.builtin == core::BuiltinFn::kUnpack4X8Snorm ||
-                 param.builtin == core::BuiltinFn::kUnpack4X8Unorm;
+    bool pack4 = param.builtin == wgsl::BuiltinFn::kUnpack4X8Snorm ||
+                 param.builtin == wgsl::BuiltinFn::kUnpack4X8Unorm;
 
     auto* call = Call(param.name, 1_u);
     WrapInFunction(call);
@@ -2666,11 +2666,11 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverTest,
     ResolverBuiltinTest_DataUnpacking,
-    testing::Values(BuiltinData{"unpack4x8snorm", core::BuiltinFn::kUnpack4X8Snorm},
-                    BuiltinData{"unpack4x8unorm", core::BuiltinFn::kUnpack4X8Unorm},
-                    BuiltinData{"unpack2x16snorm", core::BuiltinFn::kUnpack2X16Snorm},
-                    BuiltinData{"unpack2x16unorm", core::BuiltinFn::kUnpack2X16Unorm},
-                    BuiltinData{"unpack2x16float", core::BuiltinFn::kUnpack2X16Float}));
+    testing::Values(BuiltinData{"unpack4x8snorm", wgsl::BuiltinFn::kUnpack4X8Snorm},
+                    BuiltinData{"unpack4x8unorm", wgsl::BuiltinFn::kUnpack4X8Unorm},
+                    BuiltinData{"unpack2x16snorm", wgsl::BuiltinFn::kUnpack2X16Snorm},
+                    BuiltinData{"unpack2x16unorm", wgsl::BuiltinFn::kUnpack2X16Unorm},
+                    BuiltinData{"unpack2x16float", wgsl::BuiltinFn::kUnpack2X16Float}));
 
 }  // namespace data_unpacking_builtin_tests
 
@@ -2703,8 +2703,8 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverTest,
     ResolverBuiltinTest_Barrier,
-    testing::Values(BuiltinData{"storageBarrier", core::BuiltinFn::kStorageBarrier},
-                    BuiltinData{"workgroupBarrier", core::BuiltinFn::kWorkgroupBarrier}));
+    testing::Values(BuiltinData{"storageBarrier", wgsl::BuiltinFn::kStorageBarrier},
+                    BuiltinData{"workgroupBarrier", wgsl::BuiltinFn::kWorkgroupBarrier}));
 
 }  // namespace synchronization_builtin_tests
 
diff --git a/src/tint/lang/wgsl/resolver/dependency_graph.cc b/src/tint/lang/wgsl/resolver/dependency_graph.cc
index baab8cd..e2f25d8 100644
--- a/src/tint/lang/wgsl/resolver/dependency_graph.cc
+++ b/src/tint/lang/wgsl/resolver/dependency_graph.cc
@@ -474,7 +474,7 @@
 
         BuiltinType type = BuiltinType::kNone;
         std::variant<std::monostate,
-                     core::BuiltinFn,
+                     wgsl::BuiltinFn,
                      core::BuiltinType,
                      core::BuiltinValue,
                      core::AddressSpace,
@@ -490,8 +490,8 @@
     /// @returns the builtin info
     DependencyScanner::BuiltinInfo GetBuiltinInfo(Symbol symbol) {
         return builtin_info_map.GetOrCreate(symbol, [&] {
-            if (auto builtin_fn = core::ParseBuiltinFn(symbol.NameView());
-                builtin_fn != core::BuiltinFn::kNone) {
+            if (auto builtin_fn = wgsl::ParseBuiltinFn(symbol.NameView());
+                builtin_fn != wgsl::BuiltinFn::kNone) {
                 return BuiltinInfo{BuiltinType::kFunction, builtin_fn};
             }
             if (auto builtin_ty = core::ParseBuiltinType(symbol.NameView());
@@ -537,7 +537,7 @@
                     break;
                 case BuiltinType::kFunction:
                     graph_.resolved_identifiers.Add(
-                        from, ResolvedIdentifier(builtin_info.Value<core::BuiltinFn>()));
+                        from, ResolvedIdentifier(builtin_info.Value<wgsl::BuiltinFn>()));
                     break;
                 case BuiltinType::kBuiltin:
                     graph_.resolved_identifiers.Add(
@@ -921,7 +921,7 @@
                 return "<unknown>";
             });
     }
-    if (auto builtin_fn = BuiltinFn(); builtin_fn != core::BuiltinFn::kNone) {
+    if (auto builtin_fn = BuiltinFn(); builtin_fn != wgsl::BuiltinFn::kNone) {
         return "builtin function '" + tint::ToString(builtin_fn) + "'";
     }
     if (auto builtin_ty = BuiltinType(); builtin_ty != core::BuiltinType::kUndefined) {
diff --git a/src/tint/lang/wgsl/resolver/dependency_graph.h b/src/tint/lang/wgsl/resolver/dependency_graph.h
index 3755f00..85a91e2 100644
--- a/src/tint/lang/wgsl/resolver/dependency_graph.h
+++ b/src/tint/lang/wgsl/resolver/dependency_graph.h
@@ -19,13 +19,13 @@
 #include <vector>
 
 #include "src/tint/lang/core/access.h"
-#include "src/tint/lang/core/builtin_fn.h"
 #include "src/tint/lang/core/builtin_type.h"
 #include "src/tint/lang/core/builtin_value.h"
 #include "src/tint/lang/core/interpolation_sampling.h"
 #include "src/tint/lang/core/interpolation_type.h"
 #include "src/tint/lang/core/texel_format.h"
 #include "src/tint/lang/wgsl/ast/module.h"
+#include "src/tint/lang/wgsl/builtin_fn.h"
 #include "src/tint/utils/containers/hashmap.h"
 #include "src/tint/utils/diagnostic/diagnostic.h"
 
@@ -43,7 +43,7 @@
 /// - const ast::TypeDecl*  (as const ast::Node*)
 /// - const ast::Variable*  (as const ast::Node*)
 /// - const ast::Function*  (as const ast::Node*)
-/// - core::BuiltinFn
+/// - wgsl::BuiltinFn
 /// - core::Access
 /// - core::AddressSpace
 /// - core::BuiltinType
@@ -74,13 +74,13 @@
         return nullptr;
     }
 
-    /// @return the builtin function if the ResolvedIdentifier holds core::BuiltinFn, otherwise
-    /// core::BuiltinFn::kNone
-    core::BuiltinFn BuiltinFn() const {
-        if (auto n = std::get_if<core::BuiltinFn>(&value_)) {
+    /// @return the builtin function if the ResolvedIdentifier holds wgsl::BuiltinFn, otherwise
+    /// wgsl::BuiltinFn::kNone
+    wgsl::BuiltinFn BuiltinFn() const {
+        if (auto n = std::get_if<wgsl::BuiltinFn>(&value_)) {
             return *n;
         }
-        return core::BuiltinFn::kNone;
+        return wgsl::BuiltinFn::kNone;
     }
 
     /// @return the access if the ResolvedIdentifier holds core::Access, otherwise
@@ -169,7 +169,7 @@
   private:
     std::variant<UnresolvedIdentifier,
                  const ast::Node*,
-                 core::BuiltinFn,
+                 wgsl::BuiltinFn,
                  core::Access,
                  core::AddressSpace,
                  core::BuiltinType,
diff --git a/src/tint/lang/wgsl/resolver/dependency_graph_test.cc b/src/tint/lang/wgsl/resolver/dependency_graph_test.cc
index 605ffe1..5b123e1 100644
--- a/src/tint/lang/wgsl/resolver/dependency_graph_test.cc
+++ b/src/tint/lang/wgsl/resolver/dependency_graph_test.cc
@@ -1178,7 +1178,7 @@
 namespace resolve_to_builtin_func {
 
 using ResolverDependencyGraphResolveToBuiltinFn =
-    ResolverDependencyGraphTestWithParam<std::tuple<SymbolUseKind, core::BuiltinFn>>;
+    ResolverDependencyGraphTestWithParam<std::tuple<SymbolUseKind, wgsl::BuiltinFn>>;
 
 TEST_P(ResolverDependencyGraphResolveToBuiltinFn, Resolve) {
     const auto use = std::get<0>(GetParam());
@@ -1197,17 +1197,17 @@
 INSTANTIATE_TEST_SUITE_P(Types,
                          ResolverDependencyGraphResolveToBuiltinFn,
                          testing::Combine(testing::ValuesIn(kTypeUseKinds),
-                                          testing::ValuesIn(core::kBuiltinFns)));
+                                          testing::ValuesIn(wgsl::kBuiltinFns)));
 
 INSTANTIATE_TEST_SUITE_P(Values,
                          ResolverDependencyGraphResolveToBuiltinFn,
                          testing::Combine(testing::ValuesIn(kValueUseKinds),
-                                          testing::ValuesIn(core::kBuiltinFns)));
+                                          testing::ValuesIn(wgsl::kBuiltinFns)));
 
 INSTANTIATE_TEST_SUITE_P(Functions,
                          ResolverDependencyGraphResolveToBuiltinFn,
                          testing::Combine(testing::ValuesIn(kFuncUseKinds),
-                                          testing::ValuesIn(core::kBuiltinFns)));
+                                          testing::ValuesIn(wgsl::kBuiltinFns)));
 
 }  // namespace resolve_to_builtin_func
 
diff --git a/src/tint/lang/wgsl/resolver/materialize_test.cc b/src/tint/lang/wgsl/resolver/materialize_test.cc
index 6116ada..f4b0ab5 100644
--- a/src/tint/lang/wgsl/resolver/materialize_test.cc
+++ b/src/tint/lang/wgsl/resolver/materialize_test.cc
@@ -953,7 +953,7 @@
             break;
         }
         case Method::kTintMaterializeBuiltin: {
-            auto* call = Call(core::str(core::BuiltinFn::kTintMaterialize), abstract_expr());
+            auto* call = Call(wgsl::BuiltinFn::kTintMaterialize, abstract_expr());
             WrapInFunction(Decl(Const("c", call)));
             break;
         }
diff --git a/src/tint/lang/wgsl/resolver/resolver.cc b/src/tint/lang/wgsl/resolver/resolver.cc
index 8edaf01..e54460b 100644
--- a/src/tint/lang/wgsl/resolver/resolver.cc
+++ b/src/tint/lang/wgsl/resolver/resolver.cc
@@ -1941,7 +1941,7 @@
     for (size_t i = 0, n = std::min(args.Length(), target->Parameters().Length()); i < n; i++) {
         if (!Convert(const_args[i], target->Parameters()[i]->Type(),
                      args[i]->Declaration()->source)) {
-            return tint::Failure;
+            return Failure{};
         }
     }
     return const_args;
@@ -2325,7 +2325,7 @@
                 });
         }
 
-        if (auto f = resolved->BuiltinFn(); f != core::BuiltinFn::kNone) {
+        if (auto f = resolved->BuiltinFn(); f != wgsl::BuiltinFn::kNone) {
             if (!TINT_LIKELY(CheckNotTemplated("builtin", ident))) {
                 return nullptr;
             }
@@ -2400,7 +2400,7 @@
 
 template <size_t N>
 sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
-                                 core::BuiltinFn fn,
+                                 wgsl::BuiltinFn fn,
                                  Vector<const sem::ValueExpression*, N>& args) {
     auto arg_stage = core::EvaluationStage::kConstant;
     for (auto* arg : args) {
@@ -2439,7 +2439,7 @@
             flags.Contains(OverloadFlag::kIsDeprecated), flags.Contains(OverloadFlag::kMustUse));
     });
 
-    if (fn == core::BuiltinFn::kTintMaterialize) {
+    if (fn == wgsl::BuiltinFn::kTintMaterialize) {
         args[0] = Materialize(args[0]);
         if (!args[0]) {
             return nullptr;
@@ -2498,13 +2498,13 @@
         CollectTextureSamplerPairs(target, call->Arguments());
     }
 
-    if (fn == core::BuiltinFn::kWorkgroupUniformLoad) {
+    if (fn == wgsl::BuiltinFn::kWorkgroupUniformLoad) {
         if (!validator_.WorkgroupUniformLoad(call)) {
             return nullptr;
         }
     }
 
-    if (fn == core::BuiltinFn::kSubgroupBroadcast) {
+    if (fn == wgsl::BuiltinFn::kSubgroupBroadcast) {
         if (!validator_.SubgroupBroadcast(call)) {
             return nullptr;
         }
@@ -3333,7 +3333,7 @@
         return builder_->create<sem::TypeExpression>(expr, current_statement_, ty);
     }
 
-    if (resolved->BuiltinFn() != core::BuiltinFn::kNone) {
+    if (resolved->BuiltinFn() != wgsl::BuiltinFn::kNone) {
         AddError("missing '(' for builtin function call", expr->source.End());
         return nullptr;
     }
@@ -3739,19 +3739,19 @@
 
     auto* materialized = Materialize(ValueExpression(attr->expr));
     if (!materialized) {
-        return tint::Failure;
+        return Failure{};
     }
 
     if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
         AddError("@location must be an i32 or u32 value", attr->source);
-        return tint::Failure;
+        return Failure{};
     }
 
     auto const_value = materialized->ConstantValue();
     auto value = const_value->ValueAs<AInt>();
     if (value < 0) {
         AddError("@location value must be non-negative", attr->source);
-        return tint::Failure;
+        return Failure{};
     }
 
     return static_cast<uint32_t>(value);
@@ -3763,19 +3763,19 @@
 
     auto* materialized = Materialize(ValueExpression(attr->expr));
     if (!materialized) {
-        return tint::Failure;
+        return Failure{};
     }
 
     if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
         AddError("@location must be an i32 or u32 value", attr->source);
-        return tint::Failure;
+        return Failure{};
     }
 
     auto const_value = materialized->ConstantValue();
     auto value = const_value->ValueAs<AInt>();
     if (value != 0 && value != 1) {
         AddError("@index value must be zero or one", attr->source);
-        return tint::Failure;
+        return Failure{};
     }
 
     return static_cast<uint32_t>(value);
@@ -3787,18 +3787,18 @@
 
     auto* materialized = Materialize(ValueExpression(attr->expr));
     if (!materialized) {
-        return tint::Failure;
+        return Failure{};
     }
     if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
         AddError("@binding must be an i32 or u32 value", attr->source);
-        return tint::Failure;
+        return Failure{};
     }
 
     auto const_value = materialized->ConstantValue();
     auto value = const_value->ValueAs<AInt>();
     if (value < 0) {
         AddError("@binding value must be non-negative", attr->source);
-        return tint::Failure;
+        return Failure{};
     }
     return static_cast<uint32_t>(value);
 }
@@ -3809,18 +3809,18 @@
 
     auto* materialized = Materialize(ValueExpression(attr->expr));
     if (!materialized) {
-        return tint::Failure;
+        return Failure{};
     }
     if (!materialized->Type()->IsAnyOf<core::type::I32, core::type::U32>()) {
         AddError("@group must be an i32 or u32 value", attr->source);
-        return tint::Failure;
+        return Failure{};
     }
 
     auto const_value = materialized->ConstantValue();
     auto value = const_value->ValueAs<AInt>();
     if (value < 0) {
         AddError("@group value must be non-negative", attr->source);
-        return tint::Failure;
+        return Failure{};
     }
     return static_cast<uint32_t>(value);
 }
@@ -3849,18 +3849,18 @@
         }
         const auto* expr = ValueExpression(value);
         if (!expr) {
-            return tint::Failure;
+            return Failure{};
         }
         auto* ty = expr->Type();
         if (!ty->IsAnyOf<core::type::I32, core::type::U32, core::type::AbstractInt>()) {
             AddError(kErrBadExpr, value->source);
-            return tint::Failure;
+            return Failure{};
         }
 
         if (expr->Stage() != core::EvaluationStage::kConstant &&
             expr->Stage() != core::EvaluationStage::kOverride) {
             AddError(kErrBadExpr, value->source);
-            return tint::Failure;
+            return Failure{};
         }
 
         args.Push(expr);
@@ -3871,7 +3871,7 @@
     if (!common_ty) {
         AddError("workgroup_size arguments must be of the same type, either i32 or u32",
                  attr->source);
-        return tint::Failure;
+        return Failure{};
     }
 
     // If all arguments are abstract-integers, then materialize to i32.
@@ -3882,12 +3882,12 @@
     for (size_t i = 0; i < args.Length(); i++) {
         auto* materialized = Materialize(args[i], common_ty);
         if (!materialized) {
-            return tint::Failure;
+            return Failure{};
         }
         if (auto* value = materialized->ConstantValue()) {
             if (value->ValueAs<AInt>() < 1) {
                 AddError("workgroup_size argument must be at least 1", values[i]->source);
-                return tint::Failure;
+                return Failure{};
             }
             ws[i] = value->ValueAs<u32>();
         } else {
@@ -3900,7 +3900,7 @@
         total_size *= static_cast<uint64_t>(ws[i].value_or(1));
         if (total_size > 0xffffffff) {
             AddError("total workgroup grid size cannot exceed 0xffffffff", values[i]->source);
-            return tint::Failure;
+            return Failure{};
         }
     }
 
@@ -3911,7 +3911,7 @@
     const ast::BuiltinAttribute* attr) {
     auto* builtin_expr = BuiltinValueExpression(attr->builtin);
     if (!builtin_expr) {
-        return tint::Failure;
+        return Failure{};
     }
     // Apply the resolved tint::sem::BuiltinEnumExpression<tint::core::BuiltinValue> to the
     // attribute.
@@ -3944,13 +3944,13 @@
     core::Interpolation out;
     auto* type = InterpolationType(attr->type);
     if (!type) {
-        return tint::Failure;
+        return Failure{};
     }
     out.type = type->Value();
     if (attr->sampling) {
         auto* sampling = InterpolationSampling(attr->sampling);
         if (!sampling) {
-            return tint::Failure;
+            return Failure{};
         }
         out.sampling = sampling->Value();
     }
diff --git a/src/tint/lang/wgsl/resolver/resolver.h b/src/tint/lang/wgsl/resolver/resolver.h
index 5dd2029..04c5243 100644
--- a/src/tint/lang/wgsl/resolver/resolver.h
+++ b/src/tint/lang/wgsl/resolver/resolver.h
@@ -212,7 +212,7 @@
     sem::Expression* Identifier(const ast::IdentifierExpression*);
     template <size_t N>
     sem::Call* BuiltinCall(const ast::CallExpression*,
-                           core::BuiltinFn,
+                           wgsl::BuiltinFn,
                            Vector<const sem::ValueExpression*, N>& args);
     sem::ValueExpression* Literal(const ast::LiteralExpression*);
     sem::ValueExpression* MemberAccessor(const ast::MemberAccessorExpression*);
@@ -635,7 +635,7 @@
     Hashset<const ast::Expression*, 8> skip_const_eval_;
     IdentifierResolveHint identifier_resolve_hint_;
     Hashmap<const core::type::Type*, size_t, 8> nest_depth_;
-    Hashmap<std::pair<core::intrinsic::Overload, core::BuiltinFn>, sem::BuiltinFn*, 64> builtins_;
+    Hashmap<std::pair<core::intrinsic::Overload, wgsl::BuiltinFn>, sem::BuiltinFn*, 64> builtins_;
     Hashmap<core::intrinsic::Overload, sem::ValueConstructor*, 16> constructors_;
     Hashmap<core::intrinsic::Overload, sem::ValueConversion*, 16> converters_;
 };
diff --git a/src/tint/lang/wgsl/resolver/uniformity.cc b/src/tint/lang/wgsl/resolver/uniformity.cc
index 0ce82d0..506a20b 100644
--- a/src/tint/lang/wgsl/resolver/uniformity.cc
+++ b/src/tint/lang/wgsl/resolver/uniformity.cc
@@ -1552,12 +1552,12 @@
                 // some texture sampling builtins, and atomics.
                 if (builtin->IsBarrier()) {
                     callsite_tag = {CallSiteTag::CallSiteRequiredToBeUniform, default_severity};
-                } else if (builtin->Fn() == core::BuiltinFn::kWorkgroupUniformLoad) {
+                } else if (builtin->Fn() == wgsl::BuiltinFn::kWorkgroupUniformLoad) {
                     callsite_tag = {CallSiteTag::CallSiteRequiredToBeUniform, default_severity};
                 } else if (builtin->IsDerivative() ||
-                           builtin->Fn() == core::BuiltinFn::kTextureSample ||
-                           builtin->Fn() == core::BuiltinFn::kTextureSampleBias ||
-                           builtin->Fn() == core::BuiltinFn::kTextureSampleCompare) {
+                           builtin->Fn() == wgsl::BuiltinFn::kTextureSample ||
+                           builtin->Fn() == wgsl::BuiltinFn::kTextureSampleBias ||
+                           builtin->Fn() == wgsl::BuiltinFn::kTextureSampleCompare) {
                     // Get the severity of derivative uniformity violations in this context.
                     auto severity = sem_.DiagnosticSeverity(
                         call, wgsl::CoreDiagnosticRule::kDerivativeUniformity);
@@ -1568,7 +1568,7 @@
                 } else if (builtin->IsAtomic()) {
                     callsite_tag = {CallSiteTag::CallSiteNoRestriction};
                     function_tag = ReturnValueMayBeNonUniform;
-                } else if (builtin->Fn() == core::BuiltinFn::kTextureLoad) {
+                } else if (builtin->Fn() == wgsl::BuiltinFn::kTextureLoad) {
                     // Loading from a read-write storage texture may produce a non-uniform value.
                     auto* storage =
                         builtin->Parameters()[0]->Type()->As<core::type::StorageTexture>();
@@ -1670,7 +1670,7 @@
                 }
             } else {
                 auto* builtin = sem->Target()->As<sem::BuiltinFn>();
-                if (builtin && builtin->Fn() == core::BuiltinFn::kWorkgroupUniformLoad) {
+                if (builtin && builtin->Fn() == wgsl::BuiltinFn::kWorkgroupUniformLoad) {
                     // The workgroupUniformLoad builtin requires its parameter to be uniform.
                     current_function_->RequiredToBeUniform(default_severity)->AddEdge(args[i]);
                 } else {
diff --git a/src/tint/lang/wgsl/sem/builtin_fn.cc b/src/tint/lang/wgsl/sem/builtin_fn.cc
index b7c9909..4926c15 100644
--- a/src/tint/lang/wgsl/sem/builtin_fn.cc
+++ b/src/tint/lang/wgsl/sem/builtin_fn.cc
@@ -27,10 +27,10 @@
 namespace tint::sem {
 
 const char* BuiltinFn::str() const {
-    return core::str(fn_);
+    return wgsl::str(fn_);
 }
 
-BuiltinFn::BuiltinFn(core::BuiltinFn type,
+BuiltinFn::BuiltinFn(wgsl::BuiltinFn type,
                      const core::type::Type* return_type,
                      VectorRef<Parameter*> parameters,
                      core::EvaluationStage eval_stage,
@@ -45,51 +45,51 @@
 BuiltinFn::~BuiltinFn() = default;
 
 bool BuiltinFn::IsCoarseDerivative() const {
-    return core::IsCoarseDerivative(fn_);
+    return wgsl::IsCoarseDerivative(fn_);
 }
 
 bool BuiltinFn::IsFineDerivative() const {
-    return core::IsFineDerivative(fn_);
+    return wgsl::IsFineDerivative(fn_);
 }
 
 bool BuiltinFn::IsDerivative() const {
-    return core::IsDerivative(fn_);
+    return wgsl::IsDerivative(fn_);
 }
 
 bool BuiltinFn::IsTexture() const {
-    return core::IsTexture(fn_);
+    return wgsl::IsTexture(fn_);
 }
 
 bool BuiltinFn::IsImageQuery() const {
-    return core::IsImageQuery(fn_);
+    return wgsl::IsImageQuery(fn_);
 }
 
 bool BuiltinFn::IsDataPacking() const {
-    return core::IsDataPacking(fn_);
+    return wgsl::IsDataPacking(fn_);
 }
 
 bool BuiltinFn::IsDataUnpacking() const {
-    return core::IsDataUnpacking(fn_);
+    return wgsl::IsDataUnpacking(fn_);
 }
 
 bool BuiltinFn::IsBarrier() const {
-    return core::IsBarrier(fn_);
+    return wgsl::IsBarrier(fn_);
 }
 
 bool BuiltinFn::IsAtomic() const {
-    return core::IsAtomic(fn_);
+    return wgsl::IsAtomic(fn_);
 }
 
 bool BuiltinFn::IsDP4a() const {
-    return core::IsDP4a(fn_);
+    return wgsl::IsDP4a(fn_);
 }
 
 bool BuiltinFn::IsSubgroup() const {
-    return core::IsSubgroup(fn_);
+    return wgsl::IsSubgroup(fn_);
 }
 
 bool BuiltinFn::HasSideEffects() const {
-    return core::HasSideEffects(fn_);
+    return wgsl::HasSideEffects(fn_);
 }
 
 wgsl::Extension BuiltinFn::RequiredExtension() const {
@@ -99,7 +99,7 @@
     if (IsSubgroup()) {
         return wgsl::Extension::kChromiumExperimentalSubgroups;
     }
-    if (fn_ == core::BuiltinFn::kTextureBarrier) {
+    if (fn_ == wgsl::BuiltinFn::kTextureBarrier) {
         return wgsl::Extension::kChromiumExperimentalReadWriteStorageTexture;
     }
     return wgsl::Extension::kUndefined;
diff --git a/src/tint/lang/wgsl/sem/builtin_fn.h b/src/tint/lang/wgsl/sem/builtin_fn.h
index 525403c..e7b8c8f 100644
--- a/src/tint/lang/wgsl/sem/builtin_fn.h
+++ b/src/tint/lang/wgsl/sem/builtin_fn.h
@@ -18,7 +18,7 @@
 #include <string>
 #include <vector>
 
-#include "src/tint/lang/core/builtin_fn.h"
+#include "src/tint/lang/wgsl/builtin_fn.h"
 #include "src/tint/lang/wgsl/extension.h"
 #include "src/tint/lang/wgsl/sem/call_target.h"
 #include "src/tint/lang/wgsl/sem/pipeline_stage_set.h"
@@ -37,7 +37,7 @@
     /// @param supported_stages the pipeline stages that this builtin can be used in
     /// @param is_deprecated true if the particular overload is considered deprecated
     /// @param must_use true if the builtin was annotated with `@must_use`
-    BuiltinFn(core::BuiltinFn type,
+    BuiltinFn(wgsl::BuiltinFn type,
               const core::type::Type* return_type,
               VectorRef<Parameter*> parameters,
               core::EvaluationStage eval_stage,
@@ -49,7 +49,7 @@
     ~BuiltinFn() override;
 
     /// @return the type of the builtin
-    core::BuiltinFn Fn() const { return fn_; }
+    wgsl::BuiltinFn Fn() const { return fn_; }
 
     /// @return the pipeline stages that this builtin can be used in
     PipelineStageSet SupportedStages() const { return supported_stages_; }
@@ -110,7 +110,7 @@
     }
 
   private:
-    const core::BuiltinFn fn_;
+    const wgsl::BuiltinFn fn_;
     const PipelineStageSet supported_stages_;
     const bool is_deprecated_;
 };
diff --git a/src/tint/lang/wgsl/sem/builtin_fn_test.cc b/src/tint/lang/wgsl/sem/builtin_fn_test.cc
index f10a9f9..2c7a9d1 100644
--- a/src/tint/lang/wgsl/sem/builtin_fn_test.cc
+++ b/src/tint/lang/wgsl/sem/builtin_fn_test.cc
@@ -21,7 +21,7 @@
 
 struct BuiltinData {
     const char* name;
-    core::BuiltinFn builtin;
+    wgsl::BuiltinFn builtin;
 };
 
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
@@ -33,94 +33,94 @@
 
 TEST_P(BuiltinFunctionTest, Parse) {
     auto param = GetParam();
-    EXPECT_EQ(core::ParseBuiltinFn(param.name), param.builtin);
+    EXPECT_EQ(wgsl::ParseBuiltinFn(param.name), param.builtin);
 }
 
 INSTANTIATE_TEST_SUITE_P(
     BuiltinFunctionTest,
     BuiltinFunctionTest,
-    testing::Values(BuiltinData{"abs", core::BuiltinFn::kAbs},
-                    BuiltinData{"acos", core::BuiltinFn::kAcos},
-                    BuiltinData{"all", core::BuiltinFn::kAll},
-                    BuiltinData{"any", core::BuiltinFn::kAny},
-                    BuiltinData{"arrayLength", core::BuiltinFn::kArrayLength},
-                    BuiltinData{"asin", core::BuiltinFn::kAsin},
-                    BuiltinData{"atan", core::BuiltinFn::kAtan},
-                    BuiltinData{"atan2", core::BuiltinFn::kAtan2},
-                    BuiltinData{"ceil", core::BuiltinFn::kCeil},
-                    BuiltinData{"clamp", core::BuiltinFn::kClamp},
-                    BuiltinData{"cos", core::BuiltinFn::kCos},
-                    BuiltinData{"cosh", core::BuiltinFn::kCosh},
-                    BuiltinData{"countOneBits", core::BuiltinFn::kCountOneBits},
-                    BuiltinData{"cross", core::BuiltinFn::kCross},
-                    BuiltinData{"determinant", core::BuiltinFn::kDeterminant},
-                    BuiltinData{"distance", core::BuiltinFn::kDistance},
-                    BuiltinData{"dot", core::BuiltinFn::kDot},
-                    BuiltinData{"dot4I8Packed", core::BuiltinFn::kDot4I8Packed},
-                    BuiltinData{"dot4U8Packed", core::BuiltinFn::kDot4U8Packed},
-                    BuiltinData{"dpdx", core::BuiltinFn::kDpdx},
-                    BuiltinData{"dpdxCoarse", core::BuiltinFn::kDpdxCoarse},
-                    BuiltinData{"dpdxFine", core::BuiltinFn::kDpdxFine},
-                    BuiltinData{"dpdy", core::BuiltinFn::kDpdy},
-                    BuiltinData{"dpdyCoarse", core::BuiltinFn::kDpdyCoarse},
-                    BuiltinData{"dpdyFine", core::BuiltinFn::kDpdyFine},
-                    BuiltinData{"exp", core::BuiltinFn::kExp},
-                    BuiltinData{"exp2", core::BuiltinFn::kExp2},
-                    BuiltinData{"faceForward", core::BuiltinFn::kFaceForward},
-                    BuiltinData{"floor", core::BuiltinFn::kFloor},
-                    BuiltinData{"fma", core::BuiltinFn::kFma},
-                    BuiltinData{"fract", core::BuiltinFn::kFract},
-                    BuiltinData{"frexp", core::BuiltinFn::kFrexp},
-                    BuiltinData{"fwidth", core::BuiltinFn::kFwidth},
-                    BuiltinData{"fwidthCoarse", core::BuiltinFn::kFwidthCoarse},
-                    BuiltinData{"fwidthFine", core::BuiltinFn::kFwidthFine},
-                    BuiltinData{"inverseSqrt", core::BuiltinFn::kInverseSqrt},
-                    BuiltinData{"ldexp", core::BuiltinFn::kLdexp},
-                    BuiltinData{"length", core::BuiltinFn::kLength},
-                    BuiltinData{"log", core::BuiltinFn::kLog},
-                    BuiltinData{"log2", core::BuiltinFn::kLog2},
-                    BuiltinData{"max", core::BuiltinFn::kMax},
-                    BuiltinData{"min", core::BuiltinFn::kMin},
-                    BuiltinData{"mix", core::BuiltinFn::kMix},
-                    BuiltinData{"modf", core::BuiltinFn::kModf},
-                    BuiltinData{"normalize", core::BuiltinFn::kNormalize},
-                    BuiltinData{"pow", core::BuiltinFn::kPow},
-                    BuiltinData{"reflect", core::BuiltinFn::kReflect},
-                    BuiltinData{"reverseBits", core::BuiltinFn::kReverseBits},
-                    BuiltinData{"round", core::BuiltinFn::kRound},
-                    BuiltinData{"select", core::BuiltinFn::kSelect},
-                    BuiltinData{"sign", core::BuiltinFn::kSign},
-                    BuiltinData{"sin", core::BuiltinFn::kSin},
-                    BuiltinData{"sinh", core::BuiltinFn::kSinh},
-                    BuiltinData{"smoothstep", core::BuiltinFn::kSmoothstep},
-                    BuiltinData{"sqrt", core::BuiltinFn::kSqrt},
-                    BuiltinData{"step", core::BuiltinFn::kStep},
-                    BuiltinData{"storageBarrier", core::BuiltinFn::kStorageBarrier},
-                    BuiltinData{"tan", core::BuiltinFn::kTan},
-                    BuiltinData{"tanh", core::BuiltinFn::kTanh},
-                    BuiltinData{"textureDimensions", core::BuiltinFn::kTextureDimensions},
-                    BuiltinData{"textureLoad", core::BuiltinFn::kTextureLoad},
-                    BuiltinData{"textureNumLayers", core::BuiltinFn::kTextureNumLayers},
-                    BuiltinData{"textureNumLevels", core::BuiltinFn::kTextureNumLevels},
-                    BuiltinData{"textureNumSamples", core::BuiltinFn::kTextureNumSamples},
-                    BuiltinData{"textureSample", core::BuiltinFn::kTextureSample},
-                    BuiltinData{"textureSampleBias", core::BuiltinFn::kTextureSampleBias},
-                    BuiltinData{"textureSampleCompare", core::BuiltinFn::kTextureSampleCompare},
+    testing::Values(BuiltinData{"abs", wgsl::BuiltinFn::kAbs},
+                    BuiltinData{"acos", wgsl::BuiltinFn::kAcos},
+                    BuiltinData{"all", wgsl::BuiltinFn::kAll},
+                    BuiltinData{"any", wgsl::BuiltinFn::kAny},
+                    BuiltinData{"arrayLength", wgsl::BuiltinFn::kArrayLength},
+                    BuiltinData{"asin", wgsl::BuiltinFn::kAsin},
+                    BuiltinData{"atan", wgsl::BuiltinFn::kAtan},
+                    BuiltinData{"atan2", wgsl::BuiltinFn::kAtan2},
+                    BuiltinData{"ceil", wgsl::BuiltinFn::kCeil},
+                    BuiltinData{"clamp", wgsl::BuiltinFn::kClamp},
+                    BuiltinData{"cos", wgsl::BuiltinFn::kCos},
+                    BuiltinData{"cosh", wgsl::BuiltinFn::kCosh},
+                    BuiltinData{"countOneBits", wgsl::BuiltinFn::kCountOneBits},
+                    BuiltinData{"cross", wgsl::BuiltinFn::kCross},
+                    BuiltinData{"determinant", wgsl::BuiltinFn::kDeterminant},
+                    BuiltinData{"distance", wgsl::BuiltinFn::kDistance},
+                    BuiltinData{"dot", wgsl::BuiltinFn::kDot},
+                    BuiltinData{"dot4I8Packed", wgsl::BuiltinFn::kDot4I8Packed},
+                    BuiltinData{"dot4U8Packed", wgsl::BuiltinFn::kDot4U8Packed},
+                    BuiltinData{"dpdx", wgsl::BuiltinFn::kDpdx},
+                    BuiltinData{"dpdxCoarse", wgsl::BuiltinFn::kDpdxCoarse},
+                    BuiltinData{"dpdxFine", wgsl::BuiltinFn::kDpdxFine},
+                    BuiltinData{"dpdy", wgsl::BuiltinFn::kDpdy},
+                    BuiltinData{"dpdyCoarse", wgsl::BuiltinFn::kDpdyCoarse},
+                    BuiltinData{"dpdyFine", wgsl::BuiltinFn::kDpdyFine},
+                    BuiltinData{"exp", wgsl::BuiltinFn::kExp},
+                    BuiltinData{"exp2", wgsl::BuiltinFn::kExp2},
+                    BuiltinData{"faceForward", wgsl::BuiltinFn::kFaceForward},
+                    BuiltinData{"floor", wgsl::BuiltinFn::kFloor},
+                    BuiltinData{"fma", wgsl::BuiltinFn::kFma},
+                    BuiltinData{"fract", wgsl::BuiltinFn::kFract},
+                    BuiltinData{"frexp", wgsl::BuiltinFn::kFrexp},
+                    BuiltinData{"fwidth", wgsl::BuiltinFn::kFwidth},
+                    BuiltinData{"fwidthCoarse", wgsl::BuiltinFn::kFwidthCoarse},
+                    BuiltinData{"fwidthFine", wgsl::BuiltinFn::kFwidthFine},
+                    BuiltinData{"inverseSqrt", wgsl::BuiltinFn::kInverseSqrt},
+                    BuiltinData{"ldexp", wgsl::BuiltinFn::kLdexp},
+                    BuiltinData{"length", wgsl::BuiltinFn::kLength},
+                    BuiltinData{"log", wgsl::BuiltinFn::kLog},
+                    BuiltinData{"log2", wgsl::BuiltinFn::kLog2},
+                    BuiltinData{"max", wgsl::BuiltinFn::kMax},
+                    BuiltinData{"min", wgsl::BuiltinFn::kMin},
+                    BuiltinData{"mix", wgsl::BuiltinFn::kMix},
+                    BuiltinData{"modf", wgsl::BuiltinFn::kModf},
+                    BuiltinData{"normalize", wgsl::BuiltinFn::kNormalize},
+                    BuiltinData{"pow", wgsl::BuiltinFn::kPow},
+                    BuiltinData{"reflect", wgsl::BuiltinFn::kReflect},
+                    BuiltinData{"reverseBits", wgsl::BuiltinFn::kReverseBits},
+                    BuiltinData{"round", wgsl::BuiltinFn::kRound},
+                    BuiltinData{"select", wgsl::BuiltinFn::kSelect},
+                    BuiltinData{"sign", wgsl::BuiltinFn::kSign},
+                    BuiltinData{"sin", wgsl::BuiltinFn::kSin},
+                    BuiltinData{"sinh", wgsl::BuiltinFn::kSinh},
+                    BuiltinData{"smoothstep", wgsl::BuiltinFn::kSmoothstep},
+                    BuiltinData{"sqrt", wgsl::BuiltinFn::kSqrt},
+                    BuiltinData{"step", wgsl::BuiltinFn::kStep},
+                    BuiltinData{"storageBarrier", wgsl::BuiltinFn::kStorageBarrier},
+                    BuiltinData{"tan", wgsl::BuiltinFn::kTan},
+                    BuiltinData{"tanh", wgsl::BuiltinFn::kTanh},
+                    BuiltinData{"textureDimensions", wgsl::BuiltinFn::kTextureDimensions},
+                    BuiltinData{"textureLoad", wgsl::BuiltinFn::kTextureLoad},
+                    BuiltinData{"textureNumLayers", wgsl::BuiltinFn::kTextureNumLayers},
+                    BuiltinData{"textureNumLevels", wgsl::BuiltinFn::kTextureNumLevels},
+                    BuiltinData{"textureNumSamples", wgsl::BuiltinFn::kTextureNumSamples},
+                    BuiltinData{"textureSample", wgsl::BuiltinFn::kTextureSample},
+                    BuiltinData{"textureSampleBias", wgsl::BuiltinFn::kTextureSampleBias},
+                    BuiltinData{"textureSampleCompare", wgsl::BuiltinFn::kTextureSampleCompare},
                     BuiltinData{"textureSampleCompareLevel",
-                                core::BuiltinFn::kTextureSampleCompareLevel},
-                    BuiltinData{"textureSampleGrad", core::BuiltinFn::kTextureSampleGrad},
-                    BuiltinData{"textureSampleLevel", core::BuiltinFn::kTextureSampleLevel},
-                    BuiltinData{"trunc", core::BuiltinFn::kTrunc},
-                    BuiltinData{"unpack2x16float", core::BuiltinFn::kUnpack2X16Float},
-                    BuiltinData{"unpack2x16snorm", core::BuiltinFn::kUnpack2X16Snorm},
-                    BuiltinData{"unpack2x16unorm", core::BuiltinFn::kUnpack2X16Unorm},
-                    BuiltinData{"unpack4x8snorm", core::BuiltinFn::kUnpack4X8Snorm},
-                    BuiltinData{"unpack4x8unorm", core::BuiltinFn::kUnpack4X8Unorm},
-                    BuiltinData{"workgroupBarrier", core::BuiltinFn::kWorkgroupBarrier},
-                    BuiltinData{"workgroupUniformLoad", core::BuiltinFn::kWorkgroupUniformLoad}));
+                                wgsl::BuiltinFn::kTextureSampleCompareLevel},
+                    BuiltinData{"textureSampleGrad", wgsl::BuiltinFn::kTextureSampleGrad},
+                    BuiltinData{"textureSampleLevel", wgsl::BuiltinFn::kTextureSampleLevel},
+                    BuiltinData{"trunc", wgsl::BuiltinFn::kTrunc},
+                    BuiltinData{"unpack2x16float", wgsl::BuiltinFn::kUnpack2X16Float},
+                    BuiltinData{"unpack2x16snorm", wgsl::BuiltinFn::kUnpack2X16Snorm},
+                    BuiltinData{"unpack2x16unorm", wgsl::BuiltinFn::kUnpack2X16Unorm},
+                    BuiltinData{"unpack4x8snorm", wgsl::BuiltinFn::kUnpack4X8Snorm},
+                    BuiltinData{"unpack4x8unorm", wgsl::BuiltinFn::kUnpack4X8Unorm},
+                    BuiltinData{"workgroupBarrier", wgsl::BuiltinFn::kWorkgroupBarrier},
+                    BuiltinData{"workgroupUniformLoad", wgsl::BuiltinFn::kWorkgroupUniformLoad}));
 
 TEST_F(BuiltinFunctionTest, ParseNoMatch) {
-    EXPECT_EQ(core::ParseBuiltinFn("not_builtin"), core::BuiltinFn::kNone);
+    EXPECT_EQ(wgsl::ParseBuiltinFn("not_builtin"), wgsl::BuiltinFn::kNone);
 }
 
 }  // namespace
diff --git a/src/tint/lang/wgsl/wgsl.def b/src/tint/lang/wgsl/wgsl.def
index 0a40a81..9d6cce6 100644
--- a/src/tint/lang/wgsl/wgsl.def
+++ b/src/tint/lang/wgsl/wgsl.def
@@ -23,6 +23,10 @@
 // from the Dawn source directory.                                            //
 ////////////////////////////////////////////////////////////////////////////////
 
+import "src/tint/lang/core/access.def"
+import "src/tint/lang/core/address_space.def"
+import "src/tint/lang/core/texel_format.def"
+
 ////////////////////////////////////////////////////////////////////////////////
 // Enumerators                                                                //
 ////////////////////////////////////////////////////////////////////////////////
@@ -72,3 +76,902 @@
   // A Chromium-specific extension that enables pixel local storage.
   chromium_experimental_pixel_local
 }
+
+////////////////////////////////////////////////////////////////////////////////
+// WGSL primitive types                                                       //
+// Types may be decorated with @precedence(N) to prioritize which type        //
+// will be picked when multiple types of a matcher match.                     //
+// This is used to ensure that abstract numerical types materialize to the    //
+// concrete type with the lowest conversion rank.                             //
+// Types with higher the precedence values will be matched first.             //
+////////////////////////////////////////////////////////////////////////////////
+
+// https://gpuweb.github.io/gpuweb/wgsl/#plain-types-section
+type bool
+@precedence(5) @display("abstract-int")   type ia
+@precedence(4) @display("abstract-float") type fa
+@precedence(3) type i32
+@precedence(2) type u32
+@precedence(1) type f32
+@precedence(0) type f16
+type vec2<T>
+type vec3<T>
+type vec4<T>
+type mat2x2<T>
+type mat2x3<T>
+type mat2x4<T>
+type mat3x2<T>
+type mat3x3<T>
+type mat3x4<T>
+type mat4x2<T>
+type mat4x3<T>
+type mat4x4<T>
+@display("vec{N}<{T}>")     type vec<N: num, T>
+@display("mat{N}x{M}<{T}>") type mat<N: num, M: num, T>
+type ptr<S: address_space, T, A: access>
+type atomic<T>
+type array<T>
+type sampler
+type sampler_comparison
+type texture_1d<T>
+type texture_2d<T>
+type texture_2d_array<T>
+type texture_3d<T>
+type texture_cube<T>
+type texture_cube_array<T>
+type texture_multisampled_2d<T>
+type texture_depth_2d
+type texture_depth_2d_array
+type texture_depth_cube
+type texture_depth_cube_array
+type texture_depth_multisampled_2d
+type texture_storage_1d<F: texel_format, A: access>
+type texture_storage_2d<F: texel_format, A: access>
+type texture_storage_2d_array<F: texel_format, A: access>
+type texture_storage_3d<F: texel_format, A: access>
+type texture_external
+type packedVec3<T>
+
+@display("__modf_result_{T}")        type __modf_result<T>
+@display("__modf_result_vec{N}_{T}") type __modf_result_vec<N: num, T>
+@display("__frexp_result_{T}")        type __frexp_result<T>
+@display("__frexp_result_vec{N}_{T}") type __frexp_result_vec<N: num, T>
+
+type __atomic_compare_exchange_result<T>
+
+////////////////////////////////////////////////////////////////////////////////
+// Type matchers                                                              //
+//                                                                            //
+// A type matcher that can match one or more types.                           //
+////////////////////////////////////////////////////////////////////////////////
+
+match scalar: ia | fa | f32 | f16 | i32 | u32 | bool
+match concrete_scalar: f32 | f16 | i32 | u32 | bool
+match scalar_no_f32: ia | fa | i32 | f16 | u32 | bool
+match scalar_no_f16: ia | fa | f32 | i32 | u32 | bool
+match scalar_no_i32: ia | fa | f32 | f16 | u32 | bool
+match scalar_no_u32: ia | fa | f32 | f16 | i32 | bool
+match scalar_no_bool: ia | fa | f32 | f16 | i32 | u32
+match fia_fiu32_f16: fa | ia | f32 | i32 | u32 | f16
+match fia_fi32_f16: fa | ia | f32 | i32 | f16
+match fia_fiu32: fa | ia | f32 | i32 | u32
+match fa_f32: fa | f32
+match fa_f32_f16: fa | f32 | f16
+match ia_iu32: ia | i32 | u32
+match ia_i32: ia | i32
+match fiu32_f16: f32 | i32 | u32 | f16
+match fiu32: f32 | i32 | u32
+match fi32_f16: f32 | i32 | f16
+match fi32: f32 | i32
+match f32_f16: f32 | f16
+match iu32: i32 | u32
+
+////////////////////////////////////////////////////////////////////////////////
+// Enum matchers                                                              //
+//                                                                            //
+// A number matcher that can match one or more enumerator values.             //
+// All enumerator values listed in the match declaration need to be from the  //
+// same enum.                                                                 //
+////////////////////////////////////////////////////////////////////////////////
+
+// https://gpuweb.github.io/gpuweb/wgsl/#texel-formats
+match f32_texel_format
+  : texel_format.bgra8unorm
+  | texel_format.rgba8unorm
+  | texel_format.rgba8snorm
+  | texel_format.rgba16float
+  | texel_format.r32float
+  | texel_format.rg32float
+  | texel_format.rgba32float
+match i32_texel_format
+  : texel_format.rgba8sint
+  | texel_format.rgba16sint
+  | texel_format.r32sint
+  | texel_format.rg32sint
+  | texel_format.rgba32sint
+match u32_texel_format
+  : texel_format.rgba8uint
+  | texel_format.rgba16uint
+  | texel_format.r32uint
+  | texel_format.rg32uint
+  | texel_format.rgba32uint
+
+match write: access.write
+match read_write: access.read_write
+match readable
+  : access.read
+  | access.read_write
+match writable
+  : access.write
+  | access.read_write
+
+match function_private_workgroup
+  : address_space.function
+  | address_space.private
+  | address_space.workgroup
+match workgroup_or_storage
+  : address_space.workgroup
+  | address_space.storage
+match storage
+  : address_space.storage
+match workgroup
+  : address_space.workgroup
+
+////////////////////////////////////////////////////////////////////////////////
+// Builtin Functions                                                          //
+//                                                                            //
+// The builtin function declarations below declare all the built-in           //
+// functions supported by the WGSL language. This builtin definition          //
+// language supports simple static-type function declarations, as well as     //
+// single overload declarations that can match a number of different          //
+// argument types via the use of template types and template numbers          //
+//                                                                            //
+// * Basic example:                                                           //
+//                                                                            //
+//    fn isInf(f32) -> bool                                                   //
+//                                                                            //
+//   Declares an overload of the function 'isInf' that accepts a single       //
+//   parameter of type 'f32' and returns a 'bool'.                            //
+//                                                                            //
+// A template type is a type determined by the arguments to the builtin.      //
+//                                                                            //
+// * Template type example without constraint:                                //
+//                                                                            //
+//    fn arrayLength<T>(array<T>) -> u32                                      //
+//                                                                            //
+//    Declares an overload of the function 'arrayLength' that accepts a       //
+//    single argument of an array type with no constraints on the array       //
+//    element type. This overload will always return a value of the same type //
+//    as its single argument.                                                 //
+//                                                                            //
+// * Template type example with constraint:                                   //
+//                                                                            //
+//    fn abs<T: fiu32>(T) -> T                                                //
+//                                                                            //
+//    Declares an overload of the function 'abs' that accepts a single        //
+//    argument of type 'f32', 'i32' or 'u32', which returns a value of the    //
+//    same argument type.                                                     //
+//                                                                            //
+// Similarly a template number is a number or enumerator that is determined   //
+// by the arguments to the builtin.                                           //
+//                                                                            //
+// * Template number example:                                                 //
+//                                                                            //
+//    fn dpdx<N: num>(vec<N, f32>) -> vec<N, f32>                             //
+//                                                                            //
+//    Declares an overload of the function 'dpdx' that accepts a single       //
+//    argument of a variable-sized vector of 'f32', which returns a value of  //
+//    the same argument type.                                                 //
+//                                                                            //
+//                                                                            //
+// Matching algorithm for a single overload:                                  //
+// -----------------------------------------                                  //
+//                                                                            //
+// The goal of matching is to compare a function call's arguments and any     //
+// explicitly provided template types in the program source against an        //
+// overload declaration in this file, and determine if the call satisfies     //
+// the form and type constraints of the overload. If the call matches an      //
+// overload, then the overload is added to the list of 'overload candidates'  //
+// used for overload resolution (described below).                            //
+//                                                                            //
+// Prior to matching an overload, all template types are undefined.           //
+//                                                                            //
+// Template types are first defined with the type of the leftmost argument    //
+// that matches against that template type name. Subsequent arguments that    //
+// attempt to match against the template type name will either reject the     //
+// overload or refine the template, in one of 3 ways:                         //
+// (a) Fail to match, causing the overload to be immediately rejected.        //
+// (b) Match the existing template type, either exactly or via implicit       //
+//     conversion, and overload resolution continues.                         //
+// (c) Match via implicit conversion of the currently defined template type   //
+//     to the argument type. In this situation, the template type is refined  //
+//     with the more constrained argument type, and overload resolution       //
+//     continues.                                                             //
+//                                                                            //
+// To better understand, let's consider the following hypothetical overload   //
+// declaration:                                                               //
+//                                                                            //
+//    fn foo<T: scalar>(T, T);                                                //
+//                                                                            //
+//    T           - is the template type name                                 //
+//    scalar      - is a matcher for the types 'f32', 'i32', 'u32' or 'bool'  //
+//                  (declared above)                                          //
+//    <T: scalar> - declares the template type T, with the constraint that T  //
+//                  must match one of 'f32', 'i32', 'u32' or 'bool'.          //
+//                                                                            //
+// The process for resolving this overload is as follows:                     //
+//                                                                            //
+//   (1) The overload resolver begins by attempting to match the argument     //
+//       types from left to right.                                            //
+//       The first parameter type is compared against the argument type T.    //
+//       As the template type T has not been defined yet, T is defined as the //
+//       type of the first argument.                                          //
+//       There's no verification that the T type is a scalar at this stage.   //
+//   (2) The second parameter is then compared against the second argument.   //
+//       As the template type T is now defined the argument type is compared  //
+//       against the value of the defined type of T. Depending on the         //
+//       comparison of the argument type to the template type, either the     //
+//       actions of (a), (b) or (c) from above will occur.                    //
+//   (3) If all the parameters matched, constraints on the template types     //
+//       need to be checked next. If the defined type does not match the      //
+//       'match' constraint, then the overload is no longer considered.       //
+//                                                                            //
+// This algorithm for matching a single overload is less general than the     //
+// algorithm described in the WGSL spec.  But it makes the same decisions     //
+// because the overloads defined by WGSL are monotonic in the sense that once //
+// a template parameter has been refined, there is never a need to backtrack  //
+// and un-refine it to match a later argument.                                //
+//                                                                            //
+// The algorithm for matching template numbers is similar to matching         //
+// template types, except numbers need to exactly match across all uses -     //
+// there is no implicit conversion. Template numbers may match integer        //
+// numbers or enumerators.                                                    //
+//                                                                            //
+//                                                                            //
+// Overload resolution for candidate overloads                                //
+// -------------------------------------------                                //
+//                                                                            //
+// If multiple candidate overloads match a given set of arguments, then a     //
+// final overload resolution pass needs to be performed. The arguments and    //
+// overload parameter types for each candidate overload are compared,         //
+// following the algorithm described at:                                      //
+//   https://www.w3.org/TR/WGSL/#overload-resolution-section                  //
+//                                                                            //
+// If the candidate list contains a single entry, then that single candidate  //
+// is picked, and no overload resolution needs to be performed.               //
+//                                                                            //
+// If the candidate list is empty, then the call fails to resolve and an      //
+// error diagnostic is raised.                                                //
+//                                                                            //
+//                                                                            //
+// More examples                                                              //
+// -------------                                                              //
+//                                                                            //
+//   fn F()                                                                   //
+//     - Function called F.                                                   //
+//       No template types or numbers, no parameters, no return value         //
+//                                                                            //
+//   fn F() -> RETURN_TYPE                                                    //
+//     - Function with RETURN_TYPE as the return type value                   //
+//                                                                            //
+//   fn F(f32, i32)                                                           //
+//     - Two fixed-type, anonymous parameters                                 //
+//                                                                            //
+//   fn F(USAGE : f32)                                                        //
+//     - Single parameter with name USAGE.                                    //
+//       Note: Parameter names are used by Tint to infer parameter order for  //
+//       some builtin functions                                               //
+//                                                                            //
+//   fn F<T>(T)                                                               //
+//     - Single parameter of unconstrained template type T (any type)         //
+//                                                                            //
+//   fn F<T: scalar>(T)                                                       //
+//     - Single parameter of constrained template type T (must be a scalar)   //
+//                                                                            //
+//   fn F<T: fiu32>(T) -> T                                                   //
+//     - Single parameter of constrained template type T (must be a one of    //
+//       fiu32) Return type matches parameter type                            //
+//                                                                            //
+//   fn F<T, N: num>(vec<N, T>)                                               //
+//     - Single parameter of vector type with template number size N and      //
+//       element template type T                                              //
+//                                                                            //
+//   fn F<A: access>(texture_storage_1d<f32_texel_format, A>)                 //
+//     - Single parameter of texture_storage_1d type with template number     //
+//       access-control C, and of a texel format that is listed in            //
+//       f32_texel_format                                                     //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+// https://gpuweb.github.io/gpuweb/wgsl/#builtin-functions
+@must_use @const fn abs<T: fia_fiu32_f16>(T) -> T
+@must_use @const fn abs<N: num, T: fia_fiu32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn acos<T: fa_f32_f16>(@test_value(0.96891242171) T) -> T
+@must_use @const fn acos<N: num, T: fa_f32_f16>(@test_value(0.96891242171) vec<N, T>) -> vec<N, T>
+@must_use @const fn acosh<T: fa_f32_f16>(@test_value(1.5430806348) T) -> T
+@must_use @const fn acosh<N: num, T: fa_f32_f16>(@test_value(1.5430806348) vec<N, T>) -> vec<N, T>
+@must_use @const fn all(bool) -> bool
+@must_use @const fn all<N: num>(vec<N, bool>) -> bool
+@must_use @const fn any(bool) -> bool
+@must_use @const fn any<N: num>(vec<N, bool>) -> bool
+@must_use fn arrayLength<T, A: access>(ptr<storage, array<T>, A>) -> u32
+@must_use @const fn asin<T: fa_f32_f16>(@test_value(0.479425538604) T) -> T
+@must_use @const fn asin<N: num, T: fa_f32_f16>(@test_value(0.479425538604) vec<N, T>) -> vec<N, T>
+@must_use @const fn asinh<T: fa_f32_f16>(T) -> T
+@must_use @const fn asinh<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn atan<T: fa_f32_f16>(T) -> T
+@must_use @const fn atan<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn atan2<T: fa_f32_f16>(T, T) -> T
+@must_use @const fn atan2<T: fa_f32_f16, N: num>(vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn atanh<T: fa_f32_f16>(@test_value(0.5) T) -> T
+@must_use @const fn atanh<N: num, T: fa_f32_f16>(@test_value(0.5) vec<N, T>) -> vec<N, T>
+@must_use @const fn ceil<T: fa_f32_f16>(@test_value(1.5) T) -> T
+@must_use @const fn ceil<N: num, T: fa_f32_f16>(@test_value(1.5) vec<N, T>) -> vec<N, T>
+@must_use @const fn clamp<T: fia_fiu32_f16>(T, T, T) -> T
+@must_use @const fn clamp<T: fia_fiu32_f16, N: num>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn cos<T: fa_f32_f16>(@test_value(0) T) -> T
+@must_use @const fn cos<N: num, T: fa_f32_f16>(@test_value(0) vec<N, T>) -> vec<N, T>
+@must_use @const fn cosh<T: fa_f32_f16>(@test_value(0) T) -> T
+@must_use @const fn cosh<N: num, T: fa_f32_f16>(@test_value(0) vec<N, T>) -> vec<N, T>
+@must_use @const fn countLeadingZeros<T: iu32>(T) -> T
+@must_use @const fn countLeadingZeros<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
+@must_use @const fn countOneBits<T: iu32>(T) -> T
+@must_use @const fn countOneBits<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
+@must_use @const fn countTrailingZeros<T: iu32>(T) -> T
+@must_use @const fn countTrailingZeros<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
+@must_use @const fn cross<T: fa_f32_f16>(vec3<T>, vec3<T>) -> vec3<T>
+@must_use @const fn degrees<T: fa_f32_f16>(T) -> T
+@must_use @const fn degrees<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn determinant<N: num, T: fa_f32_f16>(mat<N, N, T>) -> T
+@must_use @const fn distance<T: fa_f32_f16>(T, T) -> T
+@must_use @const fn distance<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>) -> T
+@must_use @const fn dot<N: num, T: fia_fiu32_f16>(vec<N, T>, vec<N, T>) -> T
+@must_use fn dot4I8Packed(u32, u32) -> i32
+@must_use fn dot4U8Packed(u32, u32) -> u32
+@must_use @stage("fragment") fn dpdx(f32) -> f32
+@must_use @stage("fragment") fn dpdx<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @stage("fragment") fn dpdxCoarse(f32) -> f32
+@must_use @stage("fragment") fn dpdxCoarse<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @stage("fragment") fn dpdxFine(f32) -> f32
+@must_use @stage("fragment") fn dpdxFine<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @stage("fragment") fn dpdy(f32) -> f32
+@must_use @stage("fragment") fn dpdy<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @stage("fragment") fn dpdyCoarse(f32) -> f32
+@must_use @stage("fragment") fn dpdyCoarse<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @stage("fragment") fn dpdyFine(f32) -> f32
+@must_use @stage("fragment") fn dpdyFine<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @const fn exp<T: fa_f32_f16>(T) -> T
+@must_use @const fn exp<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn exp2<T: fa_f32_f16>(T) -> T
+@must_use @const fn exp2<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn extractBits<T: iu32>(T, u32, u32) -> T
+@must_use @const fn extractBits<N: num, T: iu32>(vec<N, T>, u32, u32) -> vec<N, T>
+@must_use @const fn faceForward<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn firstLeadingBit<T: iu32>(T) -> T
+@must_use @const fn firstLeadingBit<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
+@must_use @const fn firstTrailingBit<T: iu32>(T) -> T
+@must_use @const fn firstTrailingBit<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
+@must_use @const fn floor<T: fa_f32_f16>(@test_value(1.5) T) -> T
+@must_use @const fn floor<N: num, T: fa_f32_f16>(@test_value(1.5) vec<N, T>) -> vec<N, T>
+@must_use @const fn fma<T: fa_f32_f16>(T, T, T) -> T
+@must_use @const fn fma<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn fract<T: fa_f32_f16>(@test_value(1.25) T) -> T
+@must_use @const fn fract<N: num, T: fa_f32_f16>(@test_value(1.25) vec<N, T>) -> vec<N, T>
+@must_use @const fn frexp<T: fa_f32_f16>(T) -> __frexp_result<T>
+@must_use @const fn frexp<N: num, T: fa_f32_f16>(vec<N, T>) -> __frexp_result_vec<N, T>
+@must_use @stage("fragment") fn fwidth(f32) -> f32
+@must_use @stage("fragment") fn fwidth<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @stage("fragment") fn fwidthCoarse(f32) -> f32
+@must_use @stage("fragment") fn fwidthCoarse<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @stage("fragment") fn fwidthFine(f32) -> f32
+@must_use @stage("fragment") fn fwidthFine<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @const fn insertBits<T: iu32>(T, T, u32, u32) -> T
+@must_use @const fn insertBits<N: num, T: iu32>(vec<N, T>, vec<N, T>, u32, u32) -> vec<N, T>
+@must_use @const fn inverseSqrt<T: fa_f32_f16>(T) -> T
+@must_use @const fn inverseSqrt<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn ldexp<T: fa_f32_f16, U: ia_i32>(T, U) -> T
+@must_use @const fn ldexp<N: num, T: fa_f32_f16, U: ia_i32>(vec<N, T>, vec<N, U>) -> vec<N, T>
+@must_use @const fn length<T: fa_f32_f16>(@test_value(0.0) T) -> T
+@must_use @const fn length<N: num, T: fa_f32_f16>(@test_value(0.0) vec<N, T>) -> T
+@must_use @const fn log<T: fa_f32_f16>(T) -> T
+@must_use @const fn log<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn log2<T: fa_f32_f16>(T) -> T
+@must_use @const fn log2<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn max<T: fia_fiu32_f16>(T, T) -> T
+@must_use @const fn max<N: num, T: fia_fiu32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn min<T: fia_fiu32_f16>(T, T) -> T
+@must_use @const fn min<N: num, T: fia_fiu32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn mix<T: fa_f32_f16>(T, T, T) -> T
+@must_use @const fn mix<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn mix<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>, T) -> vec<N, T>
+@must_use @const fn modf<T: fa_f32_f16>(@test_value(-1.5) T) -> __modf_result<T>
+@must_use @const fn modf<N: num, T: fa_f32_f16>(@test_value(-1.5) vec<N, T>) -> __modf_result_vec<N, T>
+@must_use @const fn normalize<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn pack2x16float(vec2<f32>) -> u32
+@must_use @const fn pack2x16snorm(vec2<f32>) -> u32
+@must_use @const fn pack2x16unorm(vec2<f32>) -> u32
+@must_use @const fn pack4x8snorm(vec4<f32>) -> u32
+@must_use @const fn pack4x8unorm(vec4<f32>) -> u32
+@must_use @const fn pow<T: fa_f32_f16>(T, T) -> T
+@must_use @const fn pow<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn quantizeToF16(f32) -> f32
+@must_use @const fn quantizeToF16<N: num>(vec<N, f32>) -> vec<N, f32>
+@must_use @const fn radians<T: fa_f32_f16>(T) -> T
+@must_use @const fn radians<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn reflect<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const fn refract<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>, T) -> vec<N, T>
+@must_use @const fn reverseBits<T: iu32>(T) -> T
+@must_use @const fn reverseBits<N: num, T: iu32>(vec<N, T>) -> vec<N, T>
+@must_use @const fn round<T: fa_f32_f16>(@test_value(3.5) T) -> T
+@must_use @const fn round<N: num, T: fa_f32_f16>(@test_value(3.5) vec<N, T>) -> vec<N, T>
+@must_use @const fn saturate<T: fa_f32_f16>(@test_value(2) T) -> T
+@must_use @const fn saturate<T: fa_f32_f16, N: num>(@test_value(2) vec<N, T>) -> vec<N, T>
+@must_use @const("select_bool") fn select<T: scalar>(T, T, bool) -> T
+@must_use @const("select_bool") fn select<T: scalar, N: num>(vec<N, T>, vec<N, T>, bool) -> vec<N, T>
+@must_use @const("select_boolvec") fn select<N: num, T: scalar>(vec<N, T>, vec<N, T>, vec<N, bool>) -> vec<N, T>
+@must_use @const fn sign<T: fia_fi32_f16>(T) -> T
+@must_use @const fn sign<N: num, T: fia_fi32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn sin<T: fa_f32_f16>(@test_value(1.57079632679) T) -> T
+@must_use @const fn sin<N: num, T: fa_f32_f16>(@test_value(1.57079632679) vec<N, T>) -> vec<N, T>
+@must_use @const fn sinh<T: fa_f32_f16>(T) -> T
+@must_use @const fn sinh<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn smoothstep<T: fa_f32_f16>(@test_value(2) T, @test_value(4) T, @test_value(3) T) -> T
+@must_use @const fn smoothstep<N: num, T: fa_f32_f16>(@test_value(2) vec<N, T>, @test_value(4) vec<N, T>, @test_value(3) vec<N, T>) -> vec<N, T>
+@must_use @const fn sqrt<T: fa_f32_f16>(T) -> T
+@must_use @const fn sqrt<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn step<T: fa_f32_f16>(T, T) -> T
+@must_use @const fn step<N: num, T: fa_f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T>
+@stage("compute") fn storageBarrier()
+@must_use @const fn tan<T: fa_f32_f16>(T) -> T
+@must_use @const fn tan<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn tanh<T: fa_f32_f16>(T) -> T
+@must_use @const fn tanh<N: num, T: fa_f32_f16>(vec<N, T>) -> vec<N, T>
+@must_use @const fn transpose<M: num, N: num, T: fa_f32_f16>(mat<M, N, T>) -> mat<N, M, T>
+@must_use @const fn trunc<T: fa_f32_f16>(@test_value(1.5) T) -> T
+@must_use @const fn trunc<N: num, T: fa_f32_f16>(@test_value(1.5) vec<N, T>) -> vec<N, T>
+@must_use @const fn unpack2x16float(u32) -> vec2<f32>
+@must_use @const fn unpack2x16snorm(u32) -> vec2<f32>
+@must_use @const fn unpack2x16unorm(u32) -> vec2<f32>
+@must_use @const fn unpack4x8snorm(u32) -> vec4<f32>
+@must_use @const fn unpack4x8unorm(u32) -> vec4<f32>
+@stage("compute") fn workgroupBarrier()
+@must_use @stage("compute") fn workgroupUniformLoad<T>(ptr<workgroup, T, read_write>) -> T
+
+@stage("compute") fn textureBarrier()
+@must_use fn textureDimensions<T: fiu32>(texture: texture_1d<T>) -> u32
+@must_use fn textureDimensions<T: fiu32, L: iu32>(texture: texture_1d<T>, level: L) -> u32
+@must_use fn textureDimensions<T: fiu32>(texture: texture_2d<T>) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32, L: iu32>(texture: texture_2d<T>, level: L) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32>(texture: texture_2d_array<T>) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32, L: iu32>(texture: texture_2d_array<T>, level: L) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32>(texture: texture_3d<T>) -> vec3<u32>
+@must_use fn textureDimensions<T: fiu32, L: iu32>(texture: texture_3d<T>, level: L) -> vec3<u32>
+@must_use fn textureDimensions<T: fiu32>(texture: texture_cube<T>) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32, L: iu32>(texture: texture_cube<T>, level: L) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32>(texture: texture_cube_array<T>) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32, L: iu32>(texture: texture_cube_array<T>, level: L) -> vec2<u32>
+@must_use fn textureDimensions<T: fiu32>(texture: texture_multisampled_2d<T>) -> vec2<u32>
+@must_use fn textureDimensions(texture: texture_depth_2d) -> vec2<u32>
+@must_use fn textureDimensions<L: iu32>(texture: texture_depth_2d, level: L) -> vec2<u32>
+@must_use fn textureDimensions(texture: texture_depth_2d_array) -> vec2<u32>
+@must_use fn textureDimensions<L: iu32>(texture: texture_depth_2d_array, level: L) -> vec2<u32>
+@must_use fn textureDimensions(texture: texture_depth_cube) -> vec2<u32>
+@must_use fn textureDimensions<L: iu32>(texture: texture_depth_cube, level: L) -> vec2<u32>
+@must_use fn textureDimensions(texture: texture_depth_cube_array) -> vec2<u32>
+@must_use fn textureDimensions<L: iu32>(texture: texture_depth_cube_array, level: L) -> vec2<u32>
+@must_use fn textureDimensions(texture: texture_depth_multisampled_2d) -> vec2<u32>
+@must_use fn textureDimensions<F: texel_format, A: access>(texture: texture_storage_1d<F, A>) -> u32
+@must_use fn textureDimensions<F: texel_format, A: access>(texture: texture_storage_2d<F, A>) -> vec2<u32>
+@must_use fn textureDimensions<F: texel_format, A: access>(texture: texture_storage_2d_array<F, A>) -> vec2<u32>
+@must_use fn textureDimensions<F: texel_format, A: access>(texture: texture_storage_3d<F, A>) -> vec3<u32>
+@must_use fn textureDimensions(texture: texture_external) -> vec2<u32>
+@must_use fn textureGather<T: fiu32, C: iu32>(@const component: C, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>) -> vec4<T>
+@must_use fn textureGather<T: fiu32, C: iu32>(@const component: C, texture: texture_2d<T>, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<T>
+@must_use fn textureGather<T: fiu32, C: iu32, A: iu32>(@const component: C, texture: texture_2d_array<T>, sampler: sampler, coords: vec2<f32>, array_index: A) -> vec4<T>
+@must_use fn textureGather<T: fiu32, C: iu32, A: iu32>(@const component: C, texture: texture_2d_array<T>, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> vec4<T>
+@must_use fn textureGather<T: fiu32, C: iu32>(@const component: C, texture: texture_cube<T>, sampler: sampler, coords: vec3<f32>) -> vec4<T>
+@must_use fn textureGather<T: fiu32, C: iu32, A: iu32>(@const component: C, texture: texture_cube_array<T>, sampler: sampler, coords: vec3<f32>, array_index: A) -> vec4<T>
+@must_use fn textureGather(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
+@must_use fn textureGather(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureGather<A: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A) -> vec4<f32>
+@must_use fn textureGather<A: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureGather(texture: texture_depth_cube, sampler: sampler, coords: vec3<f32>) -> vec4<f32>
+@must_use fn textureGather<A: iu32>(texture: texture_depth_cube_array, sampler: sampler, coords: vec3<f32>, array_index: A) -> vec4<f32>
+@must_use fn textureGatherCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32) -> vec4<f32>
+@must_use fn textureGatherCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureGatherCompare<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32) -> vec4<f32>
+@must_use fn textureGatherCompare<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureGatherCompare(texture: texture_depth_cube, sampler: sampler_comparison, coords: vec3<f32>, depth_ref: f32) -> vec4<f32>
+@must_use fn textureGatherCompare<A: iu32>(texture: texture_depth_cube_array, sampler: sampler_comparison, coords: vec3<f32>, array_index: A, depth_ref: f32) -> vec4<f32>
+@must_use fn textureNumLayers<T: fiu32>(texture: texture_2d_array<T>) -> u32
+@must_use fn textureNumLayers<T: fiu32>(texture: texture_cube_array<T>) -> u32
+@must_use fn textureNumLayers(texture: texture_depth_2d_array) -> u32
+@must_use fn textureNumLayers(texture: texture_depth_cube_array) -> u32
+@must_use fn textureNumLayers<F: texel_format, A: access>(texture: texture_storage_2d_array<F, A>) -> u32
+@must_use fn textureNumLevels<T: fiu32>(texture: texture_1d<T>) -> u32
+@must_use fn textureNumLevels<T: fiu32>(texture: texture_2d<T>) -> u32
+@must_use fn textureNumLevels<T: fiu32>(texture: texture_2d_array<T>) -> u32
+@must_use fn textureNumLevels<T: fiu32>(texture: texture_3d<T>) -> u32
+@must_use fn textureNumLevels<T: fiu32>(texture: texture_cube<T>) -> u32
+@must_use fn textureNumLevels<T: fiu32>(texture: texture_cube_array<T>) -> u32
+@must_use fn textureNumLevels(texture: texture_depth_2d) -> u32
+@must_use fn textureNumLevels(texture: texture_depth_2d_array) -> u32
+@must_use fn textureNumLevels(texture: texture_depth_cube) -> u32
+@must_use fn textureNumLevels(texture: texture_depth_cube_array) -> u32
+@must_use fn textureNumSamples<T: fiu32>(texture: texture_multisampled_2d<T>) -> u32
+@must_use fn textureNumSamples(texture: texture_depth_multisampled_2d) -> u32
+@must_use @stage("fragment") fn textureSample(texture: texture_1d<f32>, sampler: sampler, coords: f32) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, @const offset: vec3<i32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample<A: iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A) -> vec4<f32>
+@must_use @stage("fragment") fn textureSample(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>) -> f32
+@must_use @stage("fragment") fn textureSample(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, @const offset: vec2<i32>) -> f32
+@must_use @stage("fragment") fn textureSample<A: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A) -> f32
+@must_use @stage("fragment") fn textureSample<A: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, @const offset: vec2<i32>) -> f32
+@must_use @stage("fragment") fn textureSample(texture: texture_depth_cube, sampler: sampler, coords: vec3<f32>) -> f32
+@must_use @stage("fragment") fn textureSample<A: iu32>(texture: texture_depth_cube_array, sampler: sampler, coords: vec3<f32>, array_index: A) -> f32
+@must_use @stage("fragment") fn textureSampleBias(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, bias: f32) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleBias(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, bias: f32, @const offset: vec2<i32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleBias<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, bias: f32) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleBias<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, bias: f32, @const offset: vec2<i32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleBias(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, bias: f32) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleBias(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, bias: f32, @const offset: vec3<i32>) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleBias(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>, bias: f32) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleBias<A: iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A, bias: f32) -> vec4<f32>
+@must_use @stage("fragment") fn textureSampleCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32) -> f32
+@must_use @stage("fragment") fn textureSampleCompare(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32, @const offset: vec2<i32>) -> f32
+@must_use @stage("fragment") fn textureSampleCompare<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32) -> f32
+@must_use @stage("fragment") fn textureSampleCompare<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32, @const offset: vec2<i32>) -> f32
+@must_use @stage("fragment") fn textureSampleCompare(texture: texture_depth_cube, sampler: sampler_comparison, coords: vec3<f32>, depth_ref: f32) -> f32
+@must_use @stage("fragment") fn textureSampleCompare<A: iu32>(texture: texture_depth_cube_array, sampler: sampler_comparison, coords: vec3<f32>, array_index: A, depth_ref: f32) -> f32
+@must_use fn textureSampleCompareLevel(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32) -> f32
+@must_use fn textureSampleCompareLevel(texture: texture_depth_2d, sampler: sampler_comparison, coords: vec2<f32>, depth_ref: f32, @const offset: vec2<i32>) -> f32
+@must_use fn textureSampleCompareLevel<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32) -> f32
+@must_use fn textureSampleCompareLevel<A: iu32>(texture: texture_depth_2d_array, sampler: sampler_comparison, coords: vec2<f32>, array_index: A, depth_ref: f32, @const offset: vec2<i32>) -> f32
+@must_use fn textureSampleCompareLevel(texture: texture_depth_cube, sampler: sampler_comparison, coords: vec3<f32>, depth_ref: f32) -> f32
+@must_use fn textureSampleCompareLevel<A: iu32>(texture: texture_depth_cube_array, sampler: sampler_comparison, coords: vec3<f32>, array_index: A, depth_ref: f32) -> f32
+@must_use fn textureSampleGrad(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, ddx: vec2<f32>, ddy: vec2<f32>) -> vec4<f32>
+@must_use fn textureSampleGrad(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, ddx: vec2<f32>, ddy: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureSampleGrad<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, ddx: vec2<f32>, ddy: vec2<f32>) -> vec4<f32>
+@must_use fn textureSampleGrad<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, ddx: vec2<f32>, ddy: vec2<f32>, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureSampleGrad(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, ddx: vec3<f32>, ddy: vec3<f32>) -> vec4<f32>
+@must_use fn textureSampleGrad(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, ddx: vec3<f32>, ddy: vec3<f32>, @const offset: vec3<i32>) -> vec4<f32>
+@must_use fn textureSampleGrad(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>, ddx: vec3<f32>, ddy: vec3<f32>) -> vec4<f32>
+@must_use fn textureSampleGrad<A: iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A, ddx: vec3<f32>, ddy: vec3<f32>) -> vec4<f32>
+@must_use fn textureSampleLevel(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, level: f32) -> vec4<f32>
+@must_use fn textureSampleLevel(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>, level: f32, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureSampleLevel<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, level: f32) -> vec4<f32>
+@must_use fn textureSampleLevel<A: iu32>(texture: texture_2d_array<f32>, sampler: sampler, coords: vec2<f32>, array_index: A, level: f32, @const offset: vec2<i32>) -> vec4<f32>
+@must_use fn textureSampleLevel(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, level: f32) -> vec4<f32>
+@must_use fn textureSampleLevel(texture: texture_3d<f32>, sampler: sampler, coords: vec3<f32>, level: f32, @const offset: vec3<i32>) -> vec4<f32>
+@must_use fn textureSampleLevel(texture: texture_cube<f32>, sampler: sampler, coords: vec3<f32>, level: f32) -> vec4<f32>
+@must_use fn textureSampleLevel<A: iu32>(texture: texture_cube_array<f32>, sampler: sampler, coords: vec3<f32>, array_index: A, level: f32) -> vec4<f32>
+@must_use fn textureSampleLevel<L: iu32>(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, level: L) -> f32
+@must_use fn textureSampleLevel<L: iu32>(texture: texture_depth_2d, sampler: sampler, coords: vec2<f32>, level: L, @const offset: vec2<i32>) -> f32
+@must_use fn textureSampleLevel<A: iu32, L: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, level: L) -> f32
+@must_use fn textureSampleLevel<A: iu32, L: iu32>(texture: texture_depth_2d_array, sampler: sampler, coords: vec2<f32>, array_index: A, level: L, @const offset: vec2<i32>) -> f32
+@must_use fn textureSampleLevel<L: iu32>(texture: texture_depth_cube, sampler: sampler, coords: vec3<f32>, level: L) -> f32
+@must_use fn textureSampleLevel<A: iu32, L: iu32>(texture: texture_depth_cube_array,sampler: sampler, coords: vec3<f32>, array_index: A, level: L) -> f32
+@must_use fn textureSampleBaseClampToEdge(texture: texture_2d<f32>, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
+@must_use fn textureSampleBaseClampToEdge(texture: texture_external, sampler: sampler, coords: vec2<f32>) -> vec4<f32>
+fn textureStore<C: iu32>(texture: texture_storage_1d<f32_texel_format, writable>, coords: C, value: vec4<f32>)
+fn textureStore<C: iu32>(texture: texture_storage_2d<f32_texel_format, writable>, coords: vec2<C>, value: vec4<f32>)
+fn textureStore<C: iu32, A: iu32>(texture: texture_storage_2d_array<f32_texel_format, writable>, coords: vec2<C>, array_index: A, value: vec4<f32>)
+fn textureStore<C: iu32>(texture: texture_storage_3d<f32_texel_format, writable>, coords: vec3<C>, value: vec4<f32>)
+fn textureStore<C: iu32>(texture: texture_storage_1d<i32_texel_format, writable>, coords: C, value: vec4<i32>)
+fn textureStore<C: iu32>(texture: texture_storage_2d<i32_texel_format, writable>, coords: vec2<C>, value: vec4<i32>)
+fn textureStore<C: iu32, A: iu32>(texture: texture_storage_2d_array<i32_texel_format, writable>, coords: vec2<C>, array_index: A, value: vec4<i32>)
+fn textureStore<C: iu32>(texture: texture_storage_3d<i32_texel_format, writable>, coords: vec3<C>, value: vec4<i32>)
+fn textureStore<C: iu32>(texture: texture_storage_1d<u32_texel_format, writable>, coords: C, value: vec4<u32>)
+fn textureStore<C: iu32>(texture: texture_storage_2d<u32_texel_format, writable>, coords: vec2<C>, value: vec4<u32>)
+fn textureStore<C: iu32, A: iu32>(texture: texture_storage_2d_array<u32_texel_format, writable>, coords: vec2<C>, array_index: A, value: vec4<u32>)
+fn textureStore<C: iu32>(texture: texture_storage_3d<u32_texel_format, writable>, coords: vec3<C>, value: vec4<u32>)
+@must_use fn textureLoad<T: fiu32, C: iu32, L: iu32>(texture: texture_1d<T>, coords: C, level: L) -> vec4<T>
+@must_use fn textureLoad<T: fiu32, C: iu32, L: iu32>(texture: texture_2d<T>, coords: vec2<C>, level: L) -> vec4<T>
+@must_use fn textureLoad<T: fiu32, C: iu32, A: iu32, L: iu32>(texture: texture_2d_array<T>, coords: vec2<C>, array_index: A, level: L) -> vec4<T>
+@must_use fn textureLoad<T: fiu32, C: iu32, L: iu32>(texture: texture_3d<T>, coords: vec3<C>, level: L) -> vec4<T>
+@must_use fn textureLoad<T: fiu32, C: iu32, S: iu32>(texture: texture_multisampled_2d<T>, coords: vec2<C>, sample_index: S) -> vec4<T>
+@must_use fn textureLoad<C: iu32, L: iu32>(texture: texture_depth_2d, coords: vec2<C>, level: L) -> f32
+@must_use fn textureLoad<C: iu32, A: iu32, L: iu32>(texture: texture_depth_2d_array, coords: vec2<C>, array_index: A, level: L) -> f32
+@must_use fn textureLoad<C: iu32, S: iu32>(texture: texture_depth_multisampled_2d, coords: vec2<C>, sample_index: S) -> f32
+@must_use fn textureLoad<C: iu32>(texture: texture_external, coords: vec2<C>) -> vec4<f32>
+@must_use fn textureLoad<C: iu32>(texture: texture_storage_1d<f32_texel_format, readable>, coords: C) -> vec4<f32>
+@must_use fn textureLoad<C: iu32>(texture: texture_storage_1d<i32_texel_format, readable>, coords: C) -> vec4<i32>
+@must_use fn textureLoad<C: iu32>(texture: texture_storage_1d<u32_texel_format, readable>, coords: C) -> vec4<u32>
+@must_use fn textureLoad<C: iu32>(texture: texture_storage_2d<f32_texel_format, readable>, coords: vec2<C>) -> vec4<f32>
+@must_use fn textureLoad<C: iu32>(texture: texture_storage_2d<i32_texel_format, readable>, coords: vec2<C>) -> vec4<i32>
+@must_use fn textureLoad<C: iu32>(texture: texture_storage_2d<u32_texel_format, readable>, coords: vec2<C>) -> vec4<u32>
+@must_use fn textureLoad<C: iu32, A: iu32>(texture: texture_storage_2d_array<f32_texel_format, readable>, coords: vec2<C>, array_index: A) -> vec4<f32>
+@must_use fn textureLoad<C: iu32, A: iu32>(texture: texture_storage_2d_array<i32_texel_format, readable>, coords: vec2<C>, array_index: A) -> vec4<i32>
+@must_use fn textureLoad<C: iu32, A: iu32>(texture: texture_storage_2d_array<u32_texel_format, readable>, coords: vec2<C>, array_index: A) -> vec4<u32>
+@must_use fn textureLoad<C: iu32>(texture: texture_storage_3d<f32_texel_format, readable>, coords: vec3<C>) -> vec4<f32>
+@must_use fn textureLoad<C: iu32>(texture: texture_storage_3d<i32_texel_format, readable>, coords: vec3<C>) -> vec4<i32>
+@must_use fn textureLoad<C: iu32>(texture: texture_storage_3d<u32_texel_format, readable>, coords: vec3<C>) -> vec4<u32>
+
+@stage("fragment", "compute") fn atomicLoad<T: iu32, S: workgroup_or_storage>(ptr<S, atomic<T>, read_write>) -> T
+@stage("fragment", "compute") fn atomicStore<T: iu32, S: workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T)
+@stage("fragment", "compute") fn atomicAdd<T: iu32, S: workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T
+@stage("fragment", "compute") fn atomicSub<T: iu32, S: workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T
+@stage("fragment", "compute") fn atomicMax<T: iu32, S: workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T
+@stage("fragment", "compute") fn atomicMin<T: iu32, S: workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T
+@stage("fragment", "compute") fn atomicAnd<T: iu32, S: workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T
+@stage("fragment", "compute") fn atomicOr<T: iu32, S: workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T
+@stage("fragment", "compute") fn atomicXor<T: iu32, S: workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T
+@stage("fragment", "compute") fn atomicExchange<T: iu32, S: workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T
+@stage("fragment", "compute") fn atomicCompareExchangeWeak<T: iu32, S: workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T, T) -> __atomic_compare_exchange_result<T>
+
+@must_use @stage("compute") fn subgroupBallot() -> vec4<u32>
+@must_use @stage("compute") fn subgroupBroadcast<T: fiu32>(value: T, @const sourceLaneIndex: u32) -> T
+
+////////////////////////////////////////////////////////////////////////////////
+// Value constructors                                                         //
+////////////////////////////////////////////////////////////////////////////////
+
+// Zero value constructors
+@must_use @const("Zero") ctor i32() -> i32
+@must_use @const("Zero") ctor u32() -> u32
+@must_use @const("Zero") ctor f32() -> f32
+@must_use @const("Zero") ctor f16() -> f16
+@must_use @const("Zero") ctor bool() -> bool
+@must_use @const("Zero") ctor vec2() -> vec2<ia>
+@must_use @const("Zero") ctor vec3() -> vec3<ia>
+@must_use @const("Zero") ctor vec4() -> vec4<ia>
+@must_use @const("Zero") ctor vec2<T: concrete_scalar>() -> vec2<T>
+@must_use @const("Zero") ctor vec3<T: concrete_scalar>() -> vec3<T>
+@must_use @const("Zero") ctor vec4<T: concrete_scalar>() -> vec4<T>
+@must_use @const("Zero") ctor mat2x2<T: f32_f16>() -> mat2x2<T>
+@must_use @const("Zero") ctor mat2x3<T: f32_f16>() -> mat2x3<T>
+@must_use @const("Zero") ctor mat2x4<T: f32_f16>() -> mat2x4<T>
+@must_use @const("Zero") ctor mat3x2<T: f32_f16>() -> mat3x2<T>
+@must_use @const("Zero") ctor mat3x3<T: f32_f16>() -> mat3x3<T>
+@must_use @const("Zero") ctor mat3x4<T: f32_f16>() -> mat3x4<T>
+@must_use @const("Zero") ctor mat4x2<T: f32_f16>() -> mat4x2<T>
+@must_use @const("Zero") ctor mat4x3<T: f32_f16>() -> mat4x3<T>
+@must_use @const("Zero") ctor mat4x4<T: f32_f16>() -> mat4x4<T>
+
+// Identity constructors
+@must_use @const("Identity") ctor i32(i32) -> i32
+@must_use @const("Identity") ctor u32(u32) -> u32
+@must_use @const("Identity") ctor f32(f32) -> f32
+@must_use @const("Identity") ctor f16(f16) -> f16
+@must_use @const("Identity") ctor bool(bool) -> bool
+@must_use @const("Identity") ctor vec2<T: scalar>(vec2<T>) -> vec2<T>
+@must_use @const("Identity") ctor vec3<T: scalar>(vec3<T>) -> vec3<T>
+@must_use @const("Identity") ctor vec4<T: scalar>(vec4<T>) -> vec4<T>
+@must_use @const("Identity") ctor mat2x2<T: f32_f16>(mat2x2<T>) -> mat2x2<T>
+@must_use @const("Identity") ctor mat2x3<T: f32_f16>(mat2x3<T>) -> mat2x3<T>
+@must_use @const("Identity") ctor mat2x4<T: f32_f16>(mat2x4<T>) -> mat2x4<T>
+@must_use @const("Identity") ctor mat3x2<T: f32_f16>(mat3x2<T>) -> mat3x2<T>
+@must_use @const("Identity") ctor mat3x3<T: f32_f16>(mat3x3<T>) -> mat3x3<T>
+@must_use @const("Identity") ctor mat3x4<T: f32_f16>(mat3x4<T>) -> mat3x4<T>
+@must_use @const("Identity") ctor mat4x2<T: f32_f16>(mat4x2<T>) -> mat4x2<T>
+@must_use @const("Identity") ctor mat4x3<T: f32_f16>(mat4x3<T>) -> mat4x3<T>
+@must_use @const("Identity") ctor mat4x4<T: f32_f16>(mat4x4<T>) -> mat4x4<T>
+
+// Vector constructors (splat)
+@must_use @const("VecSplat") ctor vec2<T: scalar>(T) -> vec2<T>
+@must_use @const("VecSplat") ctor vec3<T: scalar>(T) -> vec3<T>
+@must_use @const("VecSplat") ctor vec4<T: scalar>(T) -> vec4<T>
+
+// Vector constructors (scalar)
+@must_use @const("VecInitS") ctor vec2<T: scalar>(x: T, y: T) -> vec2<T>
+@must_use @const("VecInitS") ctor vec3<T: scalar>(x: T, y: T, z: T) -> vec3<T>
+@must_use @const("VecInitS") ctor vec4<T: scalar>(x: T, y: T, z: T, w: T) -> vec4<T>
+
+// Vector constructors (mixed)
+@must_use @const("VecInitM") ctor vec3<T: scalar>(xy: vec2<T>, z: T) -> vec3<T>
+@must_use @const("VecInitM") ctor vec3<T: scalar>(x: T, yz: vec2<T>) -> vec3<T>
+@must_use @const("VecInitM") ctor vec4<T: scalar>(xy: vec2<T>, z: T, w: T) -> vec4<T>
+@must_use @const("VecInitM") ctor vec4<T: scalar>(x: T, yz: vec2<T>, w: T) -> vec4<T>
+@must_use @const("VecInitM") ctor vec4<T: scalar>(x: T, y: T, zw: vec2<T>) -> vec4<T>
+@must_use @const("VecInitM") ctor vec4<T: scalar>(xy: vec2<T>, zw: vec2<T>) -> vec4<T>
+@must_use @const("VecInitM") ctor vec4<T: scalar>(xyz: vec3<T>, w: T) -> vec4<T>
+@must_use @const("VecInitM") ctor vec4<T: scalar>(x: T, zyw: vec3<T>) -> vec4<T>
+
+// Matrix constructors (scalar)
+@must_use @const("MatInitS")
+ctor mat2x2<T: fa_f32_f16>(T, T,
+                           T, T) -> mat2x2<T>
+@must_use @const("MatInitS")
+ctor mat2x3<T: fa_f32_f16>(T, T, T,
+                           T, T, T) -> mat2x3<T>
+@must_use @const("MatInitS")
+ctor mat2x4<T: fa_f32_f16>(T, T, T, T,
+                           T, T, T, T) -> mat2x4<T>
+@must_use @const("MatInitS")
+ctor mat3x2<T: fa_f32_f16>(T, T,
+                           T, T,
+                           T, T) -> mat3x2<T>
+@must_use @const("MatInitS")
+ctor mat3x3<T: fa_f32_f16>(T, T, T,
+                           T, T, T,
+                           T, T, T) -> mat3x3<T>
+@must_use @const("MatInitS")
+ctor mat3x4<T: fa_f32_f16>(T, T, T, T,
+                           T, T, T, T,
+                           T, T, T, T) -> mat3x4<T>
+@must_use @const("MatInitS")
+ctor mat4x2<T: fa_f32_f16>(T, T,
+                           T, T,
+                           T, T,
+                           T, T) -> mat4x2<T>
+@must_use @const("MatInitS")
+ctor mat4x3<T: fa_f32_f16>(T, T, T,
+                           T, T, T,
+                           T, T, T,
+                           T, T, T) -> mat4x3<T>
+@must_use @const("MatInitS")
+ctor mat4x4<T: fa_f32_f16>(T, T, T, T,
+                           T, T, T, T,
+                           T, T, T, T,
+                           T, T, T, T) -> mat4x4<T>
+
+// Matrix constructors (column vectors)
+@must_use @const("MatInitV") ctor mat2x2<T: fa_f32_f16>(vec2<T>, vec2<T>) -> mat2x2<T>
+@must_use @const("MatInitV") ctor mat2x3<T: fa_f32_f16>(vec3<T>, vec3<T>) -> mat2x3<T>
+@must_use @const("MatInitV") ctor mat2x4<T: fa_f32_f16>(vec4<T>, vec4<T>) -> mat2x4<T>
+@must_use @const("MatInitV") ctor mat3x2<T: fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>) -> mat3x2<T>
+@must_use @const("MatInitV") ctor mat3x3<T: fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>) -> mat3x3<T>
+@must_use @const("MatInitV") ctor mat3x4<T: fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>) -> mat3x4<T>
+@must_use @const("MatInitV") ctor mat4x2<T: fa_f32_f16>(vec2<T>, vec2<T>, vec2<T>, vec2<T>) -> mat4x2<T>
+@must_use @const("MatInitV") ctor mat4x3<T: fa_f32_f16>(vec3<T>, vec3<T>, vec3<T>, vec3<T>) -> mat4x3<T>
+@must_use @const("MatInitV") ctor mat4x4<T: fa_f32_f16>(vec4<T>, vec4<T>, vec4<T>, vec4<T>) -> mat4x4<T>
+
+////////////////////////////////////////////////////////////////////////////////
+// Value conversions                                                          //
+////////////////////////////////////////////////////////////////////////////////
+@must_use @const conv f32<T: scalar_no_f32>(T) -> f32
+@must_use @const conv f16<T: scalar_no_f16>(T) -> f16
+@must_use @const conv i32<T: scalar_no_i32>(T) -> i32
+@must_use @const conv u32<T: scalar_no_u32>(T) -> u32
+@must_use @const conv bool<T: scalar_no_bool>(T) -> bool
+
+@must_use @const conv vec2<T: f32, U: scalar_no_f32>(vec2<U>) -> vec2<f32>
+@must_use @const conv vec2<T: f16, U: scalar_no_f16>(vec2<U>) -> vec2<f16>
+@must_use @const conv vec2<T: i32, U: scalar_no_i32>(vec2<U>) -> vec2<i32>
+@must_use @const conv vec2<T: u32, U: scalar_no_u32>(vec2<U>) -> vec2<u32>
+@must_use @const conv vec2<T: bool, U: scalar_no_bool>(vec2<U>) -> vec2<bool>
+
+@must_use @const conv vec3<T: f32, U: scalar_no_f32>(vec3<U>) -> vec3<f32>
+@must_use @const conv vec3<T: f16, U: scalar_no_f16>(vec3<U>) -> vec3<f16>
+@must_use @const conv vec3<T: i32, U: scalar_no_i32>(vec3<U>) -> vec3<i32>
+@must_use @const conv vec3<T: u32, U: scalar_no_u32>(vec3<U>) -> vec3<u32>
+@must_use @const conv vec3<T: bool, U: scalar_no_bool>(vec3<U>) -> vec3<bool>
+
+@must_use @const conv vec4<T: f32, U: scalar_no_f32>(vec4<U>) -> vec4<f32>
+@must_use @const conv vec4<T: f16, U: scalar_no_f16>(vec4<U>) -> vec4<f16>
+@must_use @const conv vec4<T: i32, U: scalar_no_i32>(vec4<U>) -> vec4<i32>
+@must_use @const conv vec4<T: u32, U: scalar_no_u32>(vec4<U>) -> vec4<u32>
+@must_use @const conv vec4<T: bool, U: scalar_no_bool>(vec4<U>) -> vec4<bool>
+
+@must_use @const conv mat2x2<T: f16>(mat2x2<f32>) -> mat2x2<f16>
+@must_use @const conv mat2x2<T: f32>(mat2x2<f16>) -> mat2x2<f32>
+@must_use @const conv mat2x3<T: f16>(mat2x3<f32>) -> mat2x3<f16>
+@must_use @const conv mat2x3<T: f32>(mat2x3<f16>) -> mat2x3<f32>
+@must_use @const conv mat2x4<T: f16>(mat2x4<f32>) -> mat2x4<f16>
+@must_use @const conv mat2x4<T: f32>(mat2x4<f16>) -> mat2x4<f32>
+@must_use @const conv mat3x2<T: f16>(mat3x2<f32>) -> mat3x2<f16>
+@must_use @const conv mat3x2<T: f32>(mat3x2<f16>) -> mat3x2<f32>
+@must_use @const conv mat3x3<T: f16>(mat3x3<f32>) -> mat3x3<f16>
+@must_use @const conv mat3x3<T: f32>(mat3x3<f16>) -> mat3x3<f32>
+@must_use @const conv mat3x4<T: f16>(mat3x4<f32>) -> mat3x4<f16>
+@must_use @const conv mat3x4<T: f32>(mat3x4<f16>) -> mat3x4<f32>
+@must_use @const conv mat4x2<T: f16>(mat4x2<f32>) -> mat4x2<f16>
+@must_use @const conv mat4x2<T: f32>(mat4x2<f16>) -> mat4x2<f32>
+@must_use @const conv mat4x3<T: f16>(mat4x3<f32>) -> mat4x3<f16>
+@must_use @const conv mat4x3<T: f32>(mat4x3<f16>) -> mat4x3<f32>
+@must_use @const conv mat4x4<T: f16>(mat4x4<f32>) -> mat4x4<f16>
+@must_use @const conv mat4x4<T: f32>(mat4x4<f16>) -> mat4x4<f32>
+
+// Conversion from vec3 to internal __packed_vec3 type.
+@must_use @const conv packedVec3<T: concrete_scalar>(vec3<T>) -> packedVec3<T>
+
+////////////////////////////////////////////////////////////////////////////////
+// Operators                                                                  //
+//                                                                            //
+// The operator declarations below declare all the unary and binary operators //
+// supported by the WGSL language (with exception for address-of and          //
+// dereference unary operators).                                              //
+//                                                                            //
+// The syntax is almost identical to builtin functions, except we use 'op'    //
+// instead of 'fn'. The resolving rules are identical to builtins, which is   //
+// described in detail above.                                                 //
+//                                                                            //
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+// Unary Operators                                                            //
+////////////////////////////////////////////////////////////////////////////////
+@must_use @const op ! (bool) -> bool
+@must_use @const op ! <N: num> (vec<N, bool>) -> vec<N, bool>
+
+@must_use @const op ~ <T: ia_iu32>(T) -> T
+@must_use @const op ~ <T: ia_iu32, N: num> (vec<N, T>) -> vec<N, T>
+
+@must_use @const("UnaryMinus") op - <T: fia_fi32_f16>(T) -> T
+@must_use @const("UnaryMinus") op - <T: fia_fi32_f16, N: num> (vec<N, T>) -> vec<N, T>
+
+////////////////////////////////////////////////////////////////////////////////
+// Binary Operators                                                           //
+////////////////////////////////////////////////////////////////////////////////
+@must_use @const op + <T: fia_fiu32_f16>(T, T) -> T
+@must_use @const op + <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const op + <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
+@must_use @const op + <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
+@must_use @const op + <T: fa_f32_f16, N: num, M: num> (mat<N, M, T>, mat<N, M, T>) -> mat<N, M, T>
+
+@must_use @const op - <T: fia_fiu32_f16>(T, T) -> T
+@must_use @const op - <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const op - <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
+@must_use @const op - <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
+@must_use @const op - <T: fa_f32_f16, N: num, M: num> (mat<N, M, T>, mat<N, M, T>) -> mat<N, M, T>
+
+@must_use @const("Multiply") op * <T: fia_fiu32_f16>(T, T) -> T
+@must_use @const("Multiply") op * <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const("Multiply") op * <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
+@must_use @const("Multiply") op * <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
+@must_use @const("Multiply") op * <T: fa_f32_f16, N: num, M: num> (T, mat<N, M, T>) -> mat<N, M, T>
+@must_use @const("Multiply") op * <T: fa_f32_f16, N: num, M: num> (mat<N, M, T>, T) -> mat<N, M, T>
+@must_use @const("MultiplyMatVec") op * <T: fa_f32_f16, C: num, R: num> (mat<C, R, T>, vec<C, T>) -> vec<R, T>
+@must_use @const("MultiplyVecMat") op * <T: fa_f32_f16, C: num, R: num> (vec<R, T>, mat<C, R, T>) -> vec<C, T>
+@must_use @const("MultiplyMatMat") op * <T: fa_f32_f16, K: num, C: num, R: num> (mat<K, R, T>, mat<C, K, T>) -> mat<C, R, T>
+
+@must_use @const op / <T: fia_fiu32_f16>(T, T) -> T
+@must_use @const op / <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const op / <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
+@must_use @const op / <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
+
+@must_use @const op % <T: fia_fiu32_f16>(T, T) -> T
+@must_use @const op % <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+@must_use @const op % <T: fia_fiu32_f16, N: num> (vec<N, T>, T) -> vec<N, T>
+@must_use @const op % <T: fia_fiu32_f16, N: num> (T, vec<N, T>) -> vec<N, T>
+
+@must_use @const op ^ <T: ia_iu32>(T, T) -> T
+@must_use @const op ^ <T: ia_iu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+
+@must_use @const op & (bool, bool) -> bool
+@must_use @const op & <N: num> (vec<N, bool>, vec<N, bool>) -> vec<N, bool>
+@must_use @const op & <T: ia_iu32>(T, T) -> T
+@must_use @const op & <T: ia_iu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+
+@must_use @const op | (bool, bool) -> bool
+@must_use @const op | <N: num> (vec<N, bool>, vec<N, bool>) -> vec<N, bool>
+@must_use @const op | <T: ia_iu32>(T, T) -> T
+@must_use @const op | <T: ia_iu32, N: num> (vec<N, T>, vec<N, T>) -> vec<N, T>
+
+@must_use @const op && (bool, bool) -> bool
+@must_use @const op || (bool, bool) -> bool
+
+@must_use @const op == <T: scalar>(T, T) -> bool
+@must_use @const op == <T: scalar, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+
+@must_use @const op != <T: scalar>(T, T) -> bool
+@must_use @const op != <T: scalar, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+
+@must_use @const op < <T: fia_fiu32_f16>(T, T) -> bool
+@must_use @const op < <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+
+@must_use @const op > <T: fia_fiu32_f16>(T, T) -> bool
+@must_use @const op > <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+
+@must_use @const op <= <T: fia_fiu32_f16>(T, T) -> bool
+@must_use @const op <= <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+
+@must_use @const op >= <T: fia_fiu32_f16>(T, T) -> bool
+@must_use @const op >= <T: fia_fiu32_f16, N: num> (vec<N, T>, vec<N, T>) -> vec<N, bool>
+
+@must_use @const op << <T: ia_iu32>(T, u32) -> T
+@must_use @const op << <T: ia_iu32, N: num> (vec<N, T>, vec<N, u32>) -> vec<N, T>
+
+@must_use @const op >> <T: ia_iu32>(T, u32) -> T
+@must_use @const op >> <T: ia_iu32, N: num> (vec<N, T>, vec<N, u32>) -> vec<N, T>
+
+////////////////////////////////////////////////////////////////////////////////
+// Tint internal builtins                                                     //
+////////////////////////////////////////////////////////////////////////////////
+@const("Identity") fn _tint_materialize<T>(T) -> T
diff --git a/src/tint/lang/wgsl/writer/BUILD.bazel b/src/tint/lang/wgsl/writer/BUILD.bazel
index 570230f..36cadd8 100644
--- a/src/tint/lang/wgsl/writer/BUILD.bazel
+++ b/src/tint/lang/wgsl/writer/BUILD.bazel
@@ -36,14 +36,18 @@
     "writer.h",
   ],
   deps = [
+    "//src/tint/api/common",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
     "//src/tint/lang/wgsl/program",
     "//src/tint/lang/wgsl/sem",
     "//src/tint/lang/wgsl/writer/ast_printer",
+    "//src/tint/lang/wgsl/writer/ir_to_program",
+    "//src/tint/lang/wgsl/writer/raise",
     "//src/tint/lang/wgsl/writer/syntax_tree_printer",
     "//src/tint/utils/containers",
     "//src/tint/utils/diagnostic",
diff --git a/src/tint/lang/wgsl/writer/BUILD.cmake b/src/tint/lang/wgsl/writer/BUILD.cmake
index 4802da7..c9893f6 100644
--- a/src/tint/lang/wgsl/writer/BUILD.cmake
+++ b/src/tint/lang/wgsl/writer/BUILD.cmake
@@ -23,6 +23,7 @@
 
 include(lang/wgsl/writer/ast_printer/BUILD.cmake)
 include(lang/wgsl/writer/ir_to_program/BUILD.cmake)
+include(lang/wgsl/writer/raise/BUILD.cmake)
 include(lang/wgsl/writer/syntax_tree_printer/BUILD.cmake)
 
 ################################################################################
@@ -39,14 +40,18 @@
 )
 
 tint_target_add_dependencies(tint_lang_wgsl_writer lib
+  tint_api_common
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_ir
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
   tint_lang_wgsl_program
   tint_lang_wgsl_sem
   tint_lang_wgsl_writer_ast_printer
+  tint_lang_wgsl_writer_ir_to_program
+  tint_lang_wgsl_writer_raise
   tint_lang_wgsl_writer_syntax_tree_printer
   tint_utils_containers
   tint_utils_diagnostic
diff --git a/src/tint/lang/wgsl/writer/BUILD.gn b/src/tint/lang/wgsl/writer/BUILD.gn
index 1bbf405..21b27a4 100644
--- a/src/tint/lang/wgsl/writer/BUILD.gn
+++ b/src/tint/lang/wgsl/writer/BUILD.gn
@@ -35,14 +35,18 @@
     "writer.h",
   ]
   deps = [
+    "${tint_src_dir}/api/common",
     "${tint_src_dir}/lang/core",
     "${tint_src_dir}/lang/core/constant",
+    "${tint_src_dir}/lang/core/ir",
     "${tint_src_dir}/lang/core/type",
     "${tint_src_dir}/lang/wgsl",
     "${tint_src_dir}/lang/wgsl/ast",
     "${tint_src_dir}/lang/wgsl/program",
     "${tint_src_dir}/lang/wgsl/sem",
     "${tint_src_dir}/lang/wgsl/writer/ast_printer",
+    "${tint_src_dir}/lang/wgsl/writer/ir_to_program",
+    "${tint_src_dir}/lang/wgsl/writer/raise",
     "${tint_src_dir}/lang/wgsl/writer/syntax_tree_printer",
     "${tint_src_dir}/utils/containers",
     "${tint_src_dir}/utils/diagnostic",
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.bazel b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.bazel
index 09671ed..c14817f 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.bazel
+++ b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.bazel
@@ -43,6 +43,8 @@
     "//src/tint/lang/core/type",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
+    "//src/tint/lang/wgsl/intrinsic/data",
+    "//src/tint/lang/wgsl/ir",
     "//src/tint/lang/wgsl/program",
     "//src/tint/lang/wgsl/resolver",
     "//src/tint/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.cmake b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.cmake
index 4ac6bd8..d6e6e5f 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.cmake
+++ b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.cmake
@@ -42,6 +42,8 @@
   tint_lang_core_type
   tint_lang_wgsl
   tint_lang_wgsl_ast
+  tint_lang_wgsl_intrinsic_data
+  tint_lang_wgsl_ir
   tint_lang_wgsl_program
   tint_lang_wgsl_resolver
   tint_lang_wgsl_sem
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn
index 584fa6c..d2b88ff 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn
+++ b/src/tint/lang/wgsl/writer/ir_to_program/BUILD.gn
@@ -46,6 +46,8 @@
     "${tint_src_dir}/lang/core/type",
     "${tint_src_dir}/lang/wgsl",
     "${tint_src_dir}/lang/wgsl/ast",
+    "${tint_src_dir}/lang/wgsl/intrinsic/data",
+    "${tint_src_dir}/lang/wgsl/ir",
     "${tint_src_dir}/lang/wgsl/program",
     "${tint_src_dir}/lang/wgsl/resolver",
     "${tint_src_dir}/lang/wgsl/sem",
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/inlining_test.cc b/src/tint/lang/wgsl/writer/ir_to_program/inlining_test.cc
index 69632ee..ae49eb3 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/inlining_test.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/inlining_test.cc
@@ -735,9 +735,8 @@
 }
 
 fn f() -> f32 {
-  let v_1 = array<mat3x4<f32>, 5u>();
-  let v_2 = a(2i);
-  return v_1[a(1i)][v_2][a(3i)];
+  let v_1 = a(2i);
+  return array<mat3x4<f32>, 5u>()[a(1i)][v_1][a(3i)];
 }
 )");
 }
@@ -763,9 +762,8 @@
 }
 
 fn f() -> f32 {
-  let v_1 = array<mat3x4<f32>, 5u>();
-  let v_2 = a(3i);
-  return v_1[a(1i)][a(2i)][v_2];
+  let v_1 = a(3i);
+  return array<mat3x4<f32>, 5u>()[a(1i)][a(2i)][v_1];
 }
 )");
 }
@@ -791,10 +789,9 @@
 }
 
 fn f() -> f32 {
-  let v_1 = array<mat3x4<f32>, 5u>();
-  let v_2 = a(3i);
-  let v_3 = a(2i);
-  return v_1[a(1i)][v_3][v_2];
+  let v_1 = a(3i);
+  let v_2 = a(2i);
+  return array<mat3x4<f32>, 5u>()[a(1i)][v_2][v_1];
 }
 )");
 }
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
index 4623d29..09cd27e 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
@@ -63,6 +63,7 @@
 #include "src/tint/lang/core/type/reference.h"
 #include "src/tint/lang/core/type/sampler.h"
 #include "src/tint/lang/core/type/texture.h"
+#include "src/tint/lang/wgsl/ir/builtin_call.h"
 #include "src/tint/lang/wgsl/program/program_builder.h"
 #include "src/tint/lang/wgsl/resolver/resolve.h"
 #include "src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h"
@@ -100,20 +101,19 @@
         {
             auto result = RenameConflicts(&mod);
             if (!result) {
-                b.Diagnostics().add_error(diag::System::Transform, result.Failure());
+                b.Diagnostics().add(result.Failure().reason);
                 return Program(std::move(b));
             }
         }
 
         if (auto res = core::ir::Validate(mod); !res) {
             // IR module failed validation.
-            b.Diagnostics() = res.Failure();
+            b.Diagnostics() = res.Failure().reason;
             return Program{resolver::Resolve(b)};
         }
 
-        if (mod.root_block) {
-            RootBlock(mod.root_block);
-        }
+        RootBlock(mod.root_block);
+
         // TODO(crbug.com/tint/1902): Emit user-declared types
         for (auto* fn : mod.functions) {
             Fn(fn);
@@ -578,7 +578,7 @@
                 }
                 Bind(c->Result(), expr, PtrKind::kPtr);
             },
-            [&](core::ir::CoreBuiltinCall* c) {
+            [&](wgsl::ir::BuiltinCall* c) {
                 if (!disabled_derivative_uniformity_ && RequiresDerivativeUniformity(c->Func())) {
                     // TODO(crbug.com/tint/1985): Be smarter about disabling derivative uniformity.
                     b.DiagnosticDirective(wgsl::DiagnosticSeverity::kOff,
@@ -1141,20 +1141,20 @@
         return b.IndexAccessor(expr, Expr(index));
     }
 
-    bool RequiresDerivativeUniformity(core::BuiltinFn fn) {
+    bool RequiresDerivativeUniformity(wgsl::BuiltinFn fn) {
         switch (fn) {
-            case core::BuiltinFn::kDpdxCoarse:
-            case core::BuiltinFn::kDpdyCoarse:
-            case core::BuiltinFn::kFwidthCoarse:
-            case core::BuiltinFn::kDpdxFine:
-            case core::BuiltinFn::kDpdyFine:
-            case core::BuiltinFn::kFwidthFine:
-            case core::BuiltinFn::kDpdx:
-            case core::BuiltinFn::kDpdy:
-            case core::BuiltinFn::kFwidth:
-            case core::BuiltinFn::kTextureSample:
-            case core::BuiltinFn::kTextureSampleBias:
-            case core::BuiltinFn::kTextureSampleCompare:
+            case wgsl::BuiltinFn::kDpdxCoarse:
+            case wgsl::BuiltinFn::kDpdyCoarse:
+            case wgsl::BuiltinFn::kFwidthCoarse:
+            case wgsl::BuiltinFn::kDpdxFine:
+            case wgsl::BuiltinFn::kDpdyFine:
+            case wgsl::BuiltinFn::kFwidthFine:
+            case wgsl::BuiltinFn::kDpdx:
+            case wgsl::BuiltinFn::kDpdy:
+            case wgsl::BuiltinFn::kFwidth:
+            case wgsl::BuiltinFn::kTextureSample:
+            case wgsl::BuiltinFn::kTextureSampleBias:
+            case wgsl::BuiltinFn::kTextureSampleCompare:
                 return true;
             default:
                 return false;
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
index 44ffdd2..2071cf1 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program_test.cc
@@ -388,6 +388,377 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+// Type Construct
+////////////////////////////////////////////////////////////////////////////////
+TEST_F(IRToProgramTest, TypeConstruct_i32) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.i32());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Construct<i32>(i));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i : i32) {
+  var v : i32 = i32(i);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConstruct_u32) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.i32());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Construct<u32>(i));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i : i32) {
+  var v : u32 = u32(i);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConstruct_f32) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.i32());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Construct<f32>(i));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i : i32) {
+  var v : f32 = f32(i);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConstruct_bool) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.i32());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Construct<bool>(i));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i : i32) {
+  var v : bool = bool(i);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConstruct_struct) {
+    auto* S = ty.Struct(mod.symbols.New("S"), {
+                                                  {mod.symbols.New("a"), ty.i32()},
+                                                  {mod.symbols.New("b"), ty.u32()},
+                                                  {mod.symbols.New("c"), ty.f32()},
+                                              });
+
+    auto* fn = b.Function("f", ty.void_());
+    auto* x = b.FunctionParam("x", ty.i32());
+    auto* y = b.FunctionParam("y", ty.u32());
+    auto* z = b.FunctionParam("z", ty.f32());
+    fn->SetParams({x, y, z});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Construct(S, x, y, z));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+struct S {
+  a : i32,
+  b : u32,
+  c : f32,
+}
+
+fn f(x : i32, y : u32, z : f32) {
+  var v : S = S(x, y, z);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConstruct_array) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.i32());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Construct<array<i32, 3u>>(i, i, i));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i : i32) {
+  var v : array<i32, 3u> = array<i32, 3u>(i, i, i);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConstruct_vec3i_Splat) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.i32());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Construct<vec3<i32>>(i));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i : i32) {
+  var v : vec3<i32> = vec3<i32>(i);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConstruct_vec3i_Scalars) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.i32());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Construct<vec3<i32>>(i, i, i));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i : i32) {
+  var v : vec3<i32> = vec3<i32>(i, i, i);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConstruct_mat2x3f_Scalars) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.f32());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Construct<mat2x3<f32>>(i, i, i, i, i, i));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i : f32) {
+  var v : mat2x3<f32> = mat2x3<f32>(i, i, i, i, i, i);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConstruct_mat2x3f_Columns) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.f32());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        auto* col_0 = b.Construct<vec3<f32>>(i, i, i);
+        auto* col_1 = b.Construct<vec3<f32>>(i, i, i);
+        b.Var("v", b.Construct<mat2x3<f32>>(col_0, col_1));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i : f32) {
+  var v : mat2x3<f32> = mat2x3<f32>(vec3<f32>(i, i, i), vec3<f32>(i, i, i));
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConstruct_Inlining) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i0 = b.FunctionParam("i0", ty.i32());
+    auto* i1 = b.FunctionParam("i1", ty.i32());
+    auto* i2 = b.FunctionParam("i2", ty.i32());
+    auto* i3 = b.FunctionParam("i3", ty.i32());
+    auto* i4 = b.FunctionParam("i4", ty.i32());
+    auto* i5 = b.FunctionParam("i5", ty.i32());
+    fn->SetParams({i0, i1, i2, i3, i4, i5});
+
+    b.Append(fn->Block(), [&] {
+        auto* f3 = b.Construct<f32>(i3);
+        auto* f4 = b.Construct<f32>(i4);
+        auto* f5 = b.Construct<f32>(i5);
+        auto* f0 = b.Construct<f32>(i0);
+        auto* f2 = b.Construct<f32>(i2);
+        auto* f1 = b.Construct<f32>(i1);
+        b.Var("v", b.Construct<mat2x3<f32>>(f0, f1, f2, f3, f4, f5));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i0 : i32, i1 : i32, i2 : i32, i3 : i32, i4 : i32, i5 : i32) {
+  var v : mat2x3<f32> = mat2x3<f32>(f32(i0), f32(i1), f32(i2), f32(i3), f32(i4), f32(i5));
+}
+)");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Type Convert
+////////////////////////////////////////////////////////////////////////////////
+TEST_F(IRToProgramTest, TypeConvert_i32_to_u32) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.i32());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Convert<u32>(i));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i : i32) {
+  var v : u32 = u32(i);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConvert_u32_to_f32) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.u32());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Convert<f32>(i));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i : u32) {
+  var v : f32 = f32(i);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConvert_f32_to_i32) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.f32());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Convert<i32>(i));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i : f32) {
+  var v : i32 = i32(i);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConvert_bool_to_u32) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.bool_());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Convert<u32>(i));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i : bool) {
+  var v : u32 = u32(i);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConvert_vec3i_to_vec3u) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.vec3<i32>());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Convert<vec3<u32>>(i));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i : vec3<i32>) {
+  var v : vec3<u32> = vec3<u32>(i);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConvert_vec3u_to_vec3f) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.vec3<u32>());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Convert<vec3<f32>>(i));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+fn f(i : vec3<u32>) {
+  var v : vec3<f32> = vec3<f32>(i);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConvert_mat2x3f_to_mat2x3h) {
+    auto* fn = b.Function("f", ty.void_());
+    auto* i = b.FunctionParam("i", ty.mat2x3<f32>());
+    fn->SetParams({i});
+
+    b.Append(fn->Block(), [&] {
+        b.Var("v", b.Convert<mat2x3<f16>>(i));
+        b.Return(fn);
+    });
+
+    EXPECT_WGSL(R"(
+enable f16;
+
+fn f(i : mat2x3<f32>) {
+  var v : mat2x3<f16> = mat2x3<f16>(i);
+}
+)");
+}
+
+TEST_F(IRToProgramTest, TypeConvert_Inlining) {
+    auto* fn_g = b.Function("g", ty.void_());
+    fn_g->SetParams({
+        b.FunctionParam("a", ty.i32()),
+        b.FunctionParam("b", ty.u32()),
+        b.FunctionParam("c", ty.f32()),
+    });
+    b.Append(fn_g->Block(), [&] { b.Return(fn_g); });
+
+    auto* fn_f = b.Function("f", ty.void_());
+    auto* v = b.FunctionParam("v", ty.i32());
+    fn_f->SetParams({v});
+    b.Append(fn_f->Block(), [&] {
+        auto* u = b.Convert<u32>(v);
+        auto* f = b.Convert<f32>(v);
+        auto* i = b.Convert<i32>(v);
+        b.Call(fn_g, i, u, f);
+        b.Return(fn_f);
+    });
+
+    EXPECT_WGSL(R"(
+fn g(a : i32, b : u32, c : f32) {
+}
+
+fn f(v : i32) {
+  g(i32(v), u32(v), f32(v));
+}
+)");
+}
+
+////////////////////////////////////////////////////////////////////////////////
 // Short-circuiting binary ops
 ////////////////////////////////////////////////////////////////////////////////
 TEST_F(IRToProgramTest, ShortCircuit_And_Param_2) {
@@ -2375,7 +2746,7 @@
     //   }
     // }
 
-    b.Append(b.RootBlock(), [&] {
+    b.Append(mod.root_block, [&] {
         auto* i = b.Var(ty.ptr<storage, u32, read_write>());
         i->SetBindingPoint(0, 0);
 
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.cc b/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.cc
index 7ef8cf8..032b279 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.cc
@@ -56,10 +56,8 @@
         RegisterModuleScopeDecls();
 
         // Process the module-scope variable declarations
-        if (ir->root_block) {
-            for (auto* inst : *ir->root_block) {
-                Process(inst);
-            }
+        for (auto* inst : *ir->root_block) {
+            Process(inst);
         }
 
         // Process the functions
@@ -101,12 +99,10 @@
         }
 
         // Declare all the module-scope vars
-        if (ir->root_block) {
-            for (auto* inst : *ir->root_block) {
-                for (auto* result : inst->Results()) {
-                    if (auto symbol = ir->NameOf(result)) {
-                        Declare(scopes.Front(), result, symbol.NameView());
-                    }
+        for (auto* inst : *ir->root_block) {
+            for (auto* result : inst->Results()) {
+                if (auto symbol = ir->NameOf(result)) {
+                    Declare(scopes.Front(), result, symbol.NameView());
                 }
             }
         }
@@ -276,7 +272,7 @@
 
 }  // namespace
 
-Result<SuccessType, std::string> RenameConflicts(core::ir::Module* ir) {
+Result<SuccessType> RenameConflicts(core::ir::Module* ir) {
     auto result = ValidateAndDumpIfNeeded(*ir, "RenameConflicts transform");
     if (!result) {
         return result;
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h b/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
index b513409..c763a54 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
+++ b/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts.h
@@ -17,6 +17,7 @@
 
 #include <string>
 
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward declarations.
@@ -30,8 +31,8 @@
 /// resolving to the correct declaration, and those with identical identifiers declared in the same
 /// scope.
 /// @param module the module to transform
-/// @returns an error string on failure
-Result<SuccessType, std::string> RenameConflicts(core::ir::Module* module);
+/// @returns success or failure
+Result<SuccessType> RenameConflicts(core::ir::Module* module);
 
 }  // namespace tint::wgsl::writer
 
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts_test.cc b/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts_test.cc
index e5866f4..e00c5e8 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts_test.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts_test.cc
@@ -36,7 +36,7 @@
         // Validate the input IR.
         {
             auto res = core::ir::Validate(mod);
-            EXPECT_TRUE(res) << res.Failure().str();
+            EXPECT_TRUE(res) << res.Failure().reason.str();
             if (!res) {
                 return;
             }
@@ -48,7 +48,7 @@
 
         // Validate the output IR.
         auto res = core::ir::Validate(mod);
-        EXPECT_TRUE(res) << res.Failure().str();
+        EXPECT_TRUE(res) << res.Failure().reason.str();
     }
 
     /// @returns the transformed module as a disassembled string
@@ -67,7 +67,7 @@
 };
 
 TEST_F(IRToProgramRenameConflictsTest, NoModify_SingleNamedRootBlockVar) {
-    b.Append(b.RootBlock(), [&] { b.ir.SetName(b.Var(ty.ptr<private_, i32>()), "v"); });
+    b.Append(mod.root_block, [&] { b.ir.SetName(b.Var(ty.ptr<private_, i32>()), "v"); });
 
     auto* src = R"(
 %b1 = block {  # root
@@ -85,7 +85,7 @@
 }
 
 TEST_F(IRToProgramRenameConflictsTest, Conflict_TwoRootBlockVarsWithSameName) {
-    b.Append(b.RootBlock(), [&] {
+    b.Append(mod.root_block, [&] {
         b.ir.SetName(b.Var(ty.ptr<private_, i32>()), "v");
         b.ir.SetName(b.Var(ty.ptr<private_, u32>()), "v");
     });
@@ -114,7 +114,7 @@
 
 TEST_F(IRToProgramRenameConflictsTest, Conflict_RootBlockVarAndStructWithSameName) {
     auto* s = ty.Struct(b.ir.symbols.New("v"), {{b.ir.symbols.New("x"), ty.i32()}});
-    b.Append(b.RootBlock(), [&] { b.ir.SetName(b.Var(ty.ptr(function, s)), "v"); });
+    b.Append(mod.root_block, [&] { b.ir.SetName(b.Var(ty.ptr(function, s)), "v"); });
 
     auto* src = R"(
 v = struct @align(4) {
@@ -145,7 +145,7 @@
 }
 
 TEST_F(IRToProgramRenameConflictsTest, Conflict_RootBlockVarAndFnWithSameName) {
-    b.Append(b.RootBlock(), [&] { b.ir.SetName(b.Var(ty.ptr<private_, i32>()), "v"); });
+    b.Append(mod.root_block, [&] { b.ir.SetName(b.Var(ty.ptr<private_, i32>()), "v"); });
 
     auto* fn = b.Function("v", ty.void_());
     b.Append(fn->Block(), [&] { b.Return(fn); });
@@ -181,7 +181,7 @@
 }
 
 TEST_F(IRToProgramRenameConflictsTest, NoModify_RootBlockVar_ShadowedBy_FnVar) {
-    b.Append(b.RootBlock(), [&] {
+    b.Append(mod.root_block, [&] {
         auto* outer = b.Var(ty.ptr<private_, i32>());
         b.ir.SetName(outer, "v");
 
@@ -222,7 +222,7 @@
 }
 
 TEST_F(IRToProgramRenameConflictsTest, Conflict_RootBlockVar_ShadowedBy_FnVar) {
-    b.Append(b.RootBlock(), [&] {
+    b.Append(mod.root_block, [&] {
         auto* outer = b.Var(ty.ptr<private_, i32>());
         b.ir.SetName(outer, "v");
 
@@ -922,7 +922,7 @@
 }
 
 TEST_F(IRToProgramRenameConflictsTest, NoModify_BuiltinAddressSpace_ShadowedBy_RootBlockVar) {
-    b.Append(b.RootBlock(), [&] {  //
+    b.Append(mod.root_block, [&] {  //
         b.ir.SetName(b.Var(ty.ptr<private_, i32>()), "function");
     });
 
@@ -942,7 +942,7 @@
 }
 
 TEST_F(IRToProgramRenameConflictsTest, Conflict_BuiltinAddressSpace_ShadowedBy_RootBlockVar) {
-    b.Append(b.RootBlock(), [&] {  //
+    b.Append(mod.root_block, [&] {  //
         b.ir.SetName(b.Var(ty.ptr<private_, i32>()), "private");
     });
 
@@ -967,7 +967,7 @@
 }
 
 TEST_F(IRToProgramRenameConflictsTest, NoModify_BuiltinAccess_ShadowedBy_RootBlockVar) {
-    b.Append(b.RootBlock(), [&] {  //
+    b.Append(mod.root_block, [&] {  //
         b.ir.SetName(b.Var(ty.ptr<private_, i32>()), "read");
     });
 
@@ -987,7 +987,7 @@
 }
 
 TEST_F(IRToProgramRenameConflictsTest, Conflict_BuiltinAccess_ShadowedBy_RootBlockVar) {
-    b.Append(b.RootBlock(), [&] {  //
+    b.Append(mod.root_block, [&] {  //
         b.ir.SetName(b.Var(ty.ptr<private_, i32>()), "read_write");
     });
 
@@ -1012,7 +1012,7 @@
 }
 
 TEST_F(IRToProgramRenameConflictsTest, NoModify_BuiltinFn_ShadowedBy_RootBlockVar) {
-    b.Append(b.RootBlock(), [&] {  //
+    b.Append(mod.root_block, [&] {  //
         auto* v = b.Var(ty.ptr<private_, i32>());
         b.ir.SetName(v, "min");
     });
@@ -1045,7 +1045,7 @@
 }
 
 TEST_F(IRToProgramRenameConflictsTest, Conflict_BuiltinFn_ShadowedBy_RootBlockVar) {
-    b.Append(b.RootBlock(), [&] {  //
+    b.Append(mod.root_block, [&] {  //
         auto* v = b.Var(ty.ptr<private_, i32>());
         b.ir.SetName(v, "max");
     });
diff --git a/src/tint/lang/wgsl/writer/raise/BUILD.bazel b/src/tint/lang/wgsl/writer/raise/BUILD.bazel
new file mode 100644
index 0000000..d49adb4
--- /dev/null
+++ b/src/tint/lang/wgsl/writer/raise/BUILD.bazel
@@ -0,0 +1,96 @@
+# Copyright 2023 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# 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 = "raise",
+  srcs = [
+    "raise.cc",
+  ],
+  hdrs = [
+    "raise.h",
+  ],
+  deps = [
+    "//src/tint/api/common",
+    "//src/tint/lang/core",
+    "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/intrinsic",
+    "//src/tint/lang/core/intrinsic/data",
+    "//src/tint/lang/core/ir",
+    "//src/tint/lang/core/type",
+    "//src/tint/lang/wgsl",
+    "//src/tint/lang/wgsl/intrinsic/data",
+    "//src/tint/lang/wgsl/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",
+  ],
+  copts = COPTS,
+  visibility = ["//visibility:public"],
+)
+cc_library(
+  name = "test",
+  alwayslink = True,
+  srcs = [
+    "raise_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/intrinsic/data",
+    "//src/tint/lang/core/ir",
+    "//src/tint/lang/core/ir/transform:test",
+    "//src/tint/lang/core/type",
+    "//src/tint/lang/wgsl/writer/raise",
+    "//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/wgsl/writer/raise/BUILD.cmake b/src/tint/lang/wgsl/writer/raise/BUILD.cmake
new file mode 100644
index 0000000..fcbe110
--- /dev/null
+++ b/src/tint/lang/wgsl/writer/raise/BUILD.cmake
@@ -0,0 +1,94 @@
+# Copyright 2023 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# 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_wgsl_writer_raise
+# Kind:      lib
+################################################################################
+tint_add_target(tint_lang_wgsl_writer_raise lib
+  lang/wgsl/writer/raise/raise.cc
+  lang/wgsl/writer/raise/raise.h
+)
+
+tint_target_add_dependencies(tint_lang_wgsl_writer_raise lib
+  tint_api_common
+  tint_lang_core
+  tint_lang_core_constant
+  tint_lang_core_intrinsic
+  tint_lang_core_intrinsic_data
+  tint_lang_core_ir
+  tint_lang_core_type
+  tint_lang_wgsl
+  tint_lang_wgsl_intrinsic_data
+  tint_lang_wgsl_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
+)
+
+################################################################################
+# Target:    tint_lang_wgsl_writer_raise_test
+# Kind:      test
+################################################################################
+tint_add_target(tint_lang_wgsl_writer_raise_test test
+  lang/wgsl/writer/raise/raise_test.cc
+)
+
+tint_target_add_dependencies(tint_lang_wgsl_writer_raise_test test
+  tint_api_common
+  tint_lang_core
+  tint_lang_core_constant
+  tint_lang_core_intrinsic
+  tint_lang_core_intrinsic_data
+  tint_lang_core_ir
+  tint_lang_core_ir_transform_test
+  tint_lang_core_type
+  tint_lang_wgsl_writer_raise
+  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_wgsl_writer_raise_test test
+  "gtest"
+)
diff --git a/src/tint/lang/wgsl/writer/raise/BUILD.gn b/src/tint/lang/wgsl/writer/raise/BUILD.gn
new file mode 100644
index 0000000..18ec5e1
--- /dev/null
+++ b/src/tint/lang/wgsl/writer/raise/BUILD.gn
@@ -0,0 +1,93 @@
+# Copyright 2023 The Tint Authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+################################################################################
+# 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) {
+  import("//testing/test.gni")
+}
+
+libtint_source_set("raise") {
+  sources = [
+    "raise.cc",
+    "raise.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/intrinsic/data",
+    "${tint_src_dir}/lang/core/ir",
+    "${tint_src_dir}/lang/core/type",
+    "${tint_src_dir}/lang/wgsl",
+    "${tint_src_dir}/lang/wgsl/intrinsic/data",
+    "${tint_src_dir}/lang/wgsl/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",
+  ]
+}
+if (tint_build_unittests) {
+  tint_unittests_source_set("unittests") {
+    testonly = true
+    sources = [ "raise_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/intrinsic/data",
+      "${tint_src_dir}/lang/core/ir",
+      "${tint_src_dir}/lang/core/ir/transform:unittests",
+      "${tint_src_dir}/lang/core/type",
+      "${tint_src_dir}/lang/wgsl/writer/raise",
+      "${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/wgsl/writer/raise/raise.cc b/src/tint/lang/wgsl/writer/raise/raise.cc
new file mode 100644
index 0000000..daacf36
--- /dev/null
+++ b/src/tint/lang/wgsl/writer/raise/raise.cc
@@ -0,0 +1,169 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/lang/wgsl/writer/raise/raise.h"
+
+#include <utility>
+
+#include "src/tint/lang/core/builtin_fn.h"
+#include "src/tint/lang/core/ir/core_builtin_call.h"
+#include "src/tint/lang/wgsl/builtin_fn.h"
+#include "src/tint/lang/wgsl/ir/builtin_call.h"
+
+namespace tint::wgsl::writer::raise {
+namespace {
+
+wgsl::BuiltinFn Convert(core::BuiltinFn fn) {
+#define CASE(NAME)              \
+    case core::BuiltinFn::NAME: \
+        return wgsl::BuiltinFn::NAME;
+
+    switch (fn) {
+        CASE(kAbs)
+        CASE(kAcos)
+        CASE(kAcosh)
+        CASE(kAll)
+        CASE(kAny)
+        CASE(kArrayLength)
+        CASE(kAsin)
+        CASE(kAsinh)
+        CASE(kAtan)
+        CASE(kAtan2)
+        CASE(kAtanh)
+        CASE(kCeil)
+        CASE(kClamp)
+        CASE(kCos)
+        CASE(kCosh)
+        CASE(kCountLeadingZeros)
+        CASE(kCountOneBits)
+        CASE(kCountTrailingZeros)
+        CASE(kCross)
+        CASE(kDegrees)
+        CASE(kDeterminant)
+        CASE(kDistance)
+        CASE(kDot)
+        CASE(kDot4I8Packed)
+        CASE(kDot4U8Packed)
+        CASE(kDpdx)
+        CASE(kDpdxCoarse)
+        CASE(kDpdxFine)
+        CASE(kDpdy)
+        CASE(kDpdyCoarse)
+        CASE(kDpdyFine)
+        CASE(kExp)
+        CASE(kExp2)
+        CASE(kExtractBits)
+        CASE(kFaceForward)
+        CASE(kFirstLeadingBit)
+        CASE(kFirstTrailingBit)
+        CASE(kFloor)
+        CASE(kFma)
+        CASE(kFract)
+        CASE(kFrexp)
+        CASE(kFwidth)
+        CASE(kFwidthCoarse)
+        CASE(kFwidthFine)
+        CASE(kInsertBits)
+        CASE(kInverseSqrt)
+        CASE(kLdexp)
+        CASE(kLength)
+        CASE(kLog)
+        CASE(kLog2)
+        CASE(kMax)
+        CASE(kMin)
+        CASE(kMix)
+        CASE(kModf)
+        CASE(kNormalize)
+        CASE(kPack2X16Float)
+        CASE(kPack2X16Snorm)
+        CASE(kPack2X16Unorm)
+        CASE(kPack4X8Snorm)
+        CASE(kPack4X8Unorm)
+        CASE(kPow)
+        CASE(kQuantizeToF16)
+        CASE(kRadians)
+        CASE(kReflect)
+        CASE(kRefract)
+        CASE(kReverseBits)
+        CASE(kRound)
+        CASE(kSaturate)
+        CASE(kSelect)
+        CASE(kSign)
+        CASE(kSin)
+        CASE(kSinh)
+        CASE(kSmoothstep)
+        CASE(kSqrt)
+        CASE(kStep)
+        CASE(kStorageBarrier)
+        CASE(kTan)
+        CASE(kTanh)
+        CASE(kTranspose)
+        CASE(kTrunc)
+        CASE(kUnpack2X16Float)
+        CASE(kUnpack2X16Snorm)
+        CASE(kUnpack2X16Unorm)
+        CASE(kUnpack4X8Snorm)
+        CASE(kUnpack4X8Unorm)
+        CASE(kWorkgroupBarrier)
+        CASE(kWorkgroupUniformLoad)
+        CASE(kTextureBarrier)
+        CASE(kTextureDimensions)
+        CASE(kTextureGather)
+        CASE(kTextureGatherCompare)
+        CASE(kTextureNumLayers)
+        CASE(kTextureNumLevels)
+        CASE(kTextureNumSamples)
+        CASE(kTextureSample)
+        CASE(kTextureSampleBias)
+        CASE(kTextureSampleCompare)
+        CASE(kTextureSampleCompareLevel)
+        CASE(kTextureSampleGrad)
+        CASE(kTextureSampleLevel)
+        CASE(kTextureSampleBaseClampToEdge)
+        CASE(kTextureStore)
+        CASE(kTextureLoad)
+        CASE(kAtomicLoad)
+        CASE(kAtomicStore)
+        CASE(kAtomicAdd)
+        CASE(kAtomicSub)
+        CASE(kAtomicMax)
+        CASE(kAtomicMin)
+        CASE(kAtomicAnd)
+        CASE(kAtomicOr)
+        CASE(kAtomicXor)
+        CASE(kAtomicExchange)
+        CASE(kAtomicCompareExchangeWeak)
+        CASE(kSubgroupBallot)
+        CASE(kSubgroupBroadcast)
+        default:
+            TINT_ICE() << "unhandled builtin function: " << fn;
+            return wgsl::BuiltinFn::kNone;
+    }
+}
+
+}  // namespace
+
+Result<SuccessType> Raise(core::ir::Module& mod) {
+    for (auto* inst : mod.instructions.Objects()) {
+        if (auto* call = inst->As<core::ir::CoreBuiltinCall>()) {
+            Vector<core::ir::Value*, 8> args(call->Args());
+            auto* replacement = mod.instructions.Create<wgsl::ir::BuiltinCall>(
+                call->Result(), Convert(call->Func()), std::move(args));
+            call->ReplaceWith(replacement);
+        }
+    }
+    return Success;
+}
+
+}  // namespace tint::wgsl::writer::raise
diff --git a/src/tint/lang/wgsl/writer/raise/raise.h b/src/tint/lang/wgsl/writer/raise/raise.h
new file mode 100644
index 0000000..a5b1487
--- /dev/null
+++ b/src/tint/lang/wgsl/writer/raise/raise.h
@@ -0,0 +1,31 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_LANG_WGSL_WRITER_RAISE_RAISE_H_
+#define SRC_TINT_LANG_WGSL_WRITER_RAISE_RAISE_H_
+
+#include "src/tint/lang/core/ir/module.h"
+#include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/result/result.h"
+
+namespace tint::wgsl::writer::raise {
+
+/// Raise converts a core-dialect IR module to a WGSL-dialect IR module
+/// @param  mod the IR module
+/// @return the result of the operation
+Result<SuccessType> Raise(core::ir::Module& mod);
+
+}  // namespace tint::wgsl::writer::raise
+
+#endif  // SRC_TINT_LANG_WGSL_WRITER_RAISE_RAISE_H_
diff --git a/src/tint/lang/wgsl/writer/raise/raise_test.cc b/src/tint/lang/wgsl/writer/raise/raise_test.cc
new file mode 100644
index 0000000..a4f9b05
--- /dev/null
+++ b/src/tint/lang/wgsl/writer/raise/raise_test.cc
@@ -0,0 +1,61 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <utility>
+
+#include "src/tint/lang/core/ir/transform/helper_test.h"
+#include "src/tint/lang/core/type/struct.h"
+#include "src/tint/lang/wgsl/writer/raise/raise.h"
+
+namespace tint::wgsl::writer::raise {
+namespace {
+
+using namespace tint::core::fluent_types;     // NOLINT
+using namespace tint::core::number_suffixes;  // NOLINT
+
+using WgslWriter_RaiseTest = core::ir::transform::TransformTest;
+
+TEST_F(WgslWriter_RaiseTest, BuiltinConversion) {
+    auto* f = b.Function("f", ty.void_());
+    b.Append(f->Block(), [&] {  //
+        b.Call(ty.i32(), core::BuiltinFn::kMax, i32(1), i32(2));
+        b.Return(f);
+    });
+
+    auto* src = R"(
+%f = func():void -> %b1 {
+  %b1 = block {
+    %2:i32 = max 1i, 2i
+    ret
+  }
+}
+)";
+    EXPECT_EQ(src, str());
+
+    auto* expect = R"(
+%f = func():void -> %b1 {
+  %b1 = block {
+    %2:i32 = wgsl.max 1i, 2i
+    ret
+  }
+}
+)";
+
+    Run(Raise);
+
+    EXPECT_EQ(expect, str());
+}
+
+}  // namespace
+}  // namespace tint::wgsl::writer::raise
diff --git a/src/tint/lang/wgsl/writer/writer.cc b/src/tint/lang/wgsl/writer/writer.cc
index 48cdca0..737f173 100644
--- a/src/tint/lang/wgsl/writer/writer.cc
+++ b/src/tint/lang/wgsl/writer/writer.cc
@@ -19,6 +19,8 @@
 
 #include "src/tint/lang/wgsl/program/program.h"
 #include "src/tint/lang/wgsl/writer/ast_printer/ast_printer.h"
+#include "src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h"
+#include "src/tint/lang/wgsl/writer/raise/raise.h"
 
 #if TINT_BUILD_SYNTAX_TREE_WRITER
 #include "src/tint/lang/wgsl/writer/syntax_tree_printer/syntax_tree_printer.h"
@@ -26,7 +28,7 @@
 
 namespace tint::wgsl::writer {
 
-Result<Output, std::string> Generate(const Program& program, const Options& options) {
+Result<Output> Generate(const Program& program, const Options& options) {
     (void)options;
 
     Output output;
@@ -35,7 +37,7 @@
         // Generate the WGSL code.
         auto impl = std::make_unique<SyntaxTreePrinter>(program);
         if (!impl->Generate()) {
-            return impl->Diagnostics().str();
+            return Failure{impl->Diagnostics()};
         }
         output.wgsl = impl->Result();
     } else  // NOLINT(readability/braces)
@@ -44,7 +46,7 @@
         // Generate the WGSL code.
         auto impl = std::make_unique<ASTPrinter>(program);
         if (!impl->Generate()) {
-            return impl->Diagnostics().str();
+            return Failure{impl->Diagnostics()};
         }
         output.wgsl = impl->Result();
     }
@@ -52,4 +54,18 @@
     return output;
 }
 
+Result<Output> WgslFromIR(core::ir::Module& module) {
+    // core-dialect -> WGSL-dialect
+    if (auto res = raise::Raise(module); !res) {
+        return res.Failure();
+    }
+
+    auto program = IRToProgram(module);
+    if (!program.IsValid()) {
+        return Failure{program.Diagnostics()};
+    }
+
+    return Generate(program, Options{});
+}
+
 }  // namespace tint::wgsl::writer
diff --git a/src/tint/lang/wgsl/writer/writer.h b/src/tint/lang/wgsl/writer/writer.h
index f1e6988..b6c14bf 100644
--- a/src/tint/lang/wgsl/writer/writer.h
+++ b/src/tint/lang/wgsl/writer/writer.h
@@ -19,21 +19,30 @@
 
 #include "src/tint/lang/wgsl/writer/options.h"
 #include "src/tint/lang/wgsl/writer/output.h"
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/result/result.h"
 
 // Forward declarations
 namespace tint {
 class Program;
 }  // namespace tint
+namespace tint::core::ir {
+class Module;
+}  // namespace tint::core::ir
 
 namespace tint::wgsl::writer {
 
 /// Generate WGSL for a program, according to a set of configuration options.
-/// The result will contain the WGSL, or an error string.
+/// The result will contain the WGSL, or failure.
 /// @param program the program to translate to WGSL
 /// @param options the configuration options to use when generating WGSL
-/// @returns the resulting WGSL, or an error string
-Result<Output, std::string> Generate(const Program& program, const Options& options);
+/// @returns the resulting WGSL, or failure
+Result<Output> Generate(const Program& program, const Options& options);
+
+/// Generate WGSL from a core-dialect ir::Module.
+/// @param module the core-dialect ir::Module.
+/// @returns the resulting WGSL, or failure
+Result<Output> WgslFromIR(core::ir::Module& module);
 
 }  // namespace tint::wgsl::writer
 
diff --git a/src/tint/lang/wgsl/writer/writer_bench.cc b/src/tint/lang/wgsl/writer/writer_bench.cc
index c3fd5d4..05f349a 100644
--- a/src/tint/lang/wgsl/writer/writer_bench.cc
+++ b/src/tint/lang/wgsl/writer/writer_bench.cc
@@ -30,7 +30,7 @@
     for (auto _ : state) {
         auto res = Generate(program, {});
         if (!res) {
-            state.SkipWithError(res.Failure().c_str());
+            state.SkipWithError(res.Failure().reason.str());
         }
     }
 }
diff --git a/src/tint/utils/cli/BUILD.bazel b/src/tint/utils/cli/BUILD.bazel
index 3b9fcb0..5e2fb0f 100644
--- a/src/tint/utils/cli/BUILD.bazel
+++ b/src/tint/utils/cli/BUILD.bazel
@@ -33,6 +33,7 @@
   ],
   deps = [
     "//src/tint/utils/containers",
+    "//src/tint/utils/diagnostic",
     "//src/tint/utils/ice",
     "//src/tint/utils/macros",
     "//src/tint/utils/math",
@@ -55,6 +56,7 @@
   deps = [
     "//src/tint/utils/cli",
     "//src/tint/utils/containers",
+    "//src/tint/utils/diagnostic",
     "//src/tint/utils/ice",
     "//src/tint/utils/macros",
     "//src/tint/utils/math",
diff --git a/src/tint/utils/cli/BUILD.cmake b/src/tint/utils/cli/BUILD.cmake
index 7be4d1b..2ec8d75 100644
--- a/src/tint/utils/cli/BUILD.cmake
+++ b/src/tint/utils/cli/BUILD.cmake
@@ -32,6 +32,7 @@
 
 tint_target_add_dependencies(tint_utils_cli lib
   tint_utils_containers
+  tint_utils_diagnostic
   tint_utils_ice
   tint_utils_macros
   tint_utils_math
@@ -54,6 +55,7 @@
 tint_target_add_dependencies(tint_utils_cli_test test
   tint_utils_cli
   tint_utils_containers
+  tint_utils_diagnostic
   tint_utils_ice
   tint_utils_macros
   tint_utils_math
diff --git a/src/tint/utils/cli/BUILD.gn b/src/tint/utils/cli/BUILD.gn
index 12f567c..2306667 100644
--- a/src/tint/utils/cli/BUILD.gn
+++ b/src/tint/utils/cli/BUILD.gn
@@ -36,6 +36,7 @@
   ]
   deps = [
     "${tint_src_dir}/utils/containers",
+    "${tint_src_dir}/utils/diagnostic",
     "${tint_src_dir}/utils/ice",
     "${tint_src_dir}/utils/macros",
     "${tint_src_dir}/utils/math",
@@ -55,6 +56,7 @@
       "${tint_src_dir}:gmock_and_gtest",
       "${tint_src_dir}/utils/cli",
       "${tint_src_dir}/utils/containers",
+      "${tint_src_dir}/utils/diagnostic",
       "${tint_src_dir}/utils/ice",
       "${tint_src_dir}/utils/macros",
       "${tint_src_dir}/utils/math",
diff --git a/src/tint/utils/cli/cli.cc b/src/tint/utils/cli/cli.cc
index a8180b5..3ce5838 100644
--- a/src/tint/utils/cli/cli.cc
+++ b/src/tint/utils/cli/cli.cc
@@ -118,16 +118,14 @@
     }
 }
 
-Result<OptionSet::Unconsumed> OptionSet::Parse(std::ostream& s_err,
-                                               VectorRef<std::string_view> arguments_raw) {
+Result<OptionSet::Unconsumed> OptionSet::Parse(VectorRef<std::string_view> arguments_raw) {
     // Build a map of name to option, and set defaults
     Hashmap<std::string, Option*, 32> options_by_name;
     for (auto* opt : options.Objects()) {
         opt->SetDefault();
         for (auto name : {opt->Name(), opt->Alias(), opt->ShortName()}) {
             if (!name.empty() && !options_by_name.Add(name, opt)) {
-                s_err << "multiple options with name '" << name << "'" << std::endl;
-                return Failure;
+                return Failure{"multiple options with name '" + name + "'"};
             }
         }
     }
@@ -158,21 +156,19 @@
         }
         if (auto opt = options_by_name.Find(name)) {
             if (auto err = (*opt)->Parse(arguments); !err.empty()) {
-                s_err << err << std::endl;
-                return Failure;
+                return Failure{err};
             }
         } else {
-            s_err << "unknown flag: " << arg << std::endl;
+            StringStream err;
+            err << "unknown flag: " << arg << std::endl;
             auto names = options_by_name.Keys();
             auto alternatives =
                 Transform(names, [&](const std::string& s) { return std::string_view(s); });
-            StringStream ss;
             tint::SuggestAlternativeOptions opts;
             opts.prefix = "--";
             opts.list_possible_values = false;
-            SuggestAlternatives(arg, alternatives.Slice(), ss, opts);
-            s_err << ss.str();
-            return Failure;
+            SuggestAlternatives(arg, alternatives.Slice(), err, opts);
+            return Failure{err.str()};
         }
     }
 
diff --git a/src/tint/utils/cli/cli.h b/src/tint/utils/cli/cli.h
index 5f72859..03ae6c2 100644
--- a/src/tint/utils/cli/cli.h
+++ b/src/tint/utils/cli/cli.h
@@ -172,10 +172,9 @@
     void ShowHelp(std::ostream& out);
 
     /// Parses all the options in @p options.
-    /// @param err the error stream
     /// @param arguments the command line arguments, excluding the initial executable name
     /// @return a Result holding a list of arguments that were not consumed as options
-    Result<Unconsumed> Parse(std::ostream& err, VectorRef<std::string_view> arguments);
+    Result<Unconsumed> Parse(VectorRef<std::string_view> arguments);
 
   private:
     /// The list of options to parse
diff --git a/src/tint/utils/cli/cli_test.cc b/src/tint/utils/cli/cli_test.cc
index cfa5f25..be0f903 100644
--- a/src/tint/utils/cli/cli_test.cc
+++ b/src/tint/utils/cli/cli_test.cc
@@ -150,10 +150,8 @@
     OptionSet opts;
     auto& opt = opts.Add<BoolOption>("my_option", "a boolean value");
 
-    std::stringstream err;
-    auto res = opts.Parse(err, Split("--my_option unconsumed", " "));
-    ASSERT_TRUE(res) << err.str();
-    EXPECT_TRUE(err.str().empty());
+    auto res = opts.Parse(Split("--my_option unconsumed", " "));
+    ASSERT_TRUE(res) << res;
     EXPECT_THAT(ToStringList(res.Get()), testing::ElementsAre("unconsumed"));
     EXPECT_EQ(opt.value, true);
 }
@@ -162,10 +160,8 @@
     OptionSet opts;
     auto& opt = opts.Add<BoolOption>("my_option", "a boolean value");
 
-    std::stringstream err;
-    auto res = opts.Parse(err, Split("--my_option true", " "));
-    ASSERT_TRUE(res) << err.str();
-    EXPECT_TRUE(err.str().empty());
+    auto res = opts.Parse(Split("--my_option true", " "));
+    ASSERT_TRUE(res) << res;
     EXPECT_THAT(ToStringList(res.Get()), testing::ElementsAre());
     EXPECT_EQ(opt.value, true);
 }
@@ -174,10 +170,8 @@
     OptionSet opts;
     auto& opt = opts.Add<BoolOption>("my_option", "a boolean value", Default{true});
 
-    std::stringstream err;
-    auto res = opts.Parse(err, Split("--my_option false", " "));
-    ASSERT_TRUE(res) << err.str();
-    EXPECT_TRUE(err.str().empty());
+    auto res = opts.Parse(Split("--my_option false", " "));
+    ASSERT_TRUE(res) << res;
     EXPECT_THAT(ToStringList(res.Get()), testing::ElementsAre());
     EXPECT_EQ(opt.value, false);
 }
@@ -186,10 +180,8 @@
     OptionSet opts;
     auto& opt = opts.Add<ValueOption<int>>("my_option", "an integer value");
 
-    std::stringstream err;
-    auto res = opts.Parse(err, Split("--my_option 42", " "));
-    ASSERT_TRUE(res) << err.str();
-    EXPECT_TRUE(err.str().empty());
+    auto res = opts.Parse(Split("--my_option 42", " "));
+    ASSERT_TRUE(res) << res;
     EXPECT_THAT(ToStringList(res.Get()), testing::ElementsAre());
     EXPECT_EQ(opt.value, 42);
 }
@@ -198,10 +190,8 @@
     OptionSet opts;
     auto& opt = opts.Add<ValueOption<uint64_t>>("my_option", "a uint64_t value");
 
-    std::stringstream err;
-    auto res = opts.Parse(err, Split("--my_option 1000000", " "));
-    ASSERT_TRUE(res) << err.str();
-    EXPECT_TRUE(err.str().empty());
+    auto res = opts.Parse(Split("--my_option 1000000", " "));
+    ASSERT_TRUE(res) << res;
     EXPECT_THAT(ToStringList(res.Get()), testing::ElementsAre());
     EXPECT_EQ(opt.value, 1000000);
 }
@@ -210,10 +200,8 @@
     OptionSet opts;
     auto& opt = opts.Add<ValueOption<float>>("my_option", "a float value");
 
-    std::stringstream err;
-    auto res = opts.Parse(err, Split("--my_option 1.25", " "));
-    ASSERT_TRUE(res) << err.str();
-    EXPECT_TRUE(err.str().empty());
+    auto res = opts.Parse(Split("--my_option 1.25", " "));
+    ASSERT_TRUE(res) << res;
     EXPECT_THAT(ToStringList(res.Get()), testing::ElementsAre());
     EXPECT_EQ(opt.value, 1.25f);
 }
@@ -222,10 +210,8 @@
     OptionSet opts;
     auto& opt = opts.Add<StringOption>("my_option", "a string value");
 
-    std::stringstream err;
-    auto res = opts.Parse(err, Split("--my_option blah", " "));
-    ASSERT_TRUE(res) << err.str();
-    EXPECT_TRUE(err.str().empty());
+    auto res = opts.Parse(Split("--my_option blah", " "));
+    ASSERT_TRUE(res) << res;
     EXPECT_THAT(ToStringList(res.Get()), testing::ElementsAre());
     EXPECT_EQ(opt.value, "blah");
 }
@@ -240,10 +226,8 @@
                                             EnumName(E::Y, "Y"),
                                             EnumName(E::Z, "Z"),
                                         });
-    std::stringstream err;
-    auto res = opts.Parse(err, Split("--my_option Y", " "));
-    ASSERT_TRUE(res) << err.str();
-    EXPECT_TRUE(err.str().empty());
+    auto res = opts.Parse(Split("--my_option Y", " "));
+    ASSERT_TRUE(res) << res;
     EXPECT_THAT(ToStringList(res.Get()), testing::ElementsAre());
     EXPECT_EQ(opt.value, E::Y);
 }
@@ -252,10 +236,8 @@
     OptionSet opts;
     auto& opt = opts.Add<ValueOption<int>>("my_option", "an integer value", ShortName{"o"});
 
-    std::stringstream err;
-    auto res = opts.Parse(err, Split("-o 42", " "));
-    ASSERT_TRUE(res) << err.str();
-    EXPECT_TRUE(err.str().empty());
+    auto res = opts.Parse(Split("-o 42", " "));
+    ASSERT_TRUE(res) << res;
     EXPECT_THAT(ToStringList(res.Get()), testing::ElementsAre());
     EXPECT_EQ(opt.value, 42);
 }
@@ -264,10 +246,8 @@
     OptionSet opts;
     auto& opt = opts.Add<ValueOption<int32_t>>("my_option", "a int32_t value");
 
-    std::stringstream err;
-    auto res = opts.Parse(err, Split("abc --my_option -123 def", " "));
-    ASSERT_TRUE(res) << err.str();
-    EXPECT_TRUE(err.str().empty());
+    auto res = opts.Parse(Split("abc --my_option -123 def", " "));
+    ASSERT_TRUE(res) << res;
     EXPECT_THAT(ToStringList(res.Get()), testing::ElementsAre("abc", "def"));
     EXPECT_EQ(opt.value, -123);
 }
@@ -276,10 +256,8 @@
     OptionSet opts;
     auto& opt = opts.Add<ValueOption<int>>("my_option", "an int value");
 
-    std::stringstream err;
-    auto res = opts.Parse(err, Split("--my_option=123", " "));
-    ASSERT_TRUE(res) << err.str();
-    EXPECT_TRUE(err.str().empty());
+    auto res = opts.Parse(Split("--my_option=123", " "));
+    ASSERT_TRUE(res) << res;
     EXPECT_THAT(ToStringList(res.Get()), testing::ElementsAre());
     EXPECT_EQ(opt.value, 123);
 }
@@ -288,10 +266,8 @@
     OptionSet opts;
     auto& opt = opts.Add<BoolOption>("my_option", "a boolean value", Default{true});
 
-    std::stringstream err;
-    auto res = opts.Parse(err, tint::Empty);
-    ASSERT_TRUE(res) << err.str();
-    EXPECT_TRUE(err.str().empty());
+    auto res = opts.Parse(tint::Empty);
+    ASSERT_TRUE(res) << res;
     EXPECT_EQ(opt.value, true);
 }
 
diff --git a/src/tint/utils/diagnostic/BUILD.bazel b/src/tint/utils/diagnostic/BUILD.bazel
index 8d4b83a..1211bf9 100644
--- a/src/tint/utils/diagnostic/BUILD.bazel
+++ b/src/tint/utils/diagnostic/BUILD.bazel
@@ -53,6 +53,12 @@
     "source.h",
   ],
   deps = [
+    "//src/tint/utils/containers",
+    "//src/tint/utils/ice",
+    "//src/tint/utils/macros",
+    "//src/tint/utils/math",
+    "//src/tint/utils/memory",
+    "//src/tint/utils/rtti",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
   ],
@@ -69,7 +75,13 @@
     "source_test.cc",
   ],
   deps = [
+    "//src/tint/utils/containers",
     "//src/tint/utils/diagnostic",
+    "//src/tint/utils/ice",
+    "//src/tint/utils/macros",
+    "//src/tint/utils/math",
+    "//src/tint/utils/memory",
+    "//src/tint/utils/rtti",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
     "@gtest",
diff --git a/src/tint/utils/diagnostic/BUILD.cmake b/src/tint/utils/diagnostic/BUILD.cmake
index dc7251c..47e5ed5 100644
--- a/src/tint/utils/diagnostic/BUILD.cmake
+++ b/src/tint/utils/diagnostic/BUILD.cmake
@@ -37,6 +37,12 @@
 )
 
 tint_target_add_dependencies(tint_utils_diagnostic lib
+  tint_utils_containers
+  tint_utils_ice
+  tint_utils_macros
+  tint_utils_math
+  tint_utils_memory
+  tint_utils_rtti
   tint_utils_text
   tint_utils_traits
 )
@@ -71,7 +77,13 @@
 )
 
 tint_target_add_dependencies(tint_utils_diagnostic_test test
+  tint_utils_containers
   tint_utils_diagnostic
+  tint_utils_ice
+  tint_utils_macros
+  tint_utils_math
+  tint_utils_memory
+  tint_utils_rtti
   tint_utils_text
   tint_utils_traits
 )
diff --git a/src/tint/utils/diagnostic/BUILD.gn b/src/tint/utils/diagnostic/BUILD.gn
index e99d811..90735ad 100644
--- a/src/tint/utils/diagnostic/BUILD.gn
+++ b/src/tint/utils/diagnostic/BUILD.gn
@@ -41,6 +41,12 @@
     "source.h",
   ]
   deps = [
+    "${tint_src_dir}/utils/containers",
+    "${tint_src_dir}/utils/ice",
+    "${tint_src_dir}/utils/macros",
+    "${tint_src_dir}/utils/math",
+    "${tint_src_dir}/utils/memory",
+    "${tint_src_dir}/utils/rtti",
     "${tint_src_dir}/utils/text",
     "${tint_src_dir}/utils/traits",
   ]
@@ -68,7 +74,13 @@
     ]
     deps = [
       "${tint_src_dir}:gmock_and_gtest",
+      "${tint_src_dir}/utils/containers",
       "${tint_src_dir}/utils/diagnostic",
+      "${tint_src_dir}/utils/ice",
+      "${tint_src_dir}/utils/macros",
+      "${tint_src_dir}/utils/math",
+      "${tint_src_dir}/utils/memory",
+      "${tint_src_dir}/utils/rtti",
       "${tint_src_dir}/utils/text",
       "${tint_src_dir}/utils/traits",
     ]
diff --git a/src/tint/utils/diagnostic/diagnostic.cc b/src/tint/utils/diagnostic/diagnostic.cc
index f108c44..887554d 100644
--- a/src/tint/utils/diagnostic/diagnostic.cc
+++ b/src/tint/utils/diagnostic/diagnostic.cc
@@ -43,9 +43,4 @@
     return Formatter{style}.format(*this);
 }
 
-std::ostream& operator<<(std::ostream& out, const List& list) {
-    out << list.str();
-    return out;
-}
-
 }  // namespace tint::diag
diff --git a/src/tint/utils/diagnostic/diagnostic.h b/src/tint/utils/diagnostic/diagnostic.h
index 0fb3f36..1b40cae 100644
--- a/src/tint/utils/diagnostic/diagnostic.h
+++ b/src/tint/utils/diagnostic/diagnostic.h
@@ -19,9 +19,10 @@
 #include <ostream>
 #include <string>
 #include <utility>
-#include <vector>
 
+#include "src/tint/utils/containers/vector.h"
 #include "src/tint/utils/diagnostic/source.h"
+#include "src/tint/utils/traits/traits.h"
 
 namespace tint::diag {
 
@@ -53,6 +54,7 @@
     Type,
     Utils,
     Writer,
+    Unknown,
 };
 
 /// Diagnostic holds all the information for a single compiler diagnostic
@@ -78,9 +80,6 @@
     std::string message;
     /// system is the Tint system that raised the diagnostic.
     System system;
-    /// code is the error code, for example a validation error might have the code
-    /// `"v-0001"`.
-    const char* code = nullptr;
     /// A shared pointer to a Source::File. Only used if the diagnostic Source
     /// points to a file that was created specifically for this diagnostic
     /// (usually an ICE).
@@ -91,7 +90,7 @@
 class List {
   public:
     /// iterator is the type used for range based iteration.
-    using iterator = std::vector<Diagnostic>::const_iterator;
+    using iterator = const Diagnostic*;
 
     /// Constructs the list with no elements.
     List();
@@ -128,7 +127,7 @@
         if (diag.severity >= Severity::Error) {
             error_count_++;
         }
-        entries_.emplace_back(std::move(diag));
+        entries_.Push(std::move(diag));
     }
 
     /// adds a list of diagnostics to the end of this list.
@@ -189,25 +188,6 @@
         add(std::move(error));
     }
 
-    /// adds the error message with the given code and Source to the end of this
-    /// list.
-    /// @param system the system raising the error message
-    /// @param code the error code
-    /// @param err_msg the error message
-    /// @param source the source of the error diagnostic
-    void add_error(System system,
-                   const char* code,
-                   std::string_view err_msg,
-                   const Source& source) {
-        diag::Diagnostic error{};
-        error.code = code;
-        error.severity = diag::Severity::Error;
-        error.system = system;
-        error.source = source;
-        error.message = err_msg;
-        add(std::move(error));
-    }
-
     /// adds an internal compiler error message to the end of this list.
     /// @param system the system raising the error message
     /// @param err_msg the error message
@@ -232,11 +212,11 @@
     /// @returns the number of error diagnostics (or of higher severity).
     size_t error_count() const { return error_count_; }
     /// @returns the number of entries in the list.
-    size_t count() const { return entries_.size(); }
+    size_t count() const { return entries_.Length(); }
     /// @returns true if the diagnostics list is empty
-    bool empty() const { return entries_.empty(); }
+    bool empty() const { return entries_.IsEmpty(); }
     /// @returns the number of entrise in the diagnostics list
-    size_t size() const { return entries_.size(); }
+    size_t size() const { return entries_.Length(); }
     /// @returns the first diagnostic in the list.
     iterator begin() const { return entries_.begin(); }
     /// @returns the last diagnostic in the list.
@@ -246,7 +226,7 @@
     std::string str() const;
 
   private:
-    std::vector<Diagnostic> entries_;
+    Vector<Diagnostic, 0> entries_;
     size_t error_count_ = 0;
 };
 
@@ -254,7 +234,10 @@
 /// @param out the output stream
 /// @param list the list to emit
 /// @returns the output stream
-std::ostream& operator<<(std::ostream& out, const List& list);
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, const List& list) {
+    return out << list.str();
+}
 
 }  // namespace tint::diag
 
diff --git a/src/tint/utils/diagnostic/formatter.cc b/src/tint/utils/diagnostic/formatter.cc
index 8c995d6..5c9fc95 100644
--- a/src/tint/utils/diagnostic/formatter.cc
+++ b/src/tint/utils/diagnostic/formatter.cc
@@ -129,7 +129,6 @@
 void Formatter::format(const Diagnostic& diag, State& state) const {
     auto const& src = diag.source;
     auto const& rng = src.range;
-    bool has_code = diag.code != nullptr && diag.code[0] != '\0';
 
     state.set_style({Color::kDefault, true});
 
@@ -170,9 +169,6 @@
     if (style_.print_severity) {
         prefix.emplace_back(TextAndColor{to_str(diag.severity), severity_color, true});
     }
-    if (has_code) {
-        prefix.emplace_back(TextAndColor{diag.code, severity_color});
-    }
 
     for (size_t i = 0; i < prefix.size(); i++) {
         if (i > 0) {
diff --git a/src/tint/utils/diagnostic/formatter_test.cc b/src/tint/utils/diagnostic/formatter_test.cc
index 242be15..f5a23cd 100644
--- a/src/tint/utils/diagnostic/formatter_test.cc
+++ b/src/tint/utils/diagnostic/formatter_test.cc
@@ -22,17 +22,12 @@
 namespace tint::diag {
 namespace {
 
-Diagnostic Diag(Severity severity,
-                Source source,
-                std::string message,
-                System system,
-                const char* code = nullptr) {
+Diagnostic Diag(Severity severity, Source source, std::string message, System system) {
     Diagnostic d;
     d.severity = severity;
     d.source = source;
     d.message = std::move(message);
     d.system = system;
-    d.code = code;
     return d;
 }
 
@@ -64,8 +59,7 @@
     Diagnostic ascii_diag_err = Diag(Severity::Error,
                                      Source{Source::Range{{3, 16}, {3, 21}}, &ascii_file},
                                      "hiss",
-                                     System::Test,
-                                     "abc123");
+                                     System::Test);
     Diagnostic ascii_diag_ice = Diag(Severity::InternalCompilerError,
                                      Source{Source::Range{{4, 16}, {4, 19}}, &ascii_file},
                                      "unreachable",
@@ -86,8 +80,7 @@
     Diagnostic utf8_diag_err = Diag(Severity::Error,
                                     Source{Source::Range{{3, 15}, {3, 20}}, &utf8_file},
                                     "hiss",
-                                    System::Test,
-                                    "abc123");
+                                    System::Test);
     Diagnostic utf8_diag_ice = Diag(Severity::InternalCompilerError,
                                     Source{Source::Range{{4, 15}, {4, 18}}, &utf8_file},
                                     "unreachable",
@@ -103,7 +96,7 @@
     auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
     auto* expect = R"(1:14: purr
 2:14: grrr
-3:16 abc123: hiss)";
+3:16: hiss)";
     ASSERT_EQ(expect, got);
 }
 
@@ -112,7 +105,7 @@
     auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
     auto* expect = R"(1:14: purr
 2:14: grrr
-3:16 abc123: hiss
+3:16: hiss
 )";
     ASSERT_EQ(expect, got);
 }
@@ -130,7 +123,7 @@
     auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
     auto* expect = R"(file.name:1:14: purr
 file.name:2:14: grrr
-file.name:3:16 abc123: hiss)";
+file.name:3:16: hiss)";
     ASSERT_EQ(expect, got);
 }
 
@@ -139,7 +132,7 @@
     auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
     auto* expect = R"(1:14 note: purr
 2:14 warning: grrr
-3:16 error abc123: hiss)";
+3:16 error: hiss)";
     ASSERT_EQ(expect, got);
 }
 
@@ -154,7 +147,7 @@
 the  dog  says  woof
                 ^^^^
 
-3:16 abc123: hiss
+3:16: hiss
 the  snake  says  quack
                   ^^^^^
 )";
@@ -171,7 +164,7 @@
         "2:15: grrr\n"
         "the  \xf0\x9f\x90\x95  says  woof\n"
         "\n"
-        "3:15 abc123: hiss\n"
+        "3:15: hiss\n"
         "the  \xf0\x9f\x90\x8d  says  quack\n";
     ASSERT_EQ(expect, got);
 }
@@ -187,7 +180,7 @@
 the  dog  says  woof
                 ^^^^
 
-file.name:3:16 error abc123: hiss
+file.name:3:16 error: hiss
 the  snake  says  quack
                   ^^^^^
 )";
@@ -234,7 +227,7 @@
 the    dog    says    woof
                       ^^^^
 
-file.name:3:16 error abc123: hiss
+file.name:3:16 error: hiss
 the    snake    says    quack
                         ^^^^^
 )";
diff --git a/src/tint/utils/generator/BUILD.bazel b/src/tint/utils/generator/BUILD.bazel
index 7885b9e..6f474ef 100644
--- a/src/tint/utils/generator/BUILD.bazel
+++ b/src/tint/utils/generator/BUILD.bazel
@@ -36,6 +36,9 @@
     "//src/tint/utils/diagnostic",
     "//src/tint/utils/ice",
     "//src/tint/utils/macros",
+    "//src/tint/utils/math",
+    "//src/tint/utils/memory",
+    "//src/tint/utils/rtti",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
   ],
diff --git a/src/tint/utils/generator/BUILD.cmake b/src/tint/utils/generator/BUILD.cmake
index b05cf02..7d8a660 100644
--- a/src/tint/utils/generator/BUILD.cmake
+++ b/src/tint/utils/generator/BUILD.cmake
@@ -35,6 +35,9 @@
   tint_utils_diagnostic
   tint_utils_ice
   tint_utils_macros
+  tint_utils_math
+  tint_utils_memory
+  tint_utils_rtti
   tint_utils_text
   tint_utils_traits
 )
diff --git a/src/tint/utils/generator/BUILD.gn b/src/tint/utils/generator/BUILD.gn
index e1d134c..cf3680b 100644
--- a/src/tint/utils/generator/BUILD.gn
+++ b/src/tint/utils/generator/BUILD.gn
@@ -35,6 +35,9 @@
     "${tint_src_dir}/utils/diagnostic",
     "${tint_src_dir}/utils/ice",
     "${tint_src_dir}/utils/macros",
+    "${tint_src_dir}/utils/math",
+    "${tint_src_dir}/utils/memory",
+    "${tint_src_dir}/utils/rtti",
     "${tint_src_dir}/utils/text",
     "${tint_src_dir}/utils/traits",
   ]
diff --git a/src/tint/utils/result/BUILD.bazel b/src/tint/utils/result/BUILD.bazel
index 56456e4..9c591ed 100644
--- a/src/tint/utils/result/BUILD.bazel
+++ b/src/tint/utils/result/BUILD.bazel
@@ -32,8 +32,13 @@
     "result.h",
   ],
   deps = [
+    "//src/tint/utils/containers",
+    "//src/tint/utils/diagnostic",
     "//src/tint/utils/ice",
     "//src/tint/utils/macros",
+    "//src/tint/utils/math",
+    "//src/tint/utils/memory",
+    "//src/tint/utils/rtti",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
   ],
@@ -47,9 +52,14 @@
     "result_test.cc",
   ],
   deps = [
+    "//src/tint/utils/containers",
+    "//src/tint/utils/diagnostic",
     "//src/tint/utils/ice",
     "//src/tint/utils/macros",
+    "//src/tint/utils/math",
+    "//src/tint/utils/memory",
     "//src/tint/utils/result",
+    "//src/tint/utils/rtti",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
     "@gtest",
diff --git a/src/tint/utils/result/BUILD.cmake b/src/tint/utils/result/BUILD.cmake
index 13ab5a3..cd482ee 100644
--- a/src/tint/utils/result/BUILD.cmake
+++ b/src/tint/utils/result/BUILD.cmake
@@ -31,8 +31,13 @@
 )
 
 tint_target_add_dependencies(tint_utils_result lib
+  tint_utils_containers
+  tint_utils_diagnostic
   tint_utils_ice
   tint_utils_macros
+  tint_utils_math
+  tint_utils_memory
+  tint_utils_rtti
   tint_utils_text
   tint_utils_traits
 )
@@ -46,9 +51,14 @@
 )
 
 tint_target_add_dependencies(tint_utils_result_test test
+  tint_utils_containers
+  tint_utils_diagnostic
   tint_utils_ice
   tint_utils_macros
+  tint_utils_math
+  tint_utils_memory
   tint_utils_result
+  tint_utils_rtti
   tint_utils_text
   tint_utils_traits
 )
diff --git a/src/tint/utils/result/BUILD.gn b/src/tint/utils/result/BUILD.gn
index 4baa0ea..f607347 100644
--- a/src/tint/utils/result/BUILD.gn
+++ b/src/tint/utils/result/BUILD.gn
@@ -35,8 +35,13 @@
     "result.h",
   ]
   deps = [
+    "${tint_src_dir}/utils/containers",
+    "${tint_src_dir}/utils/diagnostic",
     "${tint_src_dir}/utils/ice",
     "${tint_src_dir}/utils/macros",
+    "${tint_src_dir}/utils/math",
+    "${tint_src_dir}/utils/memory",
+    "${tint_src_dir}/utils/rtti",
     "${tint_src_dir}/utils/text",
     "${tint_src_dir}/utils/traits",
   ]
@@ -47,9 +52,14 @@
     sources = [ "result_test.cc" ]
     deps = [
       "${tint_src_dir}:gmock_and_gtest",
+      "${tint_src_dir}/utils/containers",
+      "${tint_src_dir}/utils/diagnostic",
       "${tint_src_dir}/utils/ice",
       "${tint_src_dir}/utils/macros",
+      "${tint_src_dir}/utils/math",
+      "${tint_src_dir}/utils/memory",
       "${tint_src_dir}/utils/result",
+      "${tint_src_dir}/utils/rtti",
       "${tint_src_dir}/utils/text",
       "${tint_src_dir}/utils/traits",
     ]
diff --git a/src/tint/utils/result/result.cc b/src/tint/utils/result/result.cc
index add6f74..5bb029e 100644
--- a/src/tint/utils/result/result.cc
+++ b/src/tint/utils/result/result.cc
@@ -14,9 +14,14 @@
 
 #include "src/tint/utils/result/result.h"
 
-#if defined(__clang__)
-#pragma clang diagnostic ignored "-Wmissing-variable-declarations"
-#endif
+namespace tint {
 
-// A placeholder symbol used to emit a symbol for this lib target.
-int tint_utils_result_symbol = 1;
+Failure::Failure() = default;
+
+Failure::Failure(std::string_view err) {
+    reason.add_error(diag::System::Unknown, err, Source{});
+}
+
+Failure::Failure(diag::List diagnostics) : reason(diagnostics) {}
+
+}  // namespace tint
diff --git a/src/tint/utils/result/result.h b/src/tint/utils/result/result.h
index f79468b..8e51b44 100644
--- a/src/tint/utils/result/result.h
+++ b/src/tint/utils/result/result.h
@@ -18,6 +18,7 @@
 #include <utility>
 #include <variant>
 
+#include "src/tint/utils/diagnostic/diagnostic.h"
 #include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/text/string_stream.h"
 #include "src/tint/utils/traits/traits.h"
@@ -30,11 +31,31 @@
 /// An instance of SuccessType that can be used as a generic success value for a Result.
 static constexpr const SuccessType Success;
 
-/// Empty structure used as the default FAILURE_TYPE for a Result.
-struct FailureType {};
+/// The default Result error type.
+struct Failure {
+    /// Constructor with no diagnostics
+    Failure();
 
-/// An instance of FailureType which can be used as a generic failure value by Result
-static constexpr const FailureType Failure;
+    /// Constructor with a single diagnostic
+    /// @param err the single error diagnostic
+    explicit Failure(std::string_view err);
+
+    /// Constructor with a list of diagnostics
+    /// @param diagnostics the failure diagnostics
+    explicit Failure(diag::List diagnostics);
+
+    /// The diagnostics explaining the failure reason
+    diag::List reason;
+};
+
+/// Write the Failure to the given stream
+/// @param out the output stream
+/// @param failure the Failure
+/// @returns the output stream
+template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
+auto& operator<<(STREAM& out, const Failure& failure) {
+    return out << failure.reason;
+}
 
 /// Result is a helper for functions that need to return a value, or an failure value.
 /// Result can be constructed with either a 'success' or 'failure' value.
@@ -42,7 +63,7 @@
 /// @tparam FAILURE_TYPE the 'failure' value type. Defaults to FailureType which provides no
 ///         information about the failure, except that something failed. Must not be the same type
 ///         as SUCCESS_TYPE.
-template <typename SUCCESS_TYPE, typename FAILURE_TYPE = FailureType>
+template <typename SUCCESS_TYPE, typename FAILURE_TYPE = Failure>
 struct [[nodiscard]] Result {
     static_assert(!std::is_same_v<SUCCESS_TYPE, FAILURE_TYPE>,
                   "Result must not have the same type for SUCCESS_TYPE and FAILURE_TYPE");
@@ -168,8 +189,20 @@
           typename SUCCESS,
           typename FAILURE,
           typename = traits::EnableIfIsOStream<STREAM>>
-auto& operator<<(STREAM& out, Result<SUCCESS, FAILURE> res) {
-    return res ? (out << "success: " << res.Get()) : (out << "failure: " << res.Failure());
+auto& operator<<(STREAM& out, const Result<SUCCESS, FAILURE>& res) {
+    if (res) {
+        if constexpr (traits::HasOperatorShiftLeft<STREAM&, SUCCESS>) {
+            return out << "success: " << res.Get();
+        } else {
+            return out << "success";
+        }
+    } else {
+        if constexpr (traits::HasOperatorShiftLeft<STREAM&, FAILURE>) {
+            return out << "failure: " << res.Failure();
+        } else {
+            return out << "failure";
+        }
+    }
 }
 
 }  // namespace tint
diff --git a/src/tint/utils/result/result_test.cc b/src/tint/utils/result/result_test.cc
index 35ed8cf..6f01df8 100644
--- a/src/tint/utils/result/result_test.cc
+++ b/src/tint/utils/result/result_test.cc
@@ -39,7 +39,7 @@
 }
 
 TEST(ResultTest, Failure) {
-    auto r = Result<int>(Failure);
+    auto r = Result<int>(Failure{});
     EXPECT_FALSE(r);
     EXPECT_TRUE(!r);
 }
diff --git a/src/tint/utils/strconv/BUILD.bazel b/src/tint/utils/strconv/BUILD.bazel
index 74331d3..86eefce 100644
--- a/src/tint/utils/strconv/BUILD.bazel
+++ b/src/tint/utils/strconv/BUILD.bazel
@@ -34,9 +34,14 @@
     "parse_num.h",
   ],
   deps = [
+    "//src/tint/utils/containers",
+    "//src/tint/utils/diagnostic",
     "//src/tint/utils/ice",
     "//src/tint/utils/macros",
+    "//src/tint/utils/math",
+    "//src/tint/utils/memory",
     "//src/tint/utils/result",
+    "//src/tint/utils/rtti",
     "//src/tint/utils/text",
     "//src/tint/utils/traits",
     "@abseil_cpp//absl/strings",
diff --git a/src/tint/utils/strconv/BUILD.cmake b/src/tint/utils/strconv/BUILD.cmake
index abb1139..47ccddc 100644
--- a/src/tint/utils/strconv/BUILD.cmake
+++ b/src/tint/utils/strconv/BUILD.cmake
@@ -33,9 +33,14 @@
 )
 
 tint_target_add_dependencies(tint_utils_strconv lib
+  tint_utils_containers
+  tint_utils_diagnostic
   tint_utils_ice
   tint_utils_macros
+  tint_utils_math
+  tint_utils_memory
   tint_utils_result
+  tint_utils_rtti
   tint_utils_text
   tint_utils_traits
 )
diff --git a/src/tint/utils/strconv/BUILD.gn b/src/tint/utils/strconv/BUILD.gn
index 11b33f6..e386dcb 100644
--- a/src/tint/utils/strconv/BUILD.gn
+++ b/src/tint/utils/strconv/BUILD.gn
@@ -38,9 +38,14 @@
   ]
   deps = [
     "${tint_src_dir}:abseil",
+    "${tint_src_dir}/utils/containers",
+    "${tint_src_dir}/utils/diagnostic",
     "${tint_src_dir}/utils/ice",
     "${tint_src_dir}/utils/macros",
+    "${tint_src_dir}/utils/math",
+    "${tint_src_dir}/utils/memory",
     "${tint_src_dir}/utils/result",
+    "${tint_src_dir}/utils/rtti",
     "${tint_src_dir}/utils/text",
     "${tint_src_dir}/utils/traits",
   ]
diff --git a/src/tint/utils/traits/traits.h b/src/tint/utils/traits/traits.h
index 62071c7..ff1a24d 100644
--- a/src/tint/utils/traits/traits.h
+++ b/src/tint/utils/traits/traits.h
@@ -209,6 +209,9 @@
 template <typename T>
 using CharArrayToCharPtr = typename traits::detail::CharArrayToCharPtrImpl<T>::type;
 
+////////////////////////////////////////////////////////////////////////////////
+// IsOStream
+////////////////////////////////////////////////////////////////////////////////
 namespace detail {
 /// Helper for determining whether the type T can be used as a stream writer
 template <typename T, typename ENABLE = void>
@@ -239,6 +242,26 @@
 template <typename T = void>
 using EnableIfIsOStream = EnableIf<IsOStream<T>, T>;
 
+////////////////////////////////////////////////////////////////////////////////
+// HasOperatorShiftLeft
+////////////////////////////////////////////////////////////////////////////////
+namespace detail {
+/// Helper for determining whether the operator<<(LHS, RHS) exists
+template <typename LHS, typename RHS, typename = void>
+struct HasOperatorShiftLeft : std::false_type {};
+/// Specialization to detect operator
+template <typename LHS, typename RHS>
+struct HasOperatorShiftLeft<LHS,
+                            RHS,
+                            std::void_t<decltype((std::declval<LHS>() << std::declval<RHS>()))>>
+    : std::true_type {};
+
+}  // namespace detail
+
+/// Is true if operator<<(LHS, RHS) exists
+template <typename LHS, typename RHS>
+static constexpr bool HasOperatorShiftLeft = detail::HasOperatorShiftLeft<LHS, RHS>::value;
+
 }  // namespace tint::traits
 
 #endif  // SRC_TINT_UTILS_TRAITS_TRAITS_H_