Import Tint changes from Dawn

Changes:
  - c11e2ed2572c4ea87355112d48a990c10951df07 Make OFI transform push_constant-friendly. by Stephen White <senorblanco@chromium.org>
  - 522d475b6e03e22bb68e2eeb472292aeffa53293 Update message when indexing a scalar. by dan sinclair <dsinclair@chromium.org>
  - b1a05445b2382b94484fc47b36610077cf1e3306 [tint] Add vector overloads of subgroupBroadcast by James Price <jrprice@google.com>
  - bdc7e32ee461c1636cad7c01eae60690cbe6b6f9 Add deprecated proxy methods. by dan sinclair <dsinclair@chromium.org>
  - 12e659c1781fc666e92b09acc52e36f92ab61f8a [tint] Fix build by Ben Clayton <bclayton@google.com>
  - 26a41b967eb39c6ad9c8685e12941c910d5fc62c dawn: use binding information for HLSL interface by Antonio Maiorano <amaiorano@google.com>
  - 76aec2564a48cf67f669164e57d8def61c1b608c [tint] Reduce all hash codes to 32 bits by Ben Clayton <bclayton@google.com>
  - 4effffbfb5b41283b03dc3121521fbf272448898 [tint] Replace HashCode with TypeCode and TypeCodeSet by Ben Clayton <bclayton@google.com>
  - 9dc42add8fdeb00c36aaaa3ed2d19d4bdfbc6ab6 [tint][ast] Fix type <-> parameter shadowing issues. by Ben Clayton <bclayton@google.com>
  - ec817fd5805b7a4d8c2f529119b74355838e4e00 [tint] Move 'pointer_composite_access' to kShippedWithKil... by Ben Clayton <bclayton@google.com>
  - 1e1f488f3ea12a8be5795ba9cad2bacb275accb6 [tint][utils] PascalCase tint::diag functions by Ben Clayton <bclayton@google.com>
  - 1c5c26632a3aa4496fc14d2c4000789cf0974cb5 GLSL: move the AddBlockAttribute transform before OffsetF... by Stephen White <senorblanco@chromium.org>
  - 2817c2b745ffb971bee36bc006a37dfce07c64b1 [tint][fuzz] Fix signature of LLVMFuzzerInitialize() by Ben Clayton <bclayton@google.com>
  - 2555f180bf0d7180fe8767782b5e0f6ba3204fc9 [tint] Add TINT_ASSERT_ALL_FIELDS_REFLECTED() macro by Ben Clayton <bclayton@google.com>
GitOrigin-RevId: c11e2ed2572c4ea87355112d48a990c10951df07
Change-Id: Id1073dceaa6de6d536014c50cae3af0e1d205089
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/173500
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/api/common/binding_point.h b/src/tint/api/common/binding_point.h
index 64d61f6..2c6baa5 100644
--- a/src/tint/api/common/binding_point.h
+++ b/src/tint/api/common/binding_point.h
@@ -46,7 +46,10 @@
     uint32_t binding = 0;
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(group, binding);
+    TINT_REFLECT(BindingPoint, group, binding);
+
+    /// @returns the hash code of the BindingPoint
+    tint::HashCode HashCode() const { return tint::Hash(group, binding); }
 
     /// Equality operator
     /// @param rhs the BindingPoint to compare against
@@ -74,6 +77,9 @@
     }
 };
 
+/// Ensure that all the fields of BindingPoint are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(BindingPoint);
+
 /// Prints the BindingPoint @p bp to @p o
 /// @param o the stream to write to
 /// @param bp the BindingPoint
@@ -94,8 +100,9 @@
   public:
     /// @param binding_point the binding point to create a hash for
     /// @return the hash value
-    inline std::size_t operator()(const tint::BindingPoint& binding_point) const {
-        return tint::Hash(binding_point.group, binding_point.binding);
+    inline size_t operator()(const tint::BindingPoint& binding_point) const {
+        return static_cast<size_t>(binding_point.group) << 16 |
+               static_cast<size_t>(binding_point.binding);
     }
 };
 
diff --git a/src/tint/api/common/override_id.h b/src/tint/api/common/override_id.h
index 70abc33..99e9d6a 100644
--- a/src/tint/api/common/override_id.h
+++ b/src/tint/api/common/override_id.h
@@ -31,6 +31,7 @@
 #include <stdint.h>
 #include <functional>
 
+#include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/reflection/reflection.h"
 
 namespace tint {
@@ -41,9 +42,15 @@
     uint16_t value = 0;
 
     /// Reflect the fields of this struct so that it can be used by tint::ForeachField()
-    TINT_REFLECT(value);
+    TINT_REFLECT(OverrideId, value);
+
+    /// @returns the hash code of the OverrideId
+    tint::HashCode HashCode() const { return Hash(value); }
 };
 
+/// Ensure that all the fields of OverrideId are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(OverrideId);
+
 /// Equality operator for OverrideId
 /// @param lhs the OverrideId on the left of the '=' operator
 /// @param rhs the OverrideId on the right of the '=' operator
@@ -70,7 +77,7 @@
   public:
     /// @param id the override identifier
     /// @return the hash of the override identifier
-    inline std::size_t operator()(tint::OverrideId id) const {
+    inline size_t operator()(tint::OverrideId id) const {
         return std::hash<decltype(tint::OverrideId::value)>()(id.value);
     }
 };
diff --git a/src/tint/api/options/array_length_from_uniform.h b/src/tint/api/options/array_length_from_uniform.h
index ba7094a..f46825f 100644
--- a/src/tint/api/options/array_length_from_uniform.h
+++ b/src/tint/api/options/array_length_from_uniform.h
@@ -45,9 +45,12 @@
     std::unordered_map<BindingPoint, uint32_t> bindpoint_to_size_index;
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(ubo_binding, bindpoint_to_size_index);
+    TINT_REFLECT(ArrayLengthFromUniformOptions, ubo_binding, bindpoint_to_size_index);
 };
 
+/// Ensure that all the fields of ArrayLengthFromUniformOptions are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(ArrayLengthFromUniformOptions);
+
 }  // namespace tint
 
 #endif  // SRC_TINT_API_OPTIONS_ARRAY_LENGTH_FROM_UNIFORM_H_
diff --git a/src/tint/api/options/binding_remapper.h b/src/tint/api/options/binding_remapper.h
index 493c854..4e1e4f8 100644
--- a/src/tint/api/options/binding_remapper.h
+++ b/src/tint/api/options/binding_remapper.h
@@ -43,9 +43,12 @@
     BindingPoints binding_points;
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(binding_points);
+    TINT_REFLECT(BindingRemapperOptions, binding_points);
 };
 
+/// Ensure that all the fields of BindingRemapperOptions are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(BindingRemapperOptions);
+
 }  // namespace tint
 
 #endif  // SRC_TINT_API_OPTIONS_BINDING_REMAPPER_H_
diff --git a/src/tint/api/options/external_texture.h b/src/tint/api/options/external_texture.h
index ff01aec..76e7898 100644
--- a/src/tint/api/options/external_texture.h
+++ b/src/tint/api/options/external_texture.h
@@ -47,7 +47,7 @@
         BindingPoint params;
 
         /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-        TINT_REFLECT(plane_1, params);
+        TINT_REFLECT(BindingPoints, plane_1, params);
     };
 
     /// BindingsMap is a map where the key is the binding location of a
@@ -59,9 +59,15 @@
     BindingsMap bindings_map;
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(bindings_map);
+    TINT_REFLECT(ExternalTextureOptions, bindings_map);
 };
 
+/// Ensure that all the fields of ExternalTextureOptions::BindingPoints are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(ExternalTextureOptions::BindingPoints);
+
+/// Ensure that all the fields of ExternalTextureOptions are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(ExternalTextureOptions);
+
 }  // namespace tint
 
 #endif  // SRC_TINT_API_OPTIONS_EXTERNAL_TEXTURE_H_
diff --git a/src/tint/api/options/pixel_local.h b/src/tint/api/options/pixel_local.h
index 1b4e200..64022c3 100644
--- a/src/tint/api/options/pixel_local.h
+++ b/src/tint/api/options/pixel_local.h
@@ -54,9 +54,12 @@
     uint32_t pixel_local_group_index = 0;
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(attachments, attachment_formats, pixel_local_group_index);
+    TINT_REFLECT(PixelLocalOptions, attachments, attachment_formats, pixel_local_group_index);
 };
 
+/// Ensure that all the fields of PixelLocalOptions are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(PixelLocalOptions);
+
 /// Reflect valid value ranges for the PixelLocalOptions::TexelFormat enum.
 TINT_REFLECT_ENUM_RANGE(PixelLocalOptions::TexelFormat, kR32Sint, kR32Float);
 
diff --git a/src/tint/api/options/texture_builtins_from_uniform.h b/src/tint/api/options/texture_builtins_from_uniform.h
index ac107e5..b929c6b 100644
--- a/src/tint/api/options/texture_builtins_from_uniform.h
+++ b/src/tint/api/options/texture_builtins_from_uniform.h
@@ -47,9 +47,12 @@
     std::vector<BindingPoint> ubo_bindingpoint_ordering = {};
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(ubo_binding, ubo_bindingpoint_ordering);
+    TINT_REFLECT(TextureBuiltinsFromUniformOptions, ubo_binding, ubo_bindingpoint_ordering);
 };
 
+/// Ensure that all the fields of TextureBuiltinsFromUniformOptions are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(TextureBuiltinsFromUniformOptions);
+
 }  // namespace tint
 
 #endif  // SRC_TINT_API_OPTIONS_TEXTURE_BUILTINS_FROM_UNIFORM_H_
diff --git a/src/tint/api/tint.cc b/src/tint/api/tint.cc
index 8a48cea..3337b23 100644
--- a/src/tint/api/tint.cc
+++ b/src/tint/api/tint.cc
@@ -71,7 +71,7 @@
     tint::Program::printer = [](const tint::Program& program) {
         auto result = wgsl::writer::Generate(program, {});
         if (result != Success) {
-            return result.Failure().reason.str();
+            return result.Failure().reason.Str();
         }
         return result->wgsl;
     };
diff --git a/src/tint/cmd/common/helper.cc b/src/tint/cmd/common/helper.cc
index 3e54e9f..4dd0ea1 100644
--- a/src/tint/cmd/common/helper.cc
+++ b/src/tint/cmd/common/helper.cc
@@ -127,7 +127,7 @@
             opts.spirv_reader_options.allow_non_uniform_derivatives;
         options.allowed_features = opts.spirv_reader_options.allowed_features;
         auto ast = tint::wgsl::writer::IRToProgram(result.Get(), options);
-        if (!ast.IsValid() || ast.Diagnostics().contains_errors()) {
+        if (!ast.IsValid() || ast.Diagnostics().ContainsErrors()) {
             std::cerr << "Failed to convert IR to AST:\n\n" << ast.Diagnostics() << "\n";
             exit(1);
         }
@@ -145,9 +145,9 @@
 }  // namespace
 
 [[noreturn]] void TintInternalCompilerErrorReporter(const InternalCompilerError& err) {
-    auto printer = diag::Printer::create(stderr, true);
+    auto printer = diag::Printer::Create(stderr, true);
     diag::Style bold_red{diag::Color::kRed, true};
-    printer->write(err.Error(), bold_red);
+    printer->Write(err.Error(), bold_red);
     constexpr const char* please_file_bug = R"(
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
@@ -156,7 +156,7 @@
 *  crbug.com/tint with the source program that triggered the bug.  *
 ********************************************************************
 )";
-    printer->write(please_file_bug, bold_red);
+    printer->Write(please_file_bug, bold_red);
     exit(1);
 }
 
@@ -260,16 +260,16 @@
 
     ProgramInfo info = load();
 
-    if (info.program.Diagnostics().count() > 0) {
+    if (info.program.Diagnostics().Count() > 0) {
         if (!info.program.IsValid() && input_format != InputFormat::kWgsl) {
             // Invalid program from a non-wgsl source.
             // Print the WGSL, to help understand the diagnostics.
             PrintWGSL(std::cout, info.program);
         }
 
-        auto diag_printer = tint::diag::Printer::create(stderr, true);
+        auto diag_printer = tint::diag::Printer::Create(stderr, true);
         tint::diag::Formatter diag_formatter;
-        diag_formatter.format(info.program.Diagnostics(), diag_printer.get());
+        diag_formatter.Format(info.program.Diagnostics(), diag_printer.get());
     }
 
     if (!info.program.IsValid()) {
diff --git a/src/tint/cmd/fuzz/wgsl/main_fuzz.cc b/src/tint/cmd/fuzz/wgsl/main_fuzz.cc
index 8fa2c0f..9762952 100644
--- a/src/tint/cmd/fuzz/wgsl/main_fuzz.cc
+++ b/src/tint/cmd/fuzz/wgsl/main_fuzz.cc
@@ -47,7 +47,7 @@
     return 0;
 }
 
-extern "C" int LLVMFuzzerInitialize(int* argc, const char*** argv) {
+extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
     tint::cli::OptionSet opts;
 
     tint::Vector<std::string_view, 8> arguments;
@@ -64,9 +64,9 @@
         std::cerr << std::endl;
         // Change args to show libfuzzer help
         std::cerr << "Standard libfuzzer ";  // libfuzzer will print 'Usage:'
-        static const char* help[] = {(*argv)[0], "-help=1"};
+        static char help[] = "-help=1";
         *argc = 2;
-        *argv = help;
+        (*argv)[1] = help;
     };
 
     auto& opt_help = opts.Add<tint::cli::BoolOption>("help", "shows the usage");
diff --git a/src/tint/cmd/loopy/BUILD.bazel b/src/tint/cmd/loopy/BUILD.bazel
index 1b0859f..9a2c3ad 100644
--- a/src/tint/cmd/loopy/BUILD.bazel
+++ b/src/tint/cmd/loopy/BUILD.bazel
@@ -51,6 +51,7 @@
     "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/hlsl/writer/common",
+    "//src/tint/lang/hlsl/writer/helpers",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
     "//src/tint/lang/wgsl/common",
diff --git a/src/tint/cmd/loopy/BUILD.cmake b/src/tint/cmd/loopy/BUILD.cmake
index 2597a47..ad75e1a 100644
--- a/src/tint/cmd/loopy/BUILD.cmake
+++ b/src/tint/cmd/loopy/BUILD.cmake
@@ -52,6 +52,7 @@
   tint_lang_core_ir
   tint_lang_core_type
   tint_lang_hlsl_writer_common
+  tint_lang_hlsl_writer_helpers
   tint_lang_wgsl
   tint_lang_wgsl_ast
   tint_lang_wgsl_common
diff --git a/src/tint/cmd/loopy/BUILD.gn b/src/tint/cmd/loopy/BUILD.gn
index 5176168..f578df9 100644
--- a/src/tint/cmd/loopy/BUILD.gn
+++ b/src/tint/cmd/loopy/BUILD.gn
@@ -51,6 +51,7 @@
     "${tint_src_dir}/lang/core/ir",
     "${tint_src_dir}/lang/core/type",
     "${tint_src_dir}/lang/hlsl/writer/common",
+    "${tint_src_dir}/lang/hlsl/writer/helpers",
     "${tint_src_dir}/lang/wgsl",
     "${tint_src_dir}/lang/wgsl/ast",
     "${tint_src_dir}/lang/wgsl/common",
diff --git a/src/tint/cmd/loopy/main.cc b/src/tint/cmd/loopy/main.cc
index ccd8b23..89bbcb3 100644
--- a/src/tint/cmd/loopy/main.cc
+++ b/src/tint/cmd/loopy/main.cc
@@ -37,6 +37,7 @@
 #endif  // TINT_BUILD_GLSL_WRITER
 
 #if TINT_BUILD_HLSL_WRITER
+#include "src/tint/lang/hlsl/writer/helpers/generate_bindings.h"
 #include "src/tint/lang/hlsl/writer/writer.h"
 #endif  // TINT_BUILD_HLSL_WRITER
 
@@ -282,8 +283,7 @@
 bool GenerateHlsl(const tint::Program& program) {
 #if TINT_BUILD_HLSL_WRITER
     tint::hlsl::writer::Options gen_options;
-    gen_options.external_texture_options.bindings_map =
-        tint::cmd::GenerateExternalTextureBindings(program);
+    gen_options.bindings = tint::hlsl::writer::GenerateBindings(program);
     auto result = tint::hlsl::writer::Generate(program, gen_options);
     if (result != tint::Success) {
         tint::cmd::PrintWGSL(std::cerr, program);
diff --git a/src/tint/cmd/tint/BUILD.bazel b/src/tint/cmd/tint/BUILD.bazel
index fbc1286..d77264b 100644
--- a/src/tint/cmd/tint/BUILD.bazel
+++ b/src/tint/cmd/tint/BUILD.bazel
@@ -51,6 +51,7 @@
     "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/hlsl/writer/common",
+    "//src/tint/lang/hlsl/writer/helpers",
     "//src/tint/lang/wgsl",
     "//src/tint/lang/wgsl/ast",
     "//src/tint/lang/wgsl/ast/transform",
diff --git a/src/tint/cmd/tint/BUILD.cmake b/src/tint/cmd/tint/BUILD.cmake
index 9a02dfe..f354d49 100644
--- a/src/tint/cmd/tint/BUILD.cmake
+++ b/src/tint/cmd/tint/BUILD.cmake
@@ -52,6 +52,7 @@
   tint_lang_core_ir
   tint_lang_core_type
   tint_lang_hlsl_writer_common
+  tint_lang_hlsl_writer_helpers
   tint_lang_wgsl
   tint_lang_wgsl_ast
   tint_lang_wgsl_ast_transform
diff --git a/src/tint/cmd/tint/BUILD.gn b/src/tint/cmd/tint/BUILD.gn
index 5d0447f..e51fbf4 100644
--- a/src/tint/cmd/tint/BUILD.gn
+++ b/src/tint/cmd/tint/BUILD.gn
@@ -51,6 +51,7 @@
     "${tint_src_dir}/lang/core/ir",
     "${tint_src_dir}/lang/core/type",
     "${tint_src_dir}/lang/hlsl/writer/common",
+    "${tint_src_dir}/lang/hlsl/writer/helpers",
     "${tint_src_dir}/lang/wgsl",
     "${tint_src_dir}/lang/wgsl/ast",
     "${tint_src_dir}/lang/wgsl/ast/transform",
diff --git a/src/tint/cmd/tint/main.cc b/src/tint/cmd/tint/main.cc
index 22add27..81a9e5b 100644
--- a/src/tint/cmd/tint/main.cc
+++ b/src/tint/cmd/tint/main.cc
@@ -83,6 +83,7 @@
 
 #if TINT_BUILD_HLSL_WRITER
 #include "src/tint/lang/hlsl/validate/validate.h"
+#include "src/tint/lang/hlsl/writer/helpers/generate_bindings.h"
 #include "src/tint/lang/hlsl/writer/writer.h"
 #endif  // TINT_BUILD_HLSL_WRITER
 
@@ -776,9 +777,9 @@
         auto source = std::make_unique<tint::Source::File>(options.input_filename, result->wgsl);
         auto reparsed_program = tint::wgsl::reader::Parse(source.get(), parser_options);
         if (!reparsed_program.IsValid()) {
-            auto diag_printer = tint::diag::Printer::create(stderr, true);
+            auto diag_printer = tint::diag::Printer::Create(stderr, true);
             tint::diag::Formatter diag_formatter;
-            diag_formatter.format(reparsed_program.Diagnostics(), diag_printer.get());
+            diag_formatter.Format(reparsed_program.Diagnostics(), diag_printer.get());
             return false;
         }
     }
@@ -915,8 +916,7 @@
     tint::hlsl::writer::Options gen_options;
     gen_options.disable_robustness = !options.enable_robustness;
     gen_options.disable_workgroup_init = options.disable_workgroup_init;
-    gen_options.external_texture_options.bindings_map =
-        tint::cmd::GenerateExternalTextureBindings(program);
+    gen_options.bindings = tint::hlsl::writer::GenerateBindings(program);
     gen_options.root_constant_binding_point = options.hlsl_root_constant_binding_point;
     gen_options.pixel_local_options = options.pixel_local_options;
     gen_options.polyfill_dot_4x8_packed = options.hlsl_shader_model < kMinShaderModelForDP4aInHLSL;
@@ -1067,6 +1067,10 @@
 
         gen_options.texture_builtins_from_uniform = std::move(textureBuiltinsFromUniform);
 
+        // Place the first_instance push constant member after user-defined push constants (if any).
+        gen_options.first_instance_offset =
+            inspector.GetEntryPoint(entry_point_name).push_constant_size;
+
         auto result = tint::glsl::writer::Generate(prg, gen_options, entry_point_name);
         if (result != tint::Success) {
             tint::cmd::PrintWGSL(std::cerr, prg);
diff --git a/src/tint/fuzzers/BUILD.gn b/src/tint/fuzzers/BUILD.gn
index b570ed4..bf83f01 100644
--- a/src/tint/fuzzers/BUILD.gn
+++ b/src/tint/fuzzers/BUILD.gn
@@ -85,6 +85,7 @@
       "${tint_src_dir}/lang/core/type",
       "${tint_src_dir}/lang/glsl/writer",
       "${tint_src_dir}/lang/hlsl/writer",
+      "${tint_src_dir}/lang/hlsl/writer/helpers",
       "${tint_src_dir}/lang/msl/writer",
       "${tint_src_dir}/lang/msl/writer/helpers",
       "${tint_src_dir}/lang/spirv/writer",
diff --git a/src/tint/fuzzers/CMakeLists.txt b/src/tint/fuzzers/CMakeLists.txt
index 136afd3..134f6ca 100644
--- a/src/tint/fuzzers/CMakeLists.txt
+++ b/src/tint/fuzzers/CMakeLists.txt
@@ -51,6 +51,7 @@
     tint_spvheaders_compile_options(${NAME})
     tint_spvtools_compile_options(${NAME})
   endif()
+  target_link_libraries(${NAME} PRIVATE tint_lang_hlsl_writer_helpers)
   target_link_libraries(${NAME} PRIVATE tint_lang_msl_writer_helpers)
   target_link_libraries(${NAME} PRIVATE tint_lang_spirv_writer_helpers)
   target_compile_options(${NAME} PRIVATE -Wno-missing-prototypes)
diff --git a/src/tint/fuzzers/random_generator.cc b/src/tint/fuzzers/random_generator.cc
index 3965b1c..5bcf4cd 100644
--- a/src/tint/fuzzers/random_generator.cc
+++ b/src/tint/fuzzers/random_generator.cc
@@ -33,7 +33,6 @@
 
 #include "src/tint/fuzzers/mersenne_twister_engine.h"
 #include "src/tint/fuzzers/random_generator_engine.h"
-#include "src/tint/utils/math/hash.h"
 
 namespace tint::fuzzers {
 
@@ -47,9 +46,9 @@
 /// @param size - number of elements in buffer
 /// @returns hash of the data in the buffer
 size_t HashBuffer(const uint8_t* data, const size_t size) {
-    size_t hash = Hash(size);
+    size_t hash = std::hash<size_t>{}(size);
     for (size_t i = 0; i < size; i++) {
-        hash = HashCombine(hash, data[i]);
+        hash ^= (static_cast<uint64_t>(data[i]) * 31) + (0x7f4a7c16 ^ (hash >> 2));
     }
     return hash;
 }
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/CMakeLists.txt b/src/tint/fuzzers/tint_ast_fuzzer/CMakeLists.txt
index fbdb3b9..d4a7050 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/CMakeLists.txt
+++ b/src/tint/fuzzers/tint_ast_fuzzer/CMakeLists.txt
@@ -27,8 +27,9 @@
 
 function(add_tint_ast_fuzzer NAME)
   add_executable(${NAME} ${NAME}.cc ${AST_FUZZER_SOURCES})
-  target_link_libraries(${NAME} PRIVATE libtint_ast_fuzzer tint_lang_spirv_writer_helpers)
+  target_link_libraries(${NAME} PRIVATE libtint_ast_fuzzer tint_lang_hlsl_writer_helpers)
   target_link_libraries(${NAME} PRIVATE libtint_ast_fuzzer tint_lang_msl_writer_helpers)
+  target_link_libraries(${NAME} PRIVATE libtint_ast_fuzzer tint_lang_spirv_writer_helpers)
   tint_fuzzer_compile_options(${NAME})
   if(TINT_BUILD_SPV_READER OR TINT_BUILD_SPV_WRITER)
     tint_spvheaders_compile_options(${NAME})
diff --git a/src/tint/fuzzers/tint_common_fuzzer.cc b/src/tint/fuzzers/tint_common_fuzzer.cc
index 99f50c9..a50ca8e 100644
--- a/src/tint/fuzzers/tint_common_fuzzer.cc
+++ b/src/tint/fuzzers/tint_common_fuzzer.cc
@@ -62,6 +62,10 @@
 #include "src/tint/lang/msl/writer/helpers/generate_bindings.h"
 #endif  // TINT_BUILD_MSL_WRITER
 
+#if TINT_BUILD_HLSL_WRITER
+#include "src/tint/lang/hlsl/writer/helpers/generate_bindings.h"
+#endif  // TINT_BUILD_MSL_WRITER
+
 namespace tint::fuzzers {
 
 namespace {
@@ -73,11 +77,11 @@
 #define FATAL_ERROR(diags, msg_string)                             \
     do {                                                           \
         std::string msg = msg_string;                              \
-        auto printer = tint::diag::Printer::create(stderr, true);  \
+        auto printer = tint::diag::Printer::Create(stderr, true);  \
         if (!msg.empty()) {                                        \
-            printer->write(msg + "\n", {diag::Color::kRed, true}); \
+            printer->Write(msg + "\n", {diag::Color::kRed, true}); \
         }                                                          \
-        tint::diag::Formatter().format(diags, printer.get());      \
+        tint::diag::Formatter().Format(diags, printer.get());      \
         __builtin_trap();                                          \
     } while (false)
 
@@ -117,9 +121,9 @@
             out << "Unexpected spirv-val error:\n"
                 << (pos.line + 1) << ":" << (pos.column + 1) << ": " << msg << std::endl;
 
-            auto printer = tint::diag::Printer::create(stderr, true);
-            printer->write(out.str(), {diag::Color::kYellow, false});
-            tint::diag::Formatter().format(diags, printer.get());
+            auto printer = tint::diag::Printer::Create(stderr, true);
+            printer->Write(out.str(), {diag::Color::kYellow, false});
+            tint::diag::Formatter().Format(diags, printer.get());
         });
 
     return tools.Validate(spirv.data(), spirv.size(), spvtools::ValidatorOptions());
@@ -272,6 +276,9 @@
 #endif  // TINT_BUILD_MSL_WRITER
             break;
         case OutputFormat::kHLSL:
+#if TINT_BUILD_HLSL_WRITER
+            options_hlsl_.bindings = tint::hlsl::writer::GenerateBindings(program);
+#endif  // TINT_BUILD_HLSL_WRITER
             break;
         case OutputFormat::kSpv:
 #if TINT_BUILD_SPV_WRITER
@@ -282,51 +289,6 @@
             break;
     }
 
-    // For the generates which use MultiPlanar, make sure the configuration options are provided so
-    // that the transformer will execute.
-    if (output_ == OutputFormat::kHLSL) {
-        // Gather external texture binding information
-        // Collect next valid binding number per group
-        std::unordered_map<uint32_t, uint32_t> group_to_next_binding_number;
-        std::vector<BindingPoint> ext_tex_bps;
-        for (auto* var : program.AST().GlobalVariables()) {
-            if (auto* sem_var = program.Sem().Get(var)->As<sem::GlobalVariable>()) {
-                if (auto bp = sem_var->Attributes().binding_point) {
-                    auto& n = group_to_next_binding_number[bp->group];
-                    n = std::max(n, bp->binding + 1);
-
-                    if (sem_var->Type()->UnwrapRef()->Is<core::type::ExternalTexture>()) {
-                        ext_tex_bps.emplace_back(*bp);
-                    }
-                }
-            }
-        }
-
-        ExternalTextureOptions::BindingsMap new_bindings_map;
-        for (auto bp : ext_tex_bps) {
-            uint32_t g = bp.group;
-            uint32_t& next_num = group_to_next_binding_number[g];
-            auto new_bps = ExternalTextureOptions::BindingPoints{{g, next_num++}, {g, next_num++}};
-
-            new_bindings_map[bp] = new_bps;
-        }
-
-        switch (output_) {
-            case OutputFormat::kMSL: {
-                break;
-            }
-            case OutputFormat::kHLSL: {
-                options_hlsl_.external_texture_options.bindings_map = new_bindings_map;
-                break;
-            }
-            case OutputFormat::kSpv: {
-                break;
-            }
-            default:
-                break;
-        }
-    }
-
     switch (output_) {
         case OutputFormat::kWGSL: {
 #if TINT_BUILD_WGSL_WRITER
diff --git a/src/tint/fuzzers/tint_common_fuzzer.h b/src/tint/fuzzers/tint_common_fuzzer.h
index cad2527..9593fea 100644
--- a/src/tint/fuzzers/tint_common_fuzzer.h
+++ b/src/tint/fuzzers/tint_common_fuzzer.h
@@ -104,7 +104,7 @@
     const tint::diag::List& Diagnostics() const { return diagnostics_; }
 
     /// @returns if there are any errors in the diagnostic messages
-    bool HasErrors() const { return diagnostics_.contains_errors(); }
+    bool HasErrors() const { return diagnostics_.ContainsErrors(); }
 
     /// @returns generated SPIR-V binary, if SPIR-V was emitted.
     const std::vector<uint32_t>& GetGeneratedSpirv() const { return generated_spirv_; }
diff --git a/src/tint/fuzzers/tint_regex_fuzzer/CMakeLists.txt b/src/tint/fuzzers/tint_regex_fuzzer/CMakeLists.txt
index b6f0043..337acdd 100644
--- a/src/tint/fuzzers/tint_regex_fuzzer/CMakeLists.txt
+++ b/src/tint/fuzzers/tint_regex_fuzzer/CMakeLists.txt
@@ -27,8 +27,9 @@
 
 function(add_tint_regex_fuzzer NAME)
   add_executable(${NAME} ${NAME}.cc ${REGEX_FUZZER_SOURCES})
-  target_link_libraries(${NAME} PRIVATE libtint_regex_fuzzer tint_lang_spirv_writer_helpers)
+  target_link_libraries(${NAME} PRIVATE libtint_regex_fuzzer tint_lang_hlsl_writer_helpers)
   target_link_libraries(${NAME} PRIVATE libtint_regex_fuzzer tint_lang_msl_writer_helpers)
+  target_link_libraries(${NAME} PRIVATE libtint_regex_fuzzer tint_lang_spirv_writer_helpers)
   tint_fuzzer_compile_options(${NAME})
   tint_spvtools_compile_options(${NAME})
   target_compile_definitions(${NAME} PRIVATE CUSTOM_MUTATOR)
diff --git a/src/tint/lang/core/BUILD.bazel b/src/tint/lang/core/BUILD.bazel
index ade8daa..6515589 100644
--- a/src/tint/lang/core/BUILD.bazel
+++ b/src/tint/lang/core/BUILD.bazel
@@ -145,6 +145,7 @@
   deps = [
     "//src/tint/lang/core",
     "//src/tint/utils/macros",
+    "//src/tint/utils/math",
     "//src/tint/utils/reflection",
     "//src/tint/utils/traits",
     "@benchmark",
diff --git a/src/tint/lang/core/BUILD.cmake b/src/tint/lang/core/BUILD.cmake
index ea40bb5..d9786fe 100644
--- a/src/tint/lang/core/BUILD.cmake
+++ b/src/tint/lang/core/BUILD.cmake
@@ -152,6 +152,7 @@
 tint_target_add_dependencies(tint_lang_core_bench bench
   tint_lang_core
   tint_utils_macros
+  tint_utils_math
   tint_utils_reflection
   tint_utils_traits
 )
diff --git a/src/tint/lang/core/BUILD.gn b/src/tint/lang/core/BUILD.gn
index b1186f8..cd834ac 100644
--- a/src/tint/lang/core/BUILD.gn
+++ b/src/tint/lang/core/BUILD.gn
@@ -144,6 +144,7 @@
       "${tint_src_dir}:google_benchmark",
       "${tint_src_dir}/lang/core",
       "${tint_src_dir}/utils/macros",
+      "${tint_src_dir}/utils/math",
       "${tint_src_dir}/utils/reflection",
       "${tint_src_dir}/utils/traits",
     ]
diff --git a/src/tint/lang/core/constant/composite.h b/src/tint/lang/core/constant/composite.h
index 5844d96..1b359fe 100644
--- a/src/tint/lang/core/constant/composite.h
+++ b/src/tint/lang/core/constant/composite.h
@@ -69,7 +69,7 @@
     bool AnyZero() const override { return any_zero; }
 
     /// @copydoc Value::Hash()
-    size_t Hash() const override { return hash; }
+    HashCode Hash() const override { return hash; }
 
     /// Clones the constant into the provided context
     /// @param ctx the clone context
@@ -85,14 +85,14 @@
     /// True if any element is zero
     const bool any_zero;
     /// The hash of the composite
-    const size_t hash;
+    const HashCode hash;
 
   protected:
     /// @copydoc Value::InternalValue()
     std::variant<std::monostate, AInt, AFloat> InternalValue() const override { return {}; }
 
   private:
-    size_t CalcHash() {
+    HashCode CalcHash() {
         auto h = tint::Hash(type, all_zero, any_zero);
         for (auto* el : elements) {
             h = HashCombine(h, el->Hash());
diff --git a/src/tint/lang/core/constant/eval.cc b/src/tint/lang/core/constant/eval.cc
index 91fd4f0..7f090cd 100644
--- a/src/tint/lang/core/constant/eval.cc
+++ b/src/tint/lang/core/constant/eval.cc
@@ -281,7 +281,7 @@
             // [abstract-numeric -> x] - materialization failure
             auto msg = OverflowErrorMessage(scalar->value, target_ty->FriendlyName());
             if (ctx.use_runtime_semantics) {
-                ctx.diags.add_warning(tint::diag::System::Resolver, msg, ctx.source);
+                ctx.diags.AddWarning(tint::diag::System::Resolver, msg, ctx.source);
                 switch (conv.Failure()) {
                     case ConversionFailure::kExceedsNegativeLimit:
                         return ctx.mgr.Get<Scalar<TO>>(target_ty, TO::Lowest());
@@ -289,7 +289,7 @@
                         return ctx.mgr.Get<Scalar<TO>>(target_ty, TO::Highest());
                 }
             } else {
-                ctx.diags.add_error(tint::diag::System::Resolver, msg, ctx.source);
+                ctx.diags.AddError(tint::diag::System::Resolver, msg, ctx.source);
                 return nullptr;
             }
         } else if constexpr (IsFloatingPoint<TO>) {
@@ -297,7 +297,7 @@
             // https://www.w3.org/TR/WGSL/#floating-point-conversion
             auto msg = OverflowErrorMessage(scalar->value, target_ty->FriendlyName());
             if (ctx.use_runtime_semantics) {
-                ctx.diags.add_warning(tint::diag::System::Resolver, msg, ctx.source);
+                ctx.diags.AddWarning(tint::diag::System::Resolver, msg, ctx.source);
                 switch (conv.Failure()) {
                     case ConversionFailure::kExceedsNegativeLimit:
                         return ctx.mgr.Get<Scalar<TO>>(target_ty, TO::Lowest());
@@ -305,7 +305,7 @@
                         return ctx.mgr.Get<Scalar<TO>>(target_ty, TO::Highest());
                 }
             } else {
-                ctx.diags.add_error(tint::diag::System::Resolver, msg, ctx.source);
+                ctx.diags.AddError(tint::diag::System::Resolver, msg, ctx.source);
                 return nullptr;
             }
         } else if constexpr (IsFloatingPoint<FROM>) {
@@ -3990,18 +3990,18 @@
 
 void Eval::AddError(const std::string& msg, const Source& source) const {
     if (use_runtime_semantics_) {
-        diags.add_warning(diag::System::Constant, msg, source);
+        diags.AddWarning(diag::System::Constant, msg, source);
     } else {
-        diags.add_error(diag::System::Constant, msg, source);
+        diags.AddError(diag::System::Constant, msg, source);
     }
 }
 
 void Eval::AddWarning(const std::string& msg, const Source& source) const {
-    diags.add_warning(diag::System::Constant, msg, source);
+    diags.AddWarning(diag::System::Constant, msg, source);
 }
 
 void Eval::AddNote(const std::string& msg, const Source& source) const {
-    diags.add_note(diag::System::Constant, msg, source);
+    diags.AddNote(diag::System::Constant, msg, source);
 }
 
 }  // namespace tint::core::constant
diff --git a/src/tint/lang/core/constant/eval_binary_op_test.cc b/src/tint/lang/core/constant/eval_binary_op_test.cc
index 36ea805..f846ee1 100644
--- a/src/tint/lang/core/constant/eval_binary_op_test.cc
+++ b/src/tint/lang/core/constant/eval_binary_op_test.cc
@@ -2215,7 +2215,7 @@
     auto program = wgsl::reader::Parse(file.get());
     EXPECT_FALSE(program.IsValid());
 
-    auto error = program.Diagnostics().str();
+    auto error = program.Diagnostics().Str();
     EXPECT_EQ(error, R"(test:3:31 error: value cannot be represented as 'i32'
 const result = (one == 0) && (1111111111111111111111111111111i == 0);
                               ^
@@ -2234,7 +2234,7 @@
     auto program = wgsl::reader::Parse(file.get());
     EXPECT_FALSE(program.IsValid());
 
-    auto error = program.Diagnostics().str();
+    auto error = program.Diagnostics().Str();
     EXPECT_EQ(error, R"(test:3:31 error: value cannot be represented as 'i32'
 const result = (one == 1) || (1111111111111111111111111111111i == 0);
                               ^
@@ -2442,7 +2442,7 @@
     auto program = wgsl::reader::Parse(file.get());
 
     if (should_pass) {
-        auto error = program.Diagnostics().str();
+        auto error = program.Diagnostics().Str();
 
         EXPECT_TRUE(program.IsValid()) << error;
     } else {
diff --git a/src/tint/lang/core/constant/eval_runtime_semantics_test.cc b/src/tint/lang/core/constant/eval_runtime_semantics_test.cc
index d48c8c9..1aec87e 100644
--- a/src/tint/lang/core/constant/eval_runtime_semantics_test.cc
+++ b/src/tint/lang/core/constant/eval_runtime_semantics_test.cc
@@ -44,7 +44,7 @@
     Eval eval;
 
     /// @returns the contents of the diagnostics list as a string
-    std::string error() { return Diagnostics().str(); }
+    std::string error() { return Diagnostics().Str(); }
 };
 
 TEST_F(ConstEvalRuntimeSemanticsTest, Add_AInt_Overflow) {
diff --git a/src/tint/lang/core/constant/manager.h b/src/tint/lang/core/constant/manager.h
index 9fdfac8..993a388 100644
--- a/src/tint/lang/core/constant/manager.h
+++ b/src/tint/lang/core/constant/manager.h
@@ -155,7 +155,7 @@
     struct Hasher {
         /// @param value the value to hash
         /// @returns a hash of the value
-        size_t operator()(const constant::Value& value) const { return value.Hash(); }
+        HashCode operator()(const constant::Value& value) const { return value.Hash(); }
     };
 
     /// An equality helper for constant::Value
diff --git a/src/tint/lang/core/constant/scalar.h b/src/tint/lang/core/constant/scalar.h
index bd9724e..29a3c69 100644
--- a/src/tint/lang/core/constant/scalar.h
+++ b/src/tint/lang/core/constant/scalar.h
@@ -77,7 +77,7 @@
     bool AnyZero() const override { return IsZero(); }
 
     /// @copydoc Value::Hash()
-    size_t Hash() const override { return tint::Hash(type, ValueOf()); }
+    HashCode Hash() const override { return tint::Hash(type, ValueOf()); }
 
     /// Clones the constant into the provided context
     /// @param ctx the clone context
diff --git a/src/tint/lang/core/constant/splat.h b/src/tint/lang/core/constant/splat.h
index a65ea83..bf7a0c4 100644
--- a/src/tint/lang/core/constant/splat.h
+++ b/src/tint/lang/core/constant/splat.h
@@ -65,7 +65,7 @@
     bool AnyZero() const override { return el->AnyZero(); }
 
     /// @returns the hash for the splat
-    size_t Hash() const override { return tint::Hash(type, el->Hash(), count); }
+    HashCode Hash() const override { return tint::Hash(type, el->Hash(), count); }
 
     /// Clones the constant into the provided context
     /// @param ctx the clone context
diff --git a/src/tint/lang/core/constant/value.h b/src/tint/lang/core/constant/value.h
index 98c7bcb..c0ce056 100644
--- a/src/tint/lang/core/constant/value.h
+++ b/src/tint/lang/core/constant/value.h
@@ -70,7 +70,7 @@
     virtual bool AnyZero() const = 0;
 
     /// @returns a hash of the value.
-    virtual size_t Hash() const = 0;
+    virtual HashCode Hash() const = 0;
 
     /// @returns the value as the given scalar or abstract value.
     template <typename T>
diff --git a/src/tint/lang/core/core.def b/src/tint/lang/core/core.def
index 1e57b92..f54c573 100644
--- a/src/tint/lang/core/core.def
+++ b/src/tint/lang/core/core.def
@@ -852,6 +852,7 @@
 
 @must_use @stage("compute") fn subgroupBallot() -> vec4<u32>
 @must_use @stage("compute") fn subgroupBroadcast<T: fiu32_f16>(value: T, @const sourceLaneIndex: u32) -> T
+@must_use @stage("compute") fn subgroupBroadcast<N: num, T: fiu32_f16>(value: vec<N, T>, @const sourceLaneIndex: u32) -> vec<N, T>
 
 ////////////////////////////////////////////////////////////////////////////////
 // Value constructors                                                         //
diff --git a/src/tint/lang/core/intrinsic/data.cc b/src/tint/lang/core/intrinsic/data.cc
index a127690..4d863cf 100644
--- a/src/tint/lang/core/intrinsic/data.cc
+++ b/src/tint/lang/core/intrinsic/data.cc
@@ -4162,39 +4162,39 @@
   },
   {
     /* [350] */
+    /* usage */ core::ParameterUsage::kValue,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [351] */
+    /* usage */ core::ParameterUsage::kSourceLaneIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [352] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [351] */
+    /* [353] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
   },
   {
-    /* [352] */
+    /* [354] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(80),
     /* 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 */),
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
   },
   {
     /* [356] */
@@ -4205,329 +4205,341 @@
   {
     /* [357] */
     /* usage */ core::ParameterUsage::kNone,
-    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
-    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
     /* [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),
   },
   {
+    /* [359] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
     /* [360] */
     /* usage */ core::ParameterUsage::kNone,
-    /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
-    /* number_matcher_indices */ NumberMatcherIndicesIndex(20),
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(3),
   },
   {
     /* [361] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
-    /* number_matcher_indices */ NumberMatcherIndicesIndex(3),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
   },
   {
     /* [362] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(20),
+  },
+  {
+    /* [363] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(3),
+  },
+  {
+    /* [364] */
     /* usage */ core::ParameterUsage::kXy,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(72),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [363] */
+    /* [365] */
     /* usage */ core::ParameterUsage::kZw,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(72),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [364] */
+    /* [366] */
     /* usage */ core::ParameterUsage::kXyz,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [365] */
+    /* [367] */
     /* usage */ core::ParameterUsage::kW,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [366] */
+    /* [368] */
     /* usage */ core::ParameterUsage::kX,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [367] */
+    /* [369] */
     /* usage */ core::ParameterUsage::kZyw,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [368] */
+    /* [370] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(0),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(0),
   },
   {
-    /* [369] */
+    /* [371] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
   },
   {
-    /* [370] */
+    /* [372] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [371] */
+    /* [373] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(14),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
   },
   {
-    /* [372] */
+    /* [374] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [373] */
+    /* [375] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(28),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [374] */
+    /* [376] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(30),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [375] */
+    /* [377] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(32),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [376] */
+    /* [378] */
     /* usage */ core::ParameterUsage::kTexture,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(163),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
   },
   {
-    /* [377] */
+    /* [379] */
     /* usage */ core::ParameterUsage::kTexture,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(164),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
   },
   {
-    /* [378] */
+    /* [380] */
     /* usage */ core::ParameterUsage::kTexture,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(165),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
   },
   {
-    /* [379] */
+    /* [381] */
     /* usage */ core::ParameterUsage::kTexture,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(166),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
   },
   {
-    /* [380] */
+    /* [382] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(31),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [381] */
+    /* [383] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(85),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [382] */
+    /* [384] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(74),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [383] */
+    /* [385] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(76),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [384] */
+    /* [386] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(96),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [385] */
+    /* [387] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(102),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [386] */
+    /* [388] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(106),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [387] */
+    /* [389] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(104),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [388] */
+    /* [390] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(108),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [389] */
+    /* [391] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(112),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [390] */
+    /* [392] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(110),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [391] */
+    /* [393] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(114),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [392] */
+    /* [394] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(118),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [393] */
+    /* [395] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(116),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [394] */
+    /* [396] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(120),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [395] */
+    /* [397] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(124),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [396] */
+    /* [398] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(122),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [397] */
+    /* [399] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(126),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [398] */
+    /* [400] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(130),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [399] */
+    /* [401] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(128),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [400] */
+    /* [402] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(132),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [401] */
+    /* [403] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(136),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [402] */
+    /* [404] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(134),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [403] */
+    /* [405] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(138),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [404] */
+    /* [406] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(142),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [405] */
+    /* [407] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(140),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [406] */
+    /* [408] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(144),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [407] */
+    /* [409] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(148),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [408] */
+    /* [410] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(146),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [409] */
+    /* [411] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(150),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [410] */
+    /* [412] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(154),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [411] */
+    /* [413] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(152),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
@@ -5196,7 +5208,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(6),
-    /* parameters */ ParameterIndex(376),
+    /* parameters */ ParameterIndex(378),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -5209,7 +5221,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(6),
-    /* parameters */ ParameterIndex(377),
+    /* parameters */ ParameterIndex(379),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(36),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -5222,7 +5234,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(6),
-    /* parameters */ ParameterIndex(378),
+    /* parameters */ ParameterIndex(380),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(36),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -5235,7 +5247,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(6),
-    /* parameters */ ParameterIndex(379),
+    /* parameters */ ParameterIndex(381),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(42),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -5638,7 +5650,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(27),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(362),
+    /* parameters */ ParameterIndex(364),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(52),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(108),
@@ -5651,7 +5663,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(27),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(364),
+    /* parameters */ ParameterIndex(366),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(52),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(108),
@@ -5664,7 +5676,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(27),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(366),
+    /* parameters */ ParameterIndex(368),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(52),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(108),
@@ -5677,7 +5689,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(384),
+    /* parameters */ ParameterIndex(386),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -5690,7 +5702,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(384),
+    /* parameters */ ParameterIndex(386),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(98),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -5703,7 +5715,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(18),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(384),
+    /* parameters */ ParameterIndex(386),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(30),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -5716,7 +5728,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(20),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(384),
+    /* parameters */ ParameterIndex(386),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(32),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -5729,7 +5741,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(22),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(384),
+    /* parameters */ ParameterIndex(386),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(100),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -6522,7 +6534,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(383),
+    /* parameters */ ParameterIndex(385),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(56),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -6535,7 +6547,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(383),
+    /* parameters */ ParameterIndex(385),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(90),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -6548,7 +6560,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(18),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(383),
+    /* parameters */ ParameterIndex(385),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(66),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -6561,7 +6573,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(20),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(383),
+    /* parameters */ ParameterIndex(385),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(42),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -6574,7 +6586,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(22),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(383),
+    /* parameters */ ParameterIndex(385),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(92),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -6782,7 +6794,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(382),
+    /* parameters */ ParameterIndex(384),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(26),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -6795,7 +6807,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(382),
+    /* parameters */ ParameterIndex(384),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(84),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -6808,7 +6820,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(18),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(382),
+    /* parameters */ ParameterIndex(384),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(54),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -6821,7 +6833,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(20),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(382),
+    /* parameters */ ParameterIndex(384),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(36),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -6834,7 +6846,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(22),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(382),
+    /* parameters */ ParameterIndex(384),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(86),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -6886,7 +6898,7 @@
     /* num_template_numbers */ 1,
     /* template_types */ TemplateTypeIndex(24),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(350),
+    /* parameters */ ParameterIndex(352),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(84),
@@ -6899,7 +6911,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(10),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(355),
+    /* parameters */ ParameterIndex(357),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(2),
     /* const_eval_fn */ ConstEvalFunctionIndex(84),
@@ -6912,7 +6924,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(10),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(354),
+    /* parameters */ ParameterIndex(356),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(2),
     /* const_eval_fn */ ConstEvalFunctionIndex(84),
@@ -6925,7 +6937,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(10),
     /* template_numbers */ TemplateNumberIndex(1),
-    /* parameters */ ParameterIndex(356),
+    /* parameters */ ParameterIndex(358),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(3),
     /* const_eval_fn */ ConstEvalFunctionIndex(85),
@@ -6938,7 +6950,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(10),
     /* template_numbers */ TemplateNumberIndex(1),
-    /* parameters */ ParameterIndex(358),
+    /* parameters */ ParameterIndex(360),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(86),
@@ -6951,7 +6963,7 @@
     /* num_template_numbers */ 3,
     /* template_types */ TemplateTypeIndex(10),
     /* template_numbers */ TemplateNumberIndex(0),
-    /* parameters */ ParameterIndex(360),
+    /* parameters */ ParameterIndex(362),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(18),
     /* const_eval_fn */ ConstEvalFunctionIndex(87),
@@ -7419,7 +7431,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(385),
+    /* parameters */ ParameterIndex(387),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(102),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(104),
@@ -7458,7 +7470,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(386),
+    /* parameters */ ParameterIndex(388),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(104),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -7471,7 +7483,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(387),
+    /* parameters */ ParameterIndex(389),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(106),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -7497,7 +7509,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(388),
+    /* parameters */ ParameterIndex(390),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(108),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(104),
@@ -7536,7 +7548,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(389),
+    /* parameters */ ParameterIndex(391),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(110),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -7549,7 +7561,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(390),
+    /* parameters */ ParameterIndex(392),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(112),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -7575,7 +7587,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(391),
+    /* parameters */ ParameterIndex(393),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(114),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(104),
@@ -7614,7 +7626,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(392),
+    /* parameters */ ParameterIndex(394),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(116),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -7627,7 +7639,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(393),
+    /* parameters */ ParameterIndex(395),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(118),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -7653,7 +7665,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(394),
+    /* parameters */ ParameterIndex(396),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(120),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(104),
@@ -7692,7 +7704,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(395),
+    /* parameters */ ParameterIndex(397),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(122),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -7705,7 +7717,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(396),
+    /* parameters */ ParameterIndex(398),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(124),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -7731,7 +7743,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(397),
+    /* parameters */ ParameterIndex(399),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(126),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(104),
@@ -7770,7 +7782,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(398),
+    /* parameters */ ParameterIndex(400),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(128),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -7783,7 +7795,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(399),
+    /* parameters */ ParameterIndex(401),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(130),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -7809,7 +7821,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(400),
+    /* parameters */ ParameterIndex(402),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(132),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(104),
@@ -7848,7 +7860,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(401),
+    /* parameters */ ParameterIndex(403),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(134),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -7861,7 +7873,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(402),
+    /* parameters */ ParameterIndex(404),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(136),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -7887,7 +7899,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(403),
+    /* parameters */ ParameterIndex(405),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(138),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(104),
@@ -7926,7 +7938,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(404),
+    /* parameters */ ParameterIndex(406),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(140),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -7939,7 +7951,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(405),
+    /* parameters */ ParameterIndex(407),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(142),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -7965,7 +7977,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(406),
+    /* parameters */ ParameterIndex(408),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(144),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(104),
@@ -8004,7 +8016,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(407),
+    /* parameters */ ParameterIndex(409),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(146),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -8017,7 +8029,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(408),
+    /* parameters */ ParameterIndex(410),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(148),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -8043,7 +8055,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(409),
+    /* parameters */ ParameterIndex(411),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(150),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(104),
@@ -8082,7 +8094,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(410),
+    /* parameters */ ParameterIndex(412),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(152),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -8095,7 +8107,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(411),
+    /* parameters */ ParameterIndex(413),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(154),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(105),
@@ -8160,7 +8172,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(6),
-    /* parameters */ ParameterIndex(378),
+    /* parameters */ ParameterIndex(380),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -8212,7 +8224,7 @@
     /* num_template_numbers */ 1,
     /* template_types */ TemplateTypeIndex(24),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(350),
+    /* parameters */ ParameterIndex(352),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(82),
@@ -8225,7 +8237,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(10),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(353),
+    /* parameters */ ParameterIndex(355),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(2),
     /* const_eval_fn */ ConstEvalFunctionIndex(82),
@@ -8277,7 +8289,7 @@
     /* num_template_numbers */ 1,
     /* template_types */ TemplateTypeIndex(24),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(350),
+    /* parameters */ ParameterIndex(352),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(83),
@@ -8290,7 +8302,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(10),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(353),
+    /* parameters */ ParameterIndex(355),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(2),
     /* const_eval_fn */ ConstEvalFunctionIndex(83),
@@ -8342,7 +8354,7 @@
     /* num_template_numbers */ 1,
     /* template_types */ TemplateTypeIndex(24),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(350),
+    /* parameters */ ParameterIndex(352),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(88),
@@ -8394,7 +8406,7 @@
     /* num_template_numbers */ 1,
     /* template_types */ TemplateTypeIndex(24),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(350),
+    /* parameters */ ParameterIndex(352),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(89),
@@ -8602,7 +8614,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(380),
+    /* parameters */ ParameterIndex(382),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(31),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(104),
@@ -8680,7 +8692,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(370),
+    /* parameters */ ParameterIndex(372),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(104),
@@ -8719,7 +8731,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(381),
+    /* parameters */ ParameterIndex(383),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(85),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(104),
@@ -9278,7 +9290,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(370),
+    /* parameters */ ParameterIndex(372),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -9291,7 +9303,7 @@
     /* num_template_numbers */ 1,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(371),
+    /* parameters */ ParameterIndex(373),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(14),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -9798,7 +9810,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(370),
+    /* parameters */ ParameterIndex(372),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(53),
@@ -9811,7 +9823,7 @@
     /* num_template_numbers */ 1,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(371),
+    /* parameters */ ParameterIndex(373),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(14),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(53),
@@ -10208,747 +10220,6 @@
   },
   {
     /* [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(79),
-  },
-  {
-    /* [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(79),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(1),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(80),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(149),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
-    /* const_eval_fn */ ConstEvalFunctionIndex(80),
-  },
-  {
-    /* [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(81),
-  },
-  {
-    /* [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(81),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(1),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(90),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(149),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
-    /* const_eval_fn */ ConstEvalFunctionIndex(90),
-  },
-  {
-    /* [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(95),
-  },
-  {
-    /* [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(95),
-  },
-  {
-    /* [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(96),
-  },
-  {
-    /* [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(96),
-  },
-  {
-    /* [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(97),
-  },
-  {
-    /* [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(97),
-  },
-  {
-    /* [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(98),
-  },
-  {
-    /* [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(98),
-  },
-  {
-    /* [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(99),
-  },
-  {
-    /* [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(99),
-  },
-  {
-    /* [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(100),
-  },
-  {
-    /* [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(100),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(16),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(101),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(351),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
-    /* const_eval_fn */ ConstEvalFunctionIndex(101),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(16),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(102),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(351),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
-    /* const_eval_fn */ ConstEvalFunctionIndex(102),
-  },
-  {
-    /* [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(33),
-    /* 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(31),
-    /* 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(33),
-    /* 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(33),
-    /* 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(33),
-    /* 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(33),
-    /* 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(33),
-    /* 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(33),
-    /* 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 */ 1,
-    /* num_template_types */ 0,
-    /* num_template_numbers */ 0,
-    /* template_types */ TemplateTypeIndex(/* invalid */),
-    /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(374),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(48),
-  },
-  {
-    /* [446] */
-    /* 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(375),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(49),
-  },
-  {
-    /* [447] */
-    /* 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(374),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(50),
-  },
-  {
-    /* [448] */
-    /* 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(375),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(51),
-  },
-  {
-    /* [449] */
-    /* 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(55),
-  },
-  {
-    /* [450] */
-    /* 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(56),
-  },
-  {
-    /* [451] */
-    /* 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 */),
-  },
-  {
-    /* [452] */
-    /* 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(70),
-  },
-  {
-    /* [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(26),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(72),
-  },
-  {
-    /* [454] */
-    /* 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(73),
-  },
-  {
-    /* [455] */
-    /* 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(74),
-  },
-  {
-    /* [456] */
-    /* 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(75),
-  },
-  {
-    /* [457] */
-    /* 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(76),
-  },
-  {
-    /* [458] */
-    /* 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(30),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(77),
-  },
-  {
-    /* [459] */
-    /* 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(32),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(78),
-  },
-  {
-    /* [460] */
-    /* 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 */),
-  },
-  {
-    /* [461] */
-    /* 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 */),
-  },
-  {
-    /* [462] */
-    /* 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 */),
-  },
-  {
-    /* [463] */
-    /* 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(78),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
-  },
-  {
-    /* [464] */
-    /* 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(32),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
-  },
-  {
-    /* [465] */
     /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* num_parameters */ 2,
     /* num_template_types */ 1,
@@ -10961,9 +10232,22 @@
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
-    /* [466] */
-    /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
+    /* [409] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, 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(350),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [410] */
+    /* 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 */),
@@ -10971,7 +10255,735 @@
     /* parameters */ ParameterIndex(226),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(93),
+    /* const_eval_fn */ ConstEvalFunctionIndex(79),
+  },
+  {
+    /* [411] */
+    /* 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(79),
+  },
+  {
+    /* [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(30),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(80),
+  },
+  {
+    /* [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(30),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(80),
+  },
+  {
+    /* [414] */
+    /* 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(81),
+  },
+  {
+    /* [415] */
+    /* 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(81),
+  },
+  {
+    /* [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(30),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* 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(30),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* 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(95),
+  },
+  {
+    /* [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(95),
+  },
+  {
+    /* [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(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(96),
+  },
+  {
+    /* [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(27),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(8),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(96),
+  },
+  {
+    /* [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(97),
+  },
+  {
+    /* [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(97),
+  },
+  {
+    /* [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(98),
+  },
+  {
+    /* [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(98),
+  },
+  {
+    /* [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(99),
+  },
+  {
+    /* [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(99),
+  },
+  {
+    /* [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(24),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(100),
+  },
+  {
+    /* [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(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(8),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(100),
+  },
+  {
+    /* [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(30),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(16),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(101),
+  },
+  {
+    /* [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(30),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(353),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(101),
+  },
+  {
+    /* [432] */
+    /* 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(30),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(16),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(102),
+  },
+  {
+    /* [433] */
+    /* 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(30),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(353),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(102),
+  },
+  {
+    /* [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(25),
+    /* template_numbers */ TemplateNumberIndex(7),
+    /* parameters */ ParameterIndex(370),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [435] */
+    /* 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),
+  },
+  {
+    /* [436] */
+    /* 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(371),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(19),
+  },
+  {
+    /* [437] */
+    /* 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),
+  },
+  {
+    /* [438] */
+    /* 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(31),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [439] */
+    /* 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(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [440] */
+    /* 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),
+  },
+  {
+    /* [441] */
+    /* 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),
+  },
+  {
+    /* [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(374),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(43),
+  },
+  {
+    /* [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(374),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(44),
+  },
+  {
+    /* [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(374),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(45),
+  },
+  {
+    /* [445] */
+    /* 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(375),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(46),
+  },
+  {
+    /* [446] */
+    /* 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(375),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(47),
+  },
+  {
+    /* [447] */
+    /* 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(376),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(48),
+  },
+  {
+    /* [448] */
+    /* 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(377),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(49),
+  },
+  {
+    /* [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(376),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(50),
+  },
+  {
+    /* [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(377),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(51),
+  },
+  {
+    /* [451] */
+    /* 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(55),
+  },
+  {
+    /* [452] */
+    /* 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(56),
+  },
+  {
+    /* [453] */
+    /* 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 */),
+  },
+  {
+    /* [454] */
+    /* 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(355),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(3),
+    /* const_eval_fn */ ConstEvalFunctionIndex(70),
+  },
+  {
+    /* [455] */
+    /* 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(72),
+  },
+  {
+    /* [456] */
+    /* 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(73),
+  },
+  {
+    /* [457] */
+    /* 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(74),
+  },
+  {
+    /* [458] */
+    /* 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(75),
+  },
+  {
+    /* [459] */
+    /* 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(76),
+  },
+  {
+    /* [460] */
+    /* 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(30),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(77),
+  },
+  {
+    /* [461] */
+    /* 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(32),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(78),
+  },
+  {
+    /* [462] */
+    /* 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 */),
+  },
+  {
+    /* [463] */
+    /* 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 */),
+  },
+  {
+    /* [464] */
+    /* 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 */),
+  },
+  {
+    /* [465] */
+    /* 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(78),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [466] */
+    /* 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(32),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
     /* [467] */
@@ -10984,10 +10996,23 @@
     /* parameters */ ParameterIndex(226),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(94),
+    /* const_eval_fn */ ConstEvalFunctionIndex(93),
   },
   {
     /* [468] */
+    /* 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(94),
+  },
+  {
+    /* [469] */
     /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* num_parameters */ 1,
     /* num_template_types */ 1,
@@ -11044,7 +11069,7 @@
     /* [5] */
     /* fn arrayLength<T, A : access>(ptr<storage, array<T>, A>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(432),
+    /* overloads */ OverloadIndex(434),
   },
   {
     /* [6] */
@@ -11134,7 +11159,7 @@
     /* [18] */
     /* fn cross<T : fa_f32_f16>(vec3<T>, vec3<T>) -> vec3<T> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(433),
+    /* overloads */ OverloadIndex(435),
   },
   {
     /* [19] */
@@ -11147,7 +11172,7 @@
     /* [20] */
     /* fn determinant<N : num, T : fa_f32_f16>(mat<N, N, T>) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(434),
+    /* overloads */ OverloadIndex(436),
   },
   {
     /* [21] */
@@ -11160,19 +11185,19 @@
     /* [22] */
     /* fn dot<N : num, T : fia_fiu32_f16>(vec<N, T>, vec<N, T>) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(435),
+    /* overloads */ OverloadIndex(437),
   },
   {
     /* [23] */
     /* fn dot4I8Packed(u32, u32) -> i32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(436),
+    /* overloads */ OverloadIndex(438),
   },
   {
     /* [24] */
     /* fn dot4U8Packed(u32, u32) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(437),
+    /* overloads */ OverloadIndex(439),
   },
   {
     /* [25] */
@@ -11241,7 +11266,7 @@
     /* [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),
+    /* overloads */ OverloadIndex(440),
   },
   {
     /* [35] */
@@ -11381,61 +11406,61 @@
     /* [54] */
     /* fn normalize<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(439),
+    /* overloads */ OverloadIndex(441),
   },
   {
     /* [55] */
     /* fn pack2x16float(vec2<f32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(440),
+    /* overloads */ OverloadIndex(442),
   },
   {
     /* [56] */
     /* fn pack2x16snorm(vec2<f32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(441),
+    /* overloads */ OverloadIndex(443),
   },
   {
     /* [57] */
     /* fn pack2x16unorm(vec2<f32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(442),
+    /* overloads */ OverloadIndex(444),
   },
   {
     /* [58] */
     /* fn pack4x8snorm(vec4<f32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(443),
+    /* overloads */ OverloadIndex(445),
   },
   {
     /* [59] */
     /* fn pack4x8unorm(vec4<f32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(444),
+    /* overloads */ OverloadIndex(446),
   },
   {
     /* [60] */
     /* fn pack4xI8(vec4<i32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(445),
+    /* overloads */ OverloadIndex(447),
   },
   {
     /* [61] */
     /* fn pack4xU8(vec4<u32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(446),
+    /* overloads */ OverloadIndex(448),
   },
   {
     /* [62] */
     /* fn pack4xI8Clamp(vec4<i32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(447),
+    /* overloads */ OverloadIndex(449),
   },
   {
     /* [63] */
     /* fn pack4xU8Clamp(vec4<u32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(448),
+    /* overloads */ OverloadIndex(450),
   },
   {
     /* [64] */
@@ -11462,13 +11487,13 @@
     /* [67] */
     /* fn reflect<N : num, T : fa_f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(449),
+    /* overloads */ OverloadIndex(451),
   },
   {
     /* [68] */
     /* fn refract<N : num, T : fa_f32_f16>(vec<N, T>, vec<N, T>, T) -> vec<N, T> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(450),
+    /* overloads */ OverloadIndex(452),
   },
   {
     /* [69] */
@@ -11545,7 +11570,7 @@
     /* [79] */
     /* fn storageBarrier() */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(451),
+    /* overloads */ OverloadIndex(453),
   },
   {
     /* [80] */
@@ -11565,7 +11590,7 @@
     /* [82] */
     /* fn transpose<M : num, N : num, T : fa_f32_f16>(mat<M, N, T>) -> mat<N, M, T> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(452),
+    /* overloads */ OverloadIndex(454),
   },
   {
     /* [83] */
@@ -11578,55 +11603,55 @@
     /* [84] */
     /* fn unpack2x16float(u32) -> vec2<f32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(453),
+    /* overloads */ OverloadIndex(455),
   },
   {
     /* [85] */
     /* fn unpack2x16snorm(u32) -> vec2<f32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(454),
+    /* overloads */ OverloadIndex(456),
   },
   {
     /* [86] */
     /* fn unpack2x16unorm(u32) -> vec2<f32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(455),
+    /* overloads */ OverloadIndex(457),
   },
   {
     /* [87] */
     /* fn unpack4x8snorm(u32) -> vec4<f32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(456),
+    /* overloads */ OverloadIndex(458),
   },
   {
     /* [88] */
     /* fn unpack4x8unorm(u32) -> vec4<f32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(457),
+    /* overloads */ OverloadIndex(459),
   },
   {
     /* [89] */
     /* fn unpack4xI8(u32) -> vec4<i32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(458),
+    /* overloads */ OverloadIndex(460),
   },
   {
     /* [90] */
     /* fn unpack4xU8(u32) -> vec4<u32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(459),
+    /* overloads */ OverloadIndex(461),
   },
   {
     /* [91] */
     /* fn workgroupBarrier() */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(451),
+    /* overloads */ OverloadIndex(453),
   },
   {
     /* [92] */
     /* fn textureBarrier() */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(451),
+    /* overloads */ OverloadIndex(453),
   },
   {
     /* [93] */
@@ -11861,79 +11886,80 @@
     /* [108] */
     /* fn atomicLoad<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(460),
+    /* overloads */ OverloadIndex(462),
   },
   {
     /* [109] */
     /* fn atomicStore<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(461),
+    /* overloads */ OverloadIndex(463),
   },
   {
     /* [110] */
     /* fn atomicAdd<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(462),
+    /* overloads */ OverloadIndex(464),
   },
   {
     /* [111] */
     /* fn atomicSub<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(462),
+    /* overloads */ OverloadIndex(464),
   },
   {
     /* [112] */
     /* fn atomicMax<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(462),
+    /* overloads */ OverloadIndex(464),
   },
   {
     /* [113] */
     /* fn atomicMin<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(462),
+    /* overloads */ OverloadIndex(464),
   },
   {
     /* [114] */
     /* fn atomicAnd<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(462),
+    /* overloads */ OverloadIndex(464),
   },
   {
     /* [115] */
     /* fn atomicOr<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(462),
+    /* overloads */ OverloadIndex(464),
   },
   {
     /* [116] */
     /* fn atomicXor<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(462),
+    /* overloads */ OverloadIndex(464),
   },
   {
     /* [117] */
     /* fn atomicExchange<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(462),
+    /* overloads */ OverloadIndex(464),
   },
   {
     /* [118] */
     /* 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(463),
+    /* overloads */ OverloadIndex(465),
   },
   {
     /* [119] */
     /* fn subgroupBallot() -> vec4<u32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(464),
+    /* overloads */ OverloadIndex(466),
   },
   {
     /* [120] */
     /* fn subgroupBroadcast<T : fiu32_f16>(value: T, @const sourceLaneIndex: u32) -> T */
-    /* num overloads */ 1,
-    /* overloads */ OverloadIndex(465),
+    /* fn subgroupBroadcast<N : num, T : fiu32_f16>(value: vec<N, T>, @const sourceLaneIndex: u32) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(408),
   },
 };
 
@@ -11943,21 +11969,21 @@
     /* op !(bool) -> bool */
     /* op !<N : num>(vec<N, bool>) -> vec<N, bool> */
     /* num overloads */ 2,
-    /* overloads */ OverloadIndex(408),
+    /* overloads */ OverloadIndex(410),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(412),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(414),
   },
 };
 constexpr uint8_t kUnaryOperatorNot = 0;
@@ -12022,7 +12048,7 @@
     /* 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),
+    /* overloads */ OverloadIndex(416),
   },
   {
     /* [6] */
@@ -12046,69 +12072,69 @@
     /* [8] */
     /* op &&(bool, bool) -> bool */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(466),
+    /* overloads */ OverloadIndex(467),
   },
   {
     /* [9] */
     /* op ||(bool, bool) -> bool */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(467),
+    /* overloads */ OverloadIndex(468),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(418),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(420),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(422),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(424),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(426),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(428),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(430),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(432),
   },
 };
 constexpr uint8_t kBinaryOperatorPlus = 0;
@@ -12327,7 +12353,7 @@
     /* [17] */
     /* conv packedVec3<T : concrete_scalar>(vec3<T>) -> packedVec3<T> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(468),
+    /* overloads */ OverloadIndex(469),
   },
 };
 
diff --git a/src/tint/lang/core/intrinsic/table.h b/src/tint/lang/core/intrinsic/table.h
index 32f60fc..c1cbfcc 100644
--- a/src/tint/lang/core/intrinsic/table.h
+++ b/src/tint/lang/core/intrinsic/table.h
@@ -295,8 +295,8 @@
 struct Hasher<core::intrinsic::Overload> {
     /// @param i the core::intrinsic::Overload to create a hash for
     /// @return the hash value
-    inline std::size_t operator()(const core::intrinsic::Overload& i) const {
-        size_t hash = Hash(i.parameters.Length());
+    inline HashCode operator()(const core::intrinsic::Overload& i) const {
+        HashCode hash = Hash(i.parameters.Length());
         for (auto& p : i.parameters) {
             hash = HashCombine(hash, p.type, p.usage);
         }
diff --git a/src/tint/lang/core/ir/binary/roundtrip_test.cc b/src/tint/lang/core/ir/binary/roundtrip_test.cc
index 94e2f5b..19344f1 100644
--- a/src/tint/lang/core/ir/binary/roundtrip_test.cc
+++ b/src/tint/lang/core/ir/binary/roundtrip_test.cc
@@ -50,11 +50,11 @@
         auto pre = Disassemble(this->mod);
         auto encoded = Encode(this->mod);
         if (encoded != Success) {
-            return {pre, encoded.Failure().reason.str()};
+            return {pre, encoded.Failure().reason.Str()};
         }
         auto decoded = Decode(encoded->Slice());
         if (decoded != Success) {
-            return {pre, decoded.Failure().reason.str()};
+            return {pre, decoded.Failure().reason.Str()};
         }
         auto post = Disassemble(decoded.Get());
         return {pre, post};
diff --git a/src/tint/lang/core/ir/disassembler.h b/src/tint/lang/core/ir/disassembler.h
index c585fc4..d22b8a1 100644
--- a/src/tint/lang/core/ir/disassembler.h
+++ b/src/tint/lang/core/ir/disassembler.h
@@ -64,7 +64,7 @@
         size_t index = 0u;
 
         /// @returns the hash code of the IndexedValue
-        size_t HashCode() const { return Hash(instruction, index); }
+        tint::HashCode HashCode() const { return Hash(instruction, index); }
 
         /// An equality helper for IndexedValue.
         /// @param other the IndexedValue to compare against
diff --git a/src/tint/lang/core/ir/transform/direct_variable_access.cc b/src/tint/lang/core/ir/transform/direct_variable_access.cc
index 5297c81..ca89b39 100644
--- a/src/tint/lang/core/ir/transform/direct_variable_access.cc
+++ b/src/tint/lang/core/ir/transform/direct_variable_access.cc
@@ -53,7 +53,7 @@
     Var* var = nullptr;
 
     /// @return a hash value for this object
-    size_t HashCode() const { return Hash(var); }
+    tint::HashCode HashCode() const { return Hash(var); }
 
     /// Inequality operator
     bool operator!=(const RootModuleScopeVar& other) const { return var != other.var; }
@@ -66,7 +66,7 @@
     const type::Pointer* type = nullptr;
 
     /// @return a hash value for this object
-    size_t HashCode() const { return Hash(type); }
+    tint::HashCode HashCode() const { return Hash(type); }
 
     /// Inequality operator
     bool operator!=(const RootPtrParameter& other) const { return type != other.type; }
@@ -81,7 +81,7 @@
     const type::StructMember* member;
 
     /// @return a hash member for this object
-    size_t HashCode() const { return Hash(member); }
+    tint::HashCode HashCode() const { return Hash(member); }
 
     /// Inequality operator
     bool operator!=(const MemberAccess& other) const { return member != other.member; }
@@ -91,7 +91,7 @@
 /// The ordered list of indices is passed by parameter.
 struct IndexAccess {
     /// @return a hash value for this object
-    size_t HashCode() const { return 42; }
+    tint::HashCode HashCode() const { return 42; }
 
     /// Inequality operator
     bool operator!=(const IndexAccess&) const { return false; }
@@ -166,7 +166,7 @@
     }
 
     /// @return a hash value for this object
-    size_t HashCode() const { return Hash(root, ops); }
+    tint::HashCode HashCode() const { return Hash(root, ops); }
 
     /// Inequality operator
     bool operator!=(const AccessShape& other) const {
diff --git a/src/tint/lang/core/ir/transform/direct_variable_access_wgsl_test.cc b/src/tint/lang/core/ir/transform/direct_variable_access_wgsl_test.cc
index 77b799c..1270cf7 100644
--- a/src/tint/lang/core/ir/transform/direct_variable_access_wgsl_test.cc
+++ b/src/tint/lang/core/ir/transform/direct_variable_access_wgsl_test.cc
@@ -67,28 +67,28 @@
         Source::File file{"test", in};
         auto program_in = wgsl::reader::Parse(&file, parser_options);
         if (!program_in.IsValid()) {
-            return "wgsl::reader::Parse() failed: \n" + program_in.Diagnostics().str();
+            return "wgsl::reader::Parse() failed: \n" + program_in.Diagnostics().Str();
         }
 
         auto module = wgsl::reader::ProgramToIR(program_in);
         if (module != Success) {
-            return "ProgramToIR() failed:\n" + module.Failure().reason.str();
+            return "ProgramToIR() failed:\n" + module.Failure().reason.Str();
         }
 
         auto res = DirectVariableAccess(module.Get(), transform_options);
         if (res != Success) {
-            return "DirectVariableAccess failed:\n" + res.Failure().reason.str();
+            return "DirectVariableAccess failed:\n" + res.Failure().reason.Str();
         }
 
         auto pre_raise = ir::Disassemble(module.Get());
 
         if (auto raise = wgsl::writer::Raise(module.Get()); raise != Success) {
-            return "wgsl::writer::Raise failed:\n" + res.Failure().reason.str();
+            return "wgsl::writer::Raise failed:\n" + res.Failure().reason.Str();
         }
 
         auto program_out = wgsl::writer::IRToProgram(module.Get(), program_options);
         if (!program_out.IsValid()) {
-            return "wgsl::writer::IRToProgram() failed: \n" + program_out.Diagnostics().str() +
+            return "wgsl::writer::IRToProgram() failed: \n" + program_out.Diagnostics().Str() +
                    "\n\nIR (pre):\n" + pre_raise +                       //
                    "\n\nIR (post):\n" + ir::Disassemble(module.Get()) +  //
                    "\n\nAST:\n" + Program::printer(program_out);
@@ -96,7 +96,7 @@
 
         auto output = wgsl::writer::Generate(program_out, wgsl::writer::Options{});
         if (output != Success) {
-            return "wgsl::writer::IRToProgram() failed: \n" + output.Failure().reason.str() +
+            return "wgsl::writer::IRToProgram() failed: \n" + output.Failure().reason.Str() +
                    "\n\nIR:\n" + ir::Disassemble(module.Get());
         }
 
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index 65c952a..59e2fdd 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -324,7 +324,7 @@
         CheckFunction(func);
     }
 
-    if (!diagnostics_.contains_errors()) {
+    if (!diagnostics_.ContainsErrors()) {
         // Check for orphaned instructions.
         for (auto* inst : mod_.instructions.Objects()) {
             if (inst->Alive() && !visited_instructions_.Contains(inst)) {
@@ -333,10 +333,10 @@
         }
     }
 
-    if (diagnostics_.contains_errors()) {
+    if (diagnostics_.ContainsErrors()) {
         DisassembleIfNeeded();
-        diagnostics_.add_note(tint::diag::System::IR,
-                              "# Disassembly\n" + disassembly_file->content.data, {});
+        diagnostics_.AddNote(tint::diag::System::IR,
+                             "# Disassembly\n" + disassembly_file->content.data, {});
         return Failure{std::move(diagnostics_)};
     }
     return Success;
@@ -401,7 +401,7 @@
 }
 
 void Validator::AddError(std::string err, Source src) {
-    auto& diag = diagnostics_.add_error(tint::diag::System::IR, std::move(err), src);
+    auto& diag = diagnostics_.AddError(tint::diag::System::IR, std::move(err), src);
     if (src.range != Source::Range{{}}) {
         diag.source.file = disassembly_file.get();
         diag.owned_file = disassembly_file;
@@ -409,7 +409,7 @@
 }
 
 void Validator::AddNote(std::string note, Source src) {
-    auto& diag = diagnostics_.add_note(tint::diag::System::IR, std::move(note), src);
+    auto& diag = diagnostics_.AddNote(tint::diag::System::IR, std::move(note), src);
     if (src.range != Source::Range{{}}) {
         diag.source.file = disassembly_file.get();
         diag.owned_file = disassembly_file;
diff --git a/src/tint/lang/core/ir/validator_test.cc b/src/tint/lang/core/ir/validator_test.cc
index 0c2bef9..cd5faeb 100644
--- a/src/tint/lang/core/ir/validator_test.cc
+++ b/src/tint/lang/core/ir/validator_test.cc
@@ -59,7 +59,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:2:3 error: root block: invalid instruction: tint::core::ir::Loop
   loop [b: %b2] {  # loop_1
   ^^^^^^^^^^^^^
@@ -90,7 +90,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    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
                                      ^^^
@@ -131,7 +131,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    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 {
@@ -160,7 +160,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:3:20 error: call: call target is not part of the module
     %2:void = call %g
                    ^^
@@ -191,7 +191,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:3:20 error: call: call target must not have a pipeline stage
     %2:void = call %g
                    ^^
@@ -228,7 +228,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:8:20 error: call: function has 2 parameters, but call provides 1 arguments
     %5:void = call %g, 42i
                    ^^
@@ -265,7 +265,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:8:20 error: call: function has 2 parameters, but call provides 3 arguments
     %5:void = call %g, 1i, 2i, 3i
                    ^^
@@ -302,7 +302,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:8:28 error: call: function parameter 1 is of type i32, but argument is of type f32
     %6:void = call %g, 1i, 2.0f, 3i
                            ^^^^
@@ -331,7 +331,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:2:3 error: block: does not end in a terminator instruction
   %b1 = block {
   ^^^^^^^^^^^
@@ -358,7 +358,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    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
                                         ^^^
@@ -398,7 +398,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:3:25 error: access: constant index must be positive, got -1
     %3:f32 = access %2, -1i
                         ^^^
@@ -429,7 +429,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    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
                             ^^
@@ -465,7 +465,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.str(),
+        res.Failure().reason.Str(),
         R"(:3:55 error: access: index out of bounds for type ptr<private, array<f32, 2>, read_write>
     %3:ptr<private, f32, read_write> = access %2, 1u, 3u
                                                       ^^
@@ -500,7 +500,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
                         ^^
 
@@ -530,7 +530,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:3:51 error: access: type ptr<private, f32, read_write> cannot be indexed
     %3:ptr<private, f32, read_write> = access %2, 1u
                                                   ^^
@@ -567,7 +567,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:8:25 error: access: type MyStruct cannot be dynamically indexed
     %4:i32 = access %2, %3
                         ^^
@@ -610,7 +610,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.str(),
+        res.Failure().reason.Str(),
         R"(:8:25 error: access: type ptr<private, MyStruct, read_write> cannot be dynamically indexed
     %4:i32 = access %2, %3
                         ^^
@@ -646,7 +646,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
              ^^^^^^
@@ -678,7 +678,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.str(),
+        res.Failure().reason.Str(),
         R"(:3:40 error: access: result of access chain is type ptr<private, f32, read_write> but instruction type is ptr<private, i32, read_write>
     %3:ptr<private, i32, read_write> = access %2, 1u, 1u
                                        ^^^^^^
@@ -710,7 +710,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.str(),
+        res.Failure().reason.Str(),
         R"(:3:14 error: access: result of access chain is type ptr<private, f32, read_write> but instruction type is f32
     %3:f32 = access %2, 1u, 1u
              ^^^^^^
@@ -741,7 +741,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:3:25 error: access: cannot obtain address of vector element
     %3:f32 = access %2, 1u
                         ^^
@@ -786,7 +786,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:3:29 error: access: cannot obtain address of vector element
     %3:f32 = access %2, 1u, 1u
                             ^^
@@ -832,7 +832,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.str(),
+        res.Failure().reason.Str(),
         R"(:3:34 error: access: result of access chain is type ptr<storage, f32, read> but instruction type is ptr<uniform, f32, read>
     %3:ptr<uniform, f32, read> = access %2, 1u
                                  ^^^^^^
@@ -864,7 +864,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.str(),
+        res.Failure().reason.Str(),
         R"(:3:40 error: access: result of access chain is type ptr<storage, f32, read> but instruction type is ptr<storage, f32, read_write>
     %3:ptr<storage, f32, read_write> = access %2, 1u
                                        ^^^^^^
@@ -921,7 +921,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:3:5 error: block: terminator which isn't the final instruction
     ret
     ^^^
@@ -963,7 +963,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:4:7 error: block: does not end in a terminator instruction
       %b2 = block {  # true
       ^^^^^^^^^^^
@@ -996,7 +996,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
        ^^
 
@@ -1033,7 +1033,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
        ^^^^^
 
@@ -1072,7 +1072,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: if: result is undefined
+    EXPECT_EQ(res.Failure().reason.Str(), R"(:3:5 error: if: result is undefined
     undef = if true [t: %b2, f: %b3] {  # if_1
     ^^^^^
 
@@ -1119,7 +1119,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:4:7 error: block: does not end in a terminator instruction
       %b2 = block {  # body
       ^^^^^^^^^^^
@@ -1143,7 +1143,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(), R"(:2:3 error: var: result is undefined
+    EXPECT_EQ(res.Failure().reason.Str(), R"(:2:3 error: var: result is undefined
   undef = var
   ^^^^^
 
@@ -1170,7 +1170,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: var: result is undefined
+    EXPECT_EQ(res.Failure().reason.Str(), R"(:3:5 error: var: result is undefined
     undef = var
     ^^^^^
 
@@ -1200,7 +1200,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
                                         ^^^
 
@@ -1229,7 +1229,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: let: result is undefined
+    EXPECT_EQ(res.Failure().reason.Str(), R"(:3:5 error: let: result is undefined
     undef = let 1i
     ^^^^^
 
@@ -1258,7 +1258,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
                  ^^^^^
 
@@ -1287,7 +1287,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
              ^^^
 
@@ -1340,7 +1340,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(), expected);
+    EXPECT_EQ(res.Failure().reason.Str(), expected);
 }
 
 TEST_F(IR_ValidatorTest, Instruction_NullInstruction) {
@@ -1354,7 +1354,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:3:5 error: var: instruction of result is undefined
     %2:ptr<function, f32, read_write> = var
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -1386,7 +1386,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(), R"(:3:46 error: var: operand is not alive
+    EXPECT_EQ(res.Failure().reason.Str(), R"(:3:46 error: var: operand is not alive
     %2:ptr<function, f32, read_write> = var, %3
                                              ^^
 
@@ -1417,7 +1417,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(), R"(:3:46 error: var: operand missing usage
+    EXPECT_EQ(res.Failure().reason.Str(), R"(:3:46 error: var: operand missing usage
     %2:ptr<function, f32, read_write> = var, %3
                                              ^^
 
@@ -1447,7 +1447,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(), R"(error: orphaned instruction: load
+    EXPECT_EQ(res.Failure().reason.Str(), R"(error: orphaned instruction: load
 note: # Disassembly
 %my_func = func():void -> %b1 {
   %b1 = block {
@@ -1467,7 +1467,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
                  ^^^^^
 
@@ -1494,7 +1494,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
                      ^^^^^
 
@@ -1524,7 +1524,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: binary: result is undefined
+    EXPECT_EQ(res.Failure().reason.Str(), R"(:3:5 error: binary: result is undefined
     undef = add 3i, 2i
     ^^^^^
 
@@ -1551,7 +1551,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
                       ^^^^^
 
@@ -1581,7 +1581,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: unary: result is undefined
+    EXPECT_EQ(res.Failure().reason.Str(), R"(:3:5 error: unary: result is undefined
     undef = negation 2i
     ^^^^^
 
@@ -1611,7 +1611,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.str(),
+        res.Failure().reason.Str(),
         R"(:3:5 error: unary: unary instruction result type (f32) does not match overload result type (i32)
     %2:f32 = complement 2i
     ^^^^^^^^^^^^^^^^^^^^^^
@@ -1653,7 +1653,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
         ^^^^^^^
 
@@ -1691,7 +1691,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.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
         ^^^^^^^^^^
@@ -1735,7 +1735,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.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
         ^^^^^^^^^^^^^^^^^^^^
@@ -1796,7 +1796,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.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
                     ^^
@@ -1836,7 +1836,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:8:5 error: exit_if: found outside all control instructions
     exit_if  # if_1
     ^^^^^^^
@@ -1879,7 +1879,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:7:13 error: exit_if: if target jumps over other control instructions
             exit_if  # if_1
             ^^^^^^^
@@ -1932,7 +1932,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:7:13 error: exit_if: if target jumps over other control instructions
             exit_if  # if_1
             ^^^^^^^
@@ -1984,7 +1984,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:7:13 error: exit_if: if target jumps over other control instructions
             exit_if  # if_1
             ^^^^^^^
@@ -2043,7 +2043,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:5:9 error: exit_switch: has no parent control instruction
         exit_switch  # undef
         ^^^^^^^^^^^
@@ -2084,7 +2084,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.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
         ^^^^^^^^^^^^^^
@@ -2128,7 +2128,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.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
         ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -2190,7 +2190,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.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
                         ^^
@@ -2234,7 +2234,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:10:9 error: exit_switch: switch not found in parent control instructions
         exit_switch  # switch_1
         ^^^^^^^^^^^
@@ -2315,7 +2315,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:7:13 error: exit_switch: switch target jumps over other control instructions
             exit_switch  # switch_1
             ^^^^^^^^^^^
@@ -2366,7 +2366,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:7:13 error: exit_switch: switch target jumps over other control instructions
             exit_switch  # switch_1
             ^^^^^^^^^^^
@@ -2423,7 +2423,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:5:9 error: exit_loop: has no parent control instruction
         exit_loop  # undef
         ^^^^^^^^^
@@ -2466,7 +2466,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.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
         ^^^^^^^^^^^^
@@ -2513,7 +2513,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.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
         ^^^^^^^^^^^^^^^^^^^^^^
@@ -2578,7 +2578,7 @@
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
     EXPECT_EQ(
-        res.Failure().reason.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
                       ^^
@@ -2624,7 +2624,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:13:9 error: exit_loop: loop not found in parent control instructions
         exit_loop  # loop_1
         ^^^^^^^^^
@@ -2707,7 +2707,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:7:13 error: exit_loop: loop target jumps over other control instructions
             exit_loop  # loop_1
             ^^^^^^^^^
@@ -2762,7 +2762,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:7:13 error: exit_loop: loop target jumps over other control instructions
             exit_loop  # loop_1
             ^^^^^^^^^
@@ -2812,7 +2812,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:8:9 error: exit_loop: loop exit jumps out of continuing block
         exit_loop  # loop_1
         ^^^^^^^^^
@@ -2858,7 +2858,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:10:13 error: exit_loop: loop exit jumps out of continuing block
             exit_loop  # loop_1
             ^^^^^^^^^
@@ -2910,7 +2910,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:5:9 error: exit_loop: loop exit not permitted in loop initializer
         exit_loop  # loop_1
         ^^^^^^^^^
@@ -2960,7 +2960,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:7:13 error: exit_loop: loop exit not permitted in loop initializer
             exit_loop  # loop_1
             ^^^^^^^^^
@@ -3024,7 +3024,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: return: undefined function
+    EXPECT_EQ(res.Failure().reason.Str(), R"(:3:5 error: return: undefined function
     ret
     ^^^
 
@@ -3049,7 +3049,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
     ^^^^^^^
 
@@ -3074,7 +3074,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(), R"(:3:5 error: return: expected return value
+    EXPECT_EQ(res.Failure().reason.Str(), R"(:3:5 error: return: expected return value
     ret
     ^^^
 
@@ -3099,7 +3099,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:3:5 error: return: return value type does not match function return type
     ret 42.0f
     ^^^^^^^^^
@@ -3127,7 +3127,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(), R"(:3:19 error: load: operand is undefined
+    EXPECT_EQ(res.Failure().reason.Str(), R"(:3:19 error: load: operand is undefined
     %2:i32 = load undef
                   ^^^^^
 
@@ -3156,7 +3156,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:4:19 error: load source operand is not a memory view
     %3:f32 = load %l
                   ^^
@@ -3187,7 +3187,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:4:19 error: result type does not match source store type
     %3:f32 = load %2
                   ^^
@@ -3217,7 +3217,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
           ^^^^^
 
@@ -3246,7 +3246,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
               ^^^^^
 
@@ -3276,7 +3276,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:4:15 error: store target operand is not a memory view
     store %l, 42u
               ^^^
@@ -3307,7 +3307,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:4:15 error: value type does not match store type
     store %2, 42u
               ^^^
@@ -3339,7 +3339,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(),
+    EXPECT_EQ(res.Failure().reason.Str(),
               R"(:4:5 error: load_vector_element: result is undefined
     undef = load_vector_element %2, 1i
     ^^^^^
@@ -3370,7 +3370,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
                                  ^^^^^
 
@@ -3400,7 +3400,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
                                      ^^^^^
 
@@ -3430,7 +3430,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
                          ^^^^^
 
@@ -3460,7 +3460,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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
                              ^^^^^
 
@@ -3499,7 +3499,7 @@
 
     auto res = ir::Validate(mod);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.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/core/ir/value.h b/src/tint/lang/core/ir/value.h
index e2819bc..0603e87 100644
--- a/src/tint/lang/core/ir/value.h
+++ b/src/tint/lang/core/ir/value.h
@@ -48,7 +48,7 @@
     size_t operand_index = 0u;
 
     /// @returns the hash code of the Usage
-    size_t HashCode() const { return Hash(instruction, operand_index); }
+    tint::HashCode HashCode() const { return Hash(instruction, operand_index); }
 
     /// An equality helper for Usage.
     /// @param other the usage to compare against
diff --git a/src/tint/lang/core/type/abstract_float.cc b/src/tint/lang/core/type/abstract_float.cc
index 0a21bd5..7bc7e76 100644
--- a/src/tint/lang/core/type/abstract_float.cc
+++ b/src/tint/lang/core/type/abstract_float.cc
@@ -34,7 +34,7 @@
 
 namespace tint::core::type {
 
-AbstractFloat::AbstractFloat() : Base(Hash(tint::TypeInfo::Of<AbstractFloat>().full_hashcode)) {}
+AbstractFloat::AbstractFloat() : Base(Hash(tint::TypeCode::Of<AbstractFloat>().bits)) {}
 
 AbstractFloat::~AbstractFloat() = default;
 
diff --git a/src/tint/lang/core/type/abstract_int.cc b/src/tint/lang/core/type/abstract_int.cc
index b16e261..bd51897 100644
--- a/src/tint/lang/core/type/abstract_int.cc
+++ b/src/tint/lang/core/type/abstract_int.cc
@@ -34,7 +34,7 @@
 
 namespace tint::core::type {
 
-AbstractInt::AbstractInt() : Base(Hash(tint::TypeInfo::Of<AbstractInt>().full_hashcode)) {}
+AbstractInt::AbstractInt() : Base(Hash(tint::TypeCode::Of<AbstractInt>().bits)) {}
 
 AbstractInt::~AbstractInt() = default;
 
diff --git a/src/tint/lang/core/type/array.cc b/src/tint/lang/core/type/array.cc
index d74d582..307c63c 100644
--- a/src/tint/lang/core/type/array.cc
+++ b/src/tint/lang/core/type/array.cc
@@ -73,7 +73,7 @@
              uint32_t size,
              uint32_t stride,
              uint32_t implicit_stride)
-    : Base(Hash(tint::TypeInfo::Of<Array>().full_hashcode, count, align, size, stride),
+    : Base(Hash(tint::TypeCode::Of<Array>().bits, count, align, size, stride),
            FlagsFrom(element, count)),
       element_(element),
       count_(count),
diff --git a/src/tint/lang/core/type/array_count.cc b/src/tint/lang/core/type/array_count.cc
index 7dbc935..6049bc9 100644
--- a/src/tint/lang/core/type/array_count.cc
+++ b/src/tint/lang/core/type/array_count.cc
@@ -39,8 +39,7 @@
 ArrayCount::~ArrayCount() = default;
 
 ConstantArrayCount::ConstantArrayCount(uint32_t val)
-    : Base(static_cast<size_t>(tint::TypeInfo::Of<ConstantArrayCount>().full_hashcode)),
-      value(val) {}
+    : Base(static_cast<size_t>(tint::TypeCode::Of<ConstantArrayCount>().bits)), value(val) {}
 ConstantArrayCount::~ConstantArrayCount() = default;
 
 bool ConstantArrayCount::Equals(const UniqueNode& other) const {
@@ -59,7 +58,7 @@
 }
 
 RuntimeArrayCount::RuntimeArrayCount()
-    : Base(static_cast<size_t>(tint::TypeInfo::Of<RuntimeArrayCount>().full_hashcode)) {}
+    : Base(static_cast<size_t>(tint::TypeCode::Of<RuntimeArrayCount>().bits)) {}
 RuntimeArrayCount::~RuntimeArrayCount() = default;
 
 bool RuntimeArrayCount::Equals(const UniqueNode& other) const {
diff --git a/src/tint/lang/core/type/atomic.cc b/src/tint/lang/core/type/atomic.cc
index 775ab46..a683f24 100644
--- a/src/tint/lang/core/type/atomic.cc
+++ b/src/tint/lang/core/type/atomic.cc
@@ -39,7 +39,7 @@
 namespace tint::core::type {
 
 Atomic::Atomic(const core::type::Type* subtype)
-    : Base(Hash(tint::TypeInfo::Of<Atomic>().full_hashcode, subtype),
+    : Base(Hash(tint::TypeCode::Of<Atomic>().bits, subtype),
            core::type::Flags{
                Flag::kCreationFixedFootprint,
                Flag::kFixedFootprint,
diff --git a/src/tint/lang/core/type/bool.cc b/src/tint/lang/core/type/bool.cc
index fa48608..1a86fed 100644
--- a/src/tint/lang/core/type/bool.cc
+++ b/src/tint/lang/core/type/bool.cc
@@ -34,7 +34,7 @@
 namespace tint::core::type {
 
 Bool::Bool()
-    : Base(static_cast<size_t>(tint::TypeInfo::Of<Bool>().full_hashcode),
+    : Base(static_cast<size_t>(tint::TypeCode::Of<Bool>().bits),
            core::type::Flags{
                Flag::kConstructable,
                Flag::kCreationFixedFootprint,
diff --git a/src/tint/lang/core/type/depth_multisampled_texture.cc b/src/tint/lang/core/type/depth_multisampled_texture.cc
index 197014a..5daed0e 100644
--- a/src/tint/lang/core/type/depth_multisampled_texture.cc
+++ b/src/tint/lang/core/type/depth_multisampled_texture.cc
@@ -46,7 +46,7 @@
 }  // namespace
 
 DepthMultisampledTexture::DepthMultisampledTexture(TextureDimension dim)
-    : Base(Hash(TypeInfo::Of<DepthMultisampledTexture>().full_hashcode, dim), dim) {
+    : Base(Hash(TypeCode::Of<DepthMultisampledTexture>().bits, dim), dim) {
     TINT_ASSERT(IsValidDepthDimension(dim));
 }
 
diff --git a/src/tint/lang/core/type/depth_texture.cc b/src/tint/lang/core/type/depth_texture.cc
index 721c9b9..a246ed7 100644
--- a/src/tint/lang/core/type/depth_texture.cc
+++ b/src/tint/lang/core/type/depth_texture.cc
@@ -47,7 +47,7 @@
 }  // namespace
 
 DepthTexture::DepthTexture(TextureDimension dim)
-    : Base(Hash(TypeInfo::Of<DepthTexture>().full_hashcode, dim), dim) {
+    : Base(Hash(TypeCode::Of<DepthTexture>().bits, dim), dim) {
     TINT_ASSERT(IsValidDepthDimension(dim));
 }
 
diff --git a/src/tint/lang/core/type/external_texture.cc b/src/tint/lang/core/type/external_texture.cc
index d64e93c..54ede32 100644
--- a/src/tint/lang/core/type/external_texture.cc
+++ b/src/tint/lang/core/type/external_texture.cc
@@ -35,8 +35,8 @@
 namespace tint::core::type {
 
 ExternalTexture::ExternalTexture()
-    : Base(static_cast<size_t>(tint::TypeInfo::Of<ExternalTexture>().full_hashcode),
-           TextureDimension::k2d) {}
+    : Base(static_cast<size_t>(tint::TypeCode::Of<ExternalTexture>().bits), TextureDimension::k2d) {
+}
 
 ExternalTexture::~ExternalTexture() = default;
 
diff --git a/src/tint/lang/core/type/f16.cc b/src/tint/lang/core/type/f16.cc
index 5d4c5ba..a73f394 100644
--- a/src/tint/lang/core/type/f16.cc
+++ b/src/tint/lang/core/type/f16.cc
@@ -34,7 +34,7 @@
 namespace tint::core::type {
 
 F16::F16()
-    : Base(static_cast<size_t>(tint::TypeInfo::Of<F16>().full_hashcode),
+    : Base(static_cast<size_t>(tint::TypeCode::Of<F16>().bits),
            core::type::Flags{
                Flag::kConstructable,
                Flag::kCreationFixedFootprint,
diff --git a/src/tint/lang/core/type/f32.cc b/src/tint/lang/core/type/f32.cc
index 5cd89bd..30153f1 100644
--- a/src/tint/lang/core/type/f32.cc
+++ b/src/tint/lang/core/type/f32.cc
@@ -34,7 +34,7 @@
 namespace tint::core::type {
 
 F32::F32()
-    : Base(static_cast<size_t>(tint::TypeInfo::Of<F32>().full_hashcode),
+    : Base(static_cast<size_t>(tint::TypeCode::Of<F32>().bits),
            core::type::Flags{
                Flag::kConstructable,
                Flag::kCreationFixedFootprint,
diff --git a/src/tint/lang/core/type/i32.cc b/src/tint/lang/core/type/i32.cc
index 1e6b820..d1d02ea 100644
--- a/src/tint/lang/core/type/i32.cc
+++ b/src/tint/lang/core/type/i32.cc
@@ -34,7 +34,7 @@
 namespace tint::core::type {
 
 I32::I32()
-    : Base(static_cast<size_t>(tint::TypeInfo::Of<I32>().full_hashcode),
+    : Base(static_cast<size_t>(tint::TypeCode::Of<I32>().bits),
            core::type::Flags{
                Flag::kConstructable,
                Flag::kCreationFixedFootprint,
diff --git a/src/tint/lang/core/type/matrix.cc b/src/tint/lang/core/type/matrix.cc
index 17a90a9..f6d1c16 100644
--- a/src/tint/lang/core/type/matrix.cc
+++ b/src/tint/lang/core/type/matrix.cc
@@ -39,7 +39,7 @@
 namespace tint::core::type {
 
 Matrix::Matrix(const Vector* column_type, uint32_t columns)
-    : Base(Hash(tint::TypeInfo::Of<Vector>().full_hashcode, columns, column_type),
+    : Base(Hash(tint::TypeCode::Of<Vector>().bits, columns, column_type),
            core::type::Flags{
                Flag::kConstructable,
                Flag::kCreationFixedFootprint,
diff --git a/src/tint/lang/core/type/multisampled_texture.cc b/src/tint/lang/core/type/multisampled_texture.cc
index 3e8a86c..3094042 100644
--- a/src/tint/lang/core/type/multisampled_texture.cc
+++ b/src/tint/lang/core/type/multisampled_texture.cc
@@ -39,8 +39,7 @@
 namespace tint::core::type {
 
 MultisampledTexture::MultisampledTexture(TextureDimension dim, const Type* type)
-    : Base(Hash(tint::TypeInfo::Of<MultisampledTexture>().full_hashcode, dim, type), dim),
-      type_(type) {
+    : Base(Hash(tint::TypeCode::Of<MultisampledTexture>().bits, dim, type), dim), type_(type) {
     TINT_ASSERT(type_);
 }
 
diff --git a/src/tint/lang/core/type/pointer.cc b/src/tint/lang/core/type/pointer.cc
index bb59afe..23f7bb7 100644
--- a/src/tint/lang/core/type/pointer.cc
+++ b/src/tint/lang/core/type/pointer.cc
@@ -38,7 +38,7 @@
 namespace tint::core::type {
 
 Pointer::Pointer(core::AddressSpace address_space, const Type* store_type, core::Access access)
-    : Base(Hash(tint::TypeInfo::Of<Pointer>().full_hashcode), address_space, store_type, access) {}
+    : Base(Hash(tint::TypeCode::Of<Pointer>().bits), address_space, store_type, access) {}
 
 bool Pointer::Equals(const UniqueNode& other) const {
     if (auto* o = other.As<Pointer>()) {
diff --git a/src/tint/lang/core/type/reference.cc b/src/tint/lang/core/type/reference.cc
index 230ca87..1bb7410 100644
--- a/src/tint/lang/core/type/reference.cc
+++ b/src/tint/lang/core/type/reference.cc
@@ -37,7 +37,7 @@
 namespace tint::core::type {
 
 Reference::Reference(core::AddressSpace address_space, const Type* store_type, core::Access access)
-    : Base(Hash(tint::TypeInfo::Of<Pointer>().full_hashcode), address_space, store_type, access) {}
+    : Base(Hash(tint::TypeCode::Of<Reference>().bits), address_space, store_type, access) {}
 
 bool Reference::Equals(const UniqueNode& other) const {
     if (auto* o = other.As<Reference>()) {
diff --git a/src/tint/lang/core/type/sampled_texture.cc b/src/tint/lang/core/type/sampled_texture.cc
index 5fc4355..d8e6308 100644
--- a/src/tint/lang/core/type/sampled_texture.cc
+++ b/src/tint/lang/core/type/sampled_texture.cc
@@ -39,7 +39,7 @@
 namespace tint::core::type {
 
 SampledTexture::SampledTexture(TextureDimension dim, const Type* type)
-    : Base(Hash(TypeInfo::Of<SampledTexture>().full_hashcode, dim, type), dim), type_(type) {
+    : Base(Hash(TypeCode::Of<SampledTexture>().bits, dim, type), dim), type_(type) {
     TINT_ASSERT(type_);
 }
 
diff --git a/src/tint/lang/core/type/sampler.cc b/src/tint/lang/core/type/sampler.cc
index 4857513..4d7e9d4 100644
--- a/src/tint/lang/core/type/sampler.cc
+++ b/src/tint/lang/core/type/sampler.cc
@@ -35,8 +35,7 @@
 namespace tint::core::type {
 
 Sampler::Sampler(SamplerKind kind)
-    : Base(Hash(tint::TypeInfo::Of<Sampler>().full_hashcode, kind), core::type::Flags{}),
-      kind_(kind) {}
+    : Base(Hash(tint::TypeCode::Of<Sampler>().bits, kind), core::type::Flags{}), kind_(kind) {}
 
 Sampler::~Sampler() = default;
 
diff --git a/src/tint/lang/core/type/storage_texture.cc b/src/tint/lang/core/type/storage_texture.cc
index fc9b218..879ff99 100644
--- a/src/tint/lang/core/type/storage_texture.cc
+++ b/src/tint/lang/core/type/storage_texture.cc
@@ -42,7 +42,7 @@
                                core::TexelFormat format,
                                core::Access access,
                                const Type* subtype)
-    : Base(Hash(tint::TypeInfo::Of<StorageTexture>().full_hashcode, dim, format, access), dim),
+    : Base(Hash(tint::TypeCode::Of<StorageTexture>().bits, dim, format, access), dim),
       texel_format_(format),
       access_(access),
       subtype_(subtype) {}
diff --git a/src/tint/lang/core/type/struct.cc b/src/tint/lang/core/type/struct.cc
index ff08e35..b26042a 100644
--- a/src/tint/lang/core/type/struct.cc
+++ b/src/tint/lang/core/type/struct.cc
@@ -66,7 +66,7 @@
 }  // namespace
 
 Struct::Struct(Symbol name)
-    : Base(Hash(tint::TypeInfo::Of<Struct>().full_hashcode, name), type::Flags{}),
+    : Base(Hash(tint::TypeCode::Of<Struct>().bits, name), type::Flags{}),
       name_(name),
       members_{},
       align_(0),
@@ -78,7 +78,7 @@
                uint32_t align,
                uint32_t size,
                uint32_t size_no_padding)
-    : Base(Hash(tint::TypeInfo::Of<Struct>().full_hashcode, name), FlagsFrom(members)),
+    : Base(Hash(tint::TypeCode::Of<Struct>().bits, name), FlagsFrom(members)),
       name_(name),
       members_(std::move(members)),
       align_(align),
diff --git a/src/tint/lang/core/type/u32.cc b/src/tint/lang/core/type/u32.cc
index a73dc23..409e1fb 100644
--- a/src/tint/lang/core/type/u32.cc
+++ b/src/tint/lang/core/type/u32.cc
@@ -34,7 +34,7 @@
 namespace tint::core::type {
 
 U32::U32()
-    : Base(static_cast<size_t>(tint::TypeInfo::Of<U32>().full_hashcode),
+    : Base(static_cast<size_t>(tint::TypeCode::Of<U32>().bits),
            core::type::Flags{
                Flag::kConstructable,
                Flag::kCreationFixedFootprint,
diff --git a/src/tint/lang/core/type/vector.cc b/src/tint/lang/core/type/vector.cc
index 9e1c128..38acaed 100644
--- a/src/tint/lang/core/type/vector.cc
+++ b/src/tint/lang/core/type/vector.cc
@@ -38,7 +38,7 @@
 namespace tint::core::type {
 
 Vector::Vector(Type const* subtype, uint32_t width, bool packed /* = false */)
-    : Base(Hash(tint::TypeInfo::Of<Vector>().full_hashcode, width, subtype, packed),
+    : Base(Hash(tint::TypeCode::Of<Vector>().bits, width, subtype, packed),
            core::type::Flags{
                Flag::kConstructable,
                Flag::kCreationFixedFootprint,
diff --git a/src/tint/lang/core/type/void.cc b/src/tint/lang/core/type/void.cc
index 8f2b7fd..7e1fbf2 100644
--- a/src/tint/lang/core/type/void.cc
+++ b/src/tint/lang/core/type/void.cc
@@ -33,8 +33,7 @@
 
 namespace tint::core::type {
 
-Void::Void()
-    : Base(static_cast<size_t>(tint::TypeInfo::Of<Void>().full_hashcode), core::type::Flags{}) {}
+Void::Void() : Base(static_cast<size_t>(tint::TypeCode::Of<Void>().bits), core::type::Flags{}) {}
 
 Void::~Void() = default;
 
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 bd3deb4..a9c8c31 100644
--- a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
@@ -202,6 +202,8 @@
         manager.Add<ast::transform::ZeroInitWorkgroupMemory>();
     }
 
+    manager.Add<ast::transform::AddBlockAttribute>();
+
     manager.Add<ast::transform::OffsetFirstIndex>();
 
     // CanonicalizeEntryPointIO must come after Robustness
@@ -234,7 +236,6 @@
 
     manager.Add<ast::transform::PromoteInitializersToLet>();
     manager.Add<ast::transform::AddEmptyEntryPoint>();
-    manager.Add<ast::transform::AddBlockAttribute>();
 
     // Std140 must come after PromoteSideEffectsToDecl and before SimplifyPointers.
     manager.Add<ast::transform::Std140>();
@@ -354,7 +355,7 @@
         helpers_insertion_point += helpers_.lines.size();
     }
 
-    return !diagnostics_.contains_errors();
+    return !diagnostics_.ContainsErrors();
 }
 
 void ASTPrinter::RecordExtension(const ast::Enable* enable) {
@@ -381,8 +382,8 @@
     auto* dst_type = TypeOf(expr)->UnwrapRef();
 
     if (!dst_type->is_integer_scalar_or_vector() && !dst_type->is_float_scalar_or_vector()) {
-        diagnostics_.add_error(diag::System::Writer,
-                               "Unable to do bitcast to type " + dst_type->FriendlyName());
+        diagnostics_.AddError(diag::System::Writer,
+                              "Unable to do bitcast to type " + dst_type->FriendlyName());
         return;
     }
 
@@ -1503,9 +1504,9 @@
             out << "imageStore";
             break;
         default:
-            diagnostics_.add_error(diag::System::Writer,
-                                   "Internal compiler error: Unhandled texture builtin '" +
-                                       std::string(builtin->str()) + "'");
+            diagnostics_.AddError(diag::System::Writer,
+                                  "Internal compiler error: Unhandled texture builtin '" +
+                                      std::string(builtin->str()) + "'");
             return;
     }
 
@@ -1728,8 +1729,8 @@
         case wgsl::BuiltinFn::kUnpack4X8Unorm:
             return "unpackUnorm4x8";
         default:
-            diagnostics_.add_error(diag::System::Writer,
-                                   "Unknown builtin method: " + std::string(builtin->str()));
+            diagnostics_.AddError(diag::System::Writer,
+                                  "Unknown builtin method: " + std::string(builtin->str()));
     }
 
     return "";
@@ -1908,9 +1909,9 @@
         [&](const ast::Let* let) { EmitProgramConstVariable(let); },
         [&](const ast::Override*) {
             // Override is removed with SubstituteOverride
-            diagnostics_.add_error(diag::System::Writer,
-                                   "override-expressions should have been removed with the "
-                                   "SubstituteOverride transform");
+            diagnostics_.AddError(diag::System::Writer,
+                                  "override-expressions should have been removed with the "
+                                  "SubstituteOverride transform");
         },
         [&](const ast::Const*) {
             // Constants are embedded at their use
@@ -2174,7 +2175,7 @@
             out << "local_size_" << (i == 0 ? "x" : i == 1 ? "y" : "z") << " = ";
 
             if (!wgsize[i].has_value()) {
-                diagnostics_.add_error(
+                diagnostics_.AddError(
                     diag::System::Writer,
                     "override-expressions should have been removed with the SubstituteOverride "
                     "transform");
@@ -2278,8 +2279,8 @@
 
             auto count = a->ConstantCount();
             if (!count) {
-                diagnostics_.add_error(diag::System::Writer,
-                                       core::type::Array::kErrExpectedConstantCount);
+                diagnostics_.AddError(diag::System::Writer,
+                                      core::type::Array::kErrExpectedConstantCount);
                 return;
             }
 
@@ -2330,7 +2331,7 @@
                     return;
                 }
             }
-            diagnostics_.add_error(diag::System::Writer, "unknown integer literal suffix type");
+            diagnostics_.AddError(diag::System::Writer, "unknown integer literal suffix type");
         },  //
         TINT_ICE_ON_NO_MATCH);
 }
@@ -2382,8 +2383,8 @@
 
         auto count = arr->ConstantCount();
         if (!count) {
-            diagnostics_.add_error(diag::System::Writer,
-                                   core::type::Array::kErrExpectedConstantCount);
+            diagnostics_.AddError(diag::System::Writer,
+                                  core::type::Array::kErrExpectedConstantCount);
             return;
         }
 
@@ -2394,8 +2395,8 @@
             EmitZeroValue(out, arr->ElemType());
         }
     } else {
-        diagnostics_.add_error(diag::System::Writer,
-                               "Invalid type for zero emission: " + type->FriendlyName());
+        diagnostics_.AddError(diag::System::Writer,
+                              "Invalid type for zero emission: " + type->FriendlyName());
     }
 }
 
@@ -2670,8 +2671,8 @@
             } else {
                 auto count = arr->ConstantCount();
                 if (!count) {
-                    diagnostics_.add_error(diag::System::Writer,
-                                           core::type::Array::kErrExpectedConstantCount);
+                    diagnostics_.AddError(diag::System::Writer,
+                                          core::type::Array::kErrExpectedConstantCount);
                     return;
                 }
                 sizes.push_back(count.value());
@@ -2826,7 +2827,7 @@
     } else if (type->Is<core::type::Void>()) {
         out << "void";
     } else {
-        diagnostics_.add_error(diag::System::Writer, "unknown type in EmitType");
+        diagnostics_.AddError(diag::System::Writer, "unknown type in EmitType");
     }
 }
 
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 19aac5b..475f00a 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
@@ -35,13 +35,13 @@
 using GlslASTPrinterTest = TestHelper;
 
 TEST_F(GlslASTPrinterTest, InvalidProgram) {
-    Diagnostics().add_error(diag::System::Writer, "make the program invalid");
+    Diagnostics().AddError(diag::System::Writer, "make the program invalid");
     ASSERT_FALSE(IsValid());
     auto program = resolver::Resolve(*this);
     ASSERT_FALSE(program.IsValid());
     auto result = Generate(program, Options{}, "");
     EXPECT_NE(result, Success);
-    EXPECT_EQ(result.Failure().reason.str(), "error: make the program invalid");
+    EXPECT_EQ(result.Failure().reason.Str(), "error: make the program invalid");
 }
 
 TEST_F(GlslASTPrinterTest, Generate) {
@@ -128,7 +128,7 @@
 
     ASSERT_FALSE(gen.Generate());
     EXPECT_EQ(
-        gen.Diagnostics().str(),
+        gen.Diagnostics().Str(),
         R"(12:34 error: GLSL backend does not support extension 'chromium_internal_relaxed_uniform_layout')");
 }
 
diff --git a/src/tint/lang/glsl/writer/ast_printer/function_test.cc b/src/tint/lang/glsl/writer/ast_printer/function_test.cc
index c113c83..32a8b0f 100644
--- a/src/tint/lang/glsl/writer/ast_printer/function_test.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/function_test.cc
@@ -829,7 +829,7 @@
     ASTPrinter& gen = Build();
     gen.Generate();
     EXPECT_EQ(
-        gen.Diagnostics().str(),
+        gen.Diagnostics().Str(),
         R"(error: override-expressions should have been removed with the SubstituteOverride transform
 error: override-expressions should have been removed with the SubstituteOverride transform
 error: override-expressions should have been removed with the SubstituteOverride transform
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 6762ee6..25cc723 100644
--- a/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc
+++ b/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc
@@ -441,8 +441,8 @@
     auto* binding_info = inputs.Get<BindingInfo>();
     if (!binding_info) {
         ProgramBuilder b;
-        b.Diagnostics().add_error(diag::System::Transform,
-                                  "missing transform data for " + std::string(TypeInfo().name));
+        b.Diagnostics().AddError(diag::System::Transform,
+                                 "missing transform data for " + std::string(TypeInfo().name));
         return resolver::Resolve(b);
     }
 
diff --git a/src/tint/lang/glsl/writer/ast_raise/pad_structs.cc b/src/tint/lang/glsl/writer/ast_raise/pad_structs.cc
index 0d4aa89..08c8361 100644
--- a/src/tint/lang/glsl/writer/ast_raise/pad_structs.cc
+++ b/src/tint/lang/glsl/writer/ast_raise/pad_structs.cc
@@ -136,10 +136,9 @@
                           ctx.dst, struct_size - offset);
         }
 
-        tint::Vector<const ast::Attribute*, 1> struct_attribs;
+        tint::Vector<const ast::Attribute*, 1> struct_attribs = ctx.Clone(ast_str->attributes);
         if (!padding_members.IsEmpty()) {
-            struct_attribs =
-                tint::Vector{b.Disable(ast::DisabledValidation::kIgnoreStructMemberLimit)};
+            struct_attribs.Push(b.Disable(ast::DisabledValidation::kIgnoreStructMemberLimit));
         }
 
         auto* new_struct = b.create<ast::Struct>(ctx.Clone(ast_str->name), std::move(new_members),
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 2b31e07..7d3a4ab 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
@@ -74,7 +74,7 @@
     ApplyResult Run() {
         auto* cfg = inputs.Get<Config>();
         if (cfg == nullptr) {
-            b.Diagnostics().add_error(
+            b.Diagnostics().AddError(
                 diag::System::Transform,
                 "missing transform data for " +
                     std::string(tint::TypeInfo::Of<TextureBuiltinsFromUniform>().name));
diff --git a/src/tint/lang/glsl/writer/common/options.h b/src/tint/lang/glsl/writer/common/options.h
index 1f5298f..31e1244 100644
--- a/src/tint/lang/glsl/writer/common/options.h
+++ b/src/tint/lang/glsl/writer/common/options.h
@@ -88,7 +88,8 @@
     TextureBuiltinsFromUniformOptions texture_builtins_from_uniform = {};
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(disable_robustness,
+    TINT_REFLECT(Options,
+                 disable_robustness,
                  disable_workgroup_init,
                  disable_polyfill_integer_div_mod,
                  version,
@@ -96,9 +97,13 @@
                  placeholder_binding_point,
                  binding_remapper_options,
                  external_texture_options,
+                 first_instance_offset,
                  texture_builtins_from_uniform);
 };
 
+/// Ensure that all the fields of Options are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Options);
+
 }  // namespace tint::glsl::writer
 
 #endif  // SRC_TINT_LANG_GLSL_WRITER_COMMON_OPTIONS_H_
diff --git a/src/tint/lang/glsl/writer/common/version.h b/src/tint/lang/glsl/writer/common/version.h
index 9c3463a..7eb682e 100644
--- a/src/tint/lang/glsl/writer/common/version.h
+++ b/src/tint/lang/glsl/writer/common/version.h
@@ -68,9 +68,12 @@
     uint32_t minor_version = 1;
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(standard, major_version, minor_version);
+    TINT_REFLECT(Version, standard, major_version, minor_version);
 };
 
+/// Ensure that all the fields of Version are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Version);
+
 }  // namespace tint::glsl::writer
 
 namespace tint {
diff --git a/src/tint/lang/glsl/writer/printer/helper_test.h b/src/tint/lang/glsl/writer/printer/helper_test.h
index a720241..7550ecb 100644
--- a/src/tint/lang/glsl/writer/printer/helper_test.h
+++ b/src/tint/lang/glsl/writer/printer/helper_test.h
@@ -63,13 +63,13 @@
     /// @returns true if generation and validation succeeded
     bool Generate() {
         if (auto raised = Raise(mod); raised != Success) {
-            err_ = raised.Failure().reason.str();
+            err_ = raised.Failure().reason.Str();
             return false;
         }
 
         auto result = Print(mod, version);
         if (result != Success) {
-            err_ = result.Failure().reason.str();
+            err_ = result.Failure().reason.Str();
             return false;
         }
         output_ = result.Get();
diff --git a/src/tint/lang/glsl/writer/writer_bench.cc b/src/tint/lang/glsl/writer/writer_bench.cc
index 162e5b0..8505dac 100644
--- a/src/tint/lang/glsl/writer/writer_bench.cc
+++ b/src/tint/lang/glsl/writer/writer_bench.cc
@@ -38,7 +38,7 @@
 void GenerateGLSL(benchmark::State& state, std::string input_name) {
     auto res = bench::LoadProgram(input_name);
     if (res != Success) {
-        state.SkipWithError(res.Failure().reason.str());
+        state.SkipWithError(res.Failure().reason.Str());
         return;
     }
     auto& program = res->program;
@@ -53,7 +53,7 @@
         for (auto& ep : entry_points) {
             auto gen_res = Generate(program, {}, ep);
             if (gen_res != Success) {
-                state.SkipWithError(gen_res.Failure().reason.str());
+                state.SkipWithError(gen_res.Failure().reason.Str());
             }
         }
     }
diff --git a/src/tint/lang/hlsl/writer/BUILD.cmake b/src/tint/lang/hlsl/writer/BUILD.cmake
index 5a19a3c..a40f368 100644
--- a/src/tint/lang/hlsl/writer/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/BUILD.cmake
@@ -37,6 +37,7 @@
 include(lang/hlsl/writer/ast_printer/BUILD.cmake)
 include(lang/hlsl/writer/ast_raise/BUILD.cmake)
 include(lang/hlsl/writer/common/BUILD.cmake)
+include(lang/hlsl/writer/helpers/BUILD.cmake)
 
 if(TINT_BUILD_HLSL_WRITER)
 ################################################################################
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 f2a8f82..4552722 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
@@ -50,6 +50,7 @@
 #include "src/tint/lang/hlsl/writer/ast_raise/pixel_local.h"
 #include "src/tint/lang/hlsl/writer/ast_raise/remove_continue_in_switch.h"
 #include "src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.h"
+#include "src/tint/lang/hlsl/writer/common/option_helpers.h"
 #include "src/tint/lang/wgsl/ast/call_statement.h"
 #include "src/tint/lang/wgsl/ast/internal_attribute.h"
 #include "src/tint/lang/wgsl/ast/interpolate_attribute.h"
@@ -206,10 +207,9 @@
         manager.Add<ast::transform::Robustness>();
 
         ast::transform::Robustness::Config config = {};
-
         config.bindings_ignored = std::unordered_set<BindingPoint>(
-            options.binding_points_ignored_in_robustness_transform.cbegin(),
-            options.binding_points_ignored_in_robustness_transform.cend());
+            options.bindings.ignored_by_robustness_transform.cbegin(),
+            options.bindings.ignored_by_robustness_transform.cend());
 
         // Direct3D guarantees to return zero for any resource that is accessed out of bounds, and
         // according to the description of the assembly store_uav_typed, out of bounds addressing
@@ -219,20 +219,24 @@
         data.Add<ast::transform::Robustness::Config>(config);
     }
 
-    // Note: it is more efficient for MultiplanarExternalTexture to come after Robustness
-    data.Add<ast::transform::MultiplanarExternalTexture::NewBindingPoints>(
-        options.external_texture_options.bindings_map);
-    manager.Add<ast::transform::MultiplanarExternalTexture>();
+    ExternalTextureOptions external_texture_options{};
+    RemapperData remapper_data{};
+    ArrayLengthFromUniformOptions array_length_from_uniform_options{};
+    PopulateBindingRelatedOptions(options, remapper_data, external_texture_options,
+                                  array_length_from_uniform_options);
 
-    // BindingRemapper must come after MultiplanarExternalTexture
     manager.Add<ast::transform::BindingRemapper>();
-
     // D3D11 and 12 registers like `t3` and `c3` have the same bindingOffset number in
     // the remapping but should not be considered a collision because they have
     // different types.
     data.Add<ast::transform::BindingRemapper::Remappings>(
-        options.binding_remapper_options.binding_points, options.access_controls,
-        /* allow_collisions */ true);
+        remapper_data, options.bindings.access_controls, /* allow_collisions */ true);
+
+    // Note: it is more efficient for MultiplanarExternalTexture to come after Robustness
+    // MultiplanarExternalTexture must come after BindingRemapper
+    data.Add<ast::transform::MultiplanarExternalTexture::NewBindingPoints>(
+        external_texture_options.bindings_map, /* may_collide */ true);
+    manager.Add<ast::transform::MultiplanarExternalTexture>();
 
     {  // Builtin polyfills
         ast::transform::BuiltinPolyfill::Builtins polyfills;
@@ -330,11 +334,10 @@
     manager.Add<ast::transform::RemovePhonies>();
 
     // Build the config for the internal ArrayLengthFromUniform transform.
-    auto& array_length_from_uniform = options.array_length_from_uniform;
     ast::transform::ArrayLengthFromUniform::Config array_length_from_uniform_cfg(
-        array_length_from_uniform.ubo_binding);
+        array_length_from_uniform_options.ubo_binding);
     array_length_from_uniform_cfg.bindpoint_to_size_index =
-        array_length_from_uniform.bindpoint_to_size_index;
+        std::move(array_length_from_uniform_options.bindpoint_to_size_index);
 
     // DemoteToHelper must come after CanonicalizeEntryPointIO, PromoteSideEffectsToDecl, and
     // ExpandCompoundAssignment.
@@ -698,8 +701,8 @@
     auto* dst_el_type = dst_type->DeepestElement();
 
     if (!dst_el_type->is_integer_scalar() && !dst_el_type->is_float_scalar()) {
-        diagnostics_.add_error(diag::System::Writer,
-                               "Unable to do bitcast to type " + dst_el_type->FriendlyName());
+        diagnostics_.AddError(diag::System::Writer,
+                              "Unable to do bitcast to type " + dst_el_type->FriendlyName());
         return false;
     }
 
@@ -2443,8 +2446,8 @@
                     break;
                 }
                 default:
-                    diagnostics_.add_error(diag::System::Writer,
-                                           "Internal error: unhandled data packing builtin");
+                    diagnostics_.AddError(diag::System::Writer,
+                                          "Internal error: unhandled data packing builtin");
                     return false;
             }
 
@@ -2510,8 +2513,8 @@
                     Line(b) << "return f16tof32(uint2(i & 0xffff, i >> 16));";
                     break;
                 default:
-                    diagnostics_.add_error(diag::System::Writer,
-                                           "Internal error: unhandled data packing builtin");
+                    diagnostics_.AddError(diag::System::Writer,
+                                          "Internal error: unhandled data packing builtin");
                     return false;
             }
 
@@ -2585,8 +2588,8 @@
                     functionName = "dot4add_u8packed";
                     break;
                 default:
-                    diagnostics_.add_error(diag::System::Writer,
-                                           "Internal error: unhandled DP4a builtin");
+                    diagnostics_.AddError(diag::System::Writer,
+                                          "Internal error: unhandled DP4a builtin");
                     return false;
             }
             Line(b) << "return " << functionName << "(" << params[0] << ", " << params[1]
@@ -2925,9 +2928,9 @@
             out << "[";
             break;
         default:
-            diagnostics_.add_error(diag::System::Writer,
-                                   "Internal compiler error: Unhandled texture builtin '" +
-                                       std::string(builtin->str()) + "'");
+            diagnostics_.AddError(diag::System::Writer,
+                                  "Internal compiler error: Unhandled texture builtin '" +
+                                      std::string(builtin->str()) + "'");
             return false;
     }
 
@@ -3113,8 +3116,8 @@
         case wgsl::BuiltinFn::kSubgroupBroadcast:
             return "WaveReadLaneAt";
         default:
-            diagnostics_.add_error(diag::System::Writer,
-                                   "Unknown builtin method: " + std::string(builtin->str()));
+            diagnostics_.AddError(diag::System::Writer,
+                                  "Unknown builtin method: " + std::string(builtin->str()));
     }
 
     return "";
@@ -3386,7 +3389,7 @@
                 case core::AddressSpace::kWorkgroup:
                     return EmitWorkgroupVariable(sem);
                 case core::AddressSpace::kPushConstant:
-                    diagnostics_.add_error(
+                    diagnostics_.AddError(
                         diag::System::Writer,
                         "unhandled address space " + tint::ToString(sem->AddressSpace()));
                     return false;
@@ -3398,9 +3401,9 @@
         },
         [&](const ast::Override*) {
             // Override is removed with SubstituteOverride
-            diagnostics_.add_error(diag::System::Writer,
-                                   "override-expressions should have been removed with the "
-                                   "SubstituteOverride transform");
+            diagnostics_.AddError(diag::System::Writer,
+                                  "override-expressions should have been removed with the "
+                                  "SubstituteOverride transform");
             return false;
         },
         [&](const ast::Const*) {
@@ -3623,7 +3626,7 @@
                     out << ", ";
                 }
                 if (!wgsize[i].has_value()) {
-                    diagnostics_.add_error(
+                    diagnostics_.AddError(
                         diag::System::Writer,
                         "override-expressions should have been removed with the SubstituteOverride "
                         "transform");
@@ -3778,8 +3781,8 @@
 
             auto count = a->ConstantCount();
             if (!count) {
-                diagnostics_.add_error(diag::System::Writer,
-                                       core::type::Array::kErrExpectedConstantCount);
+                diagnostics_.AddError(diag::System::Writer,
+                                      core::type::Array::kErrExpectedConstantCount);
                 return false;
             }
 
@@ -3874,7 +3877,7 @@
                     out << "u";
                     return true;
             }
-            diagnostics_.add_error(diag::System::Writer, "unknown integer literal suffix type");
+            diagnostics_.AddError(diag::System::Writer, "unknown integer literal suffix type");
             return false;
         },  //
         TINT_ICE_ON_NO_MATCH);
@@ -4341,8 +4344,8 @@
                 }
                 const auto count = arr->ConstantCount();
                 if (!count) {
-                    diagnostics_.add_error(diag::System::Writer,
-                                           core::type::Array::kErrExpectedConstantCount);
+                    diagnostics_.AddError(diag::System::Writer,
+                                          core::type::Array::kErrExpectedConstantCount);
                     return false;
                 }
 
@@ -4581,7 +4584,7 @@
             if (auto builtin = attributes.builtin) {
                 auto name = builtin_to_attribute(builtin.value());
                 if (name.empty()) {
-                    diagnostics_.add_error(diag::System::Writer, "unsupported builtin");
+                    diagnostics_.AddError(diag::System::Writer, "unsupported builtin");
                     return false;
                 }
                 post += " : " + name;
@@ -4589,7 +4592,7 @@
             if (auto interpolation = attributes.interpolation) {
                 auto mod = interpolation_to_modifiers(interpolation->type, interpolation->sampling);
                 if (mod.empty()) {
-                    diagnostics_.add_error(diag::System::Writer, "unsupported interpolation");
+                    diagnostics_.AddError(diag::System::Writer, "unsupported interpolation");
                     return false;
                 }
                 pre += mod;
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 0d68b42..88db758 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
@@ -35,13 +35,13 @@
 using HlslASTPrinterTest = TestHelper;
 
 TEST_F(HlslASTPrinterTest, InvalidProgram) {
-    Diagnostics().add_error(diag::System::Writer, "make the program invalid");
+    Diagnostics().AddError(diag::System::Writer, "make the program invalid");
     ASSERT_FALSE(IsValid());
     auto program = resolver::Resolve(*this);
     ASSERT_FALSE(program.IsValid());
     auto result = Generate(program, Options{});
     EXPECT_NE(result, Success);
-    EXPECT_EQ(result.Failure().reason.str(), "error: make the program invalid");
+    EXPECT_EQ(result.Failure().reason.Str(), "error: make the program invalid");
 }
 
 TEST_F(HlslASTPrinterTest, UnsupportedExtension) {
@@ -51,7 +51,7 @@
 
     ASSERT_FALSE(gen.Generate());
     EXPECT_EQ(
-        gen.Diagnostics().str(),
+        gen.Diagnostics().Str(),
         R"(12:34 error: HLSL backend does not support extension 'chromium_internal_relaxed_uniform_layout')");
 }
 
diff --git a/src/tint/lang/hlsl/writer/ast_printer/function_test.cc b/src/tint/lang/hlsl/writer/ast_printer/function_test.cc
index 2f6822c..2575346 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/function_test.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/function_test.cc
@@ -737,7 +737,7 @@
 
     EXPECT_FALSE(gen.Generate()) << gen.Diagnostics();
     EXPECT_EQ(
-        gen.Diagnostics().str(),
+        gen.Diagnostics().Str(),
         R"(error: override-expressions should have been removed with the SubstituteOverride transform)");
 }
 
diff --git a/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.cc b/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.cc
index 22a8ff3..610fc4b 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/num_workgroups_from_uniform.cc
@@ -90,8 +90,8 @@
 
     auto* cfg = inputs.Get<Config>();
     if (cfg == nullptr) {
-        b.Diagnostics().add_error(diag::System::Transform,
-                                  "missing transform data for " + std::string(TypeInfo().name));
+        b.Diagnostics().AddError(diag::System::Transform,
+                                 "missing transform data for " + std::string(TypeInfo().name));
         return resolver::Resolve(b);
     }
 
diff --git a/src/tint/lang/hlsl/writer/ast_raise/pixel_local.cc b/src/tint/lang/hlsl/writer/ast_raise/pixel_local.cc
index de4f17d..b3fa496 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/pixel_local.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/pixel_local.cc
@@ -453,9 +453,9 @@
     uint32_t ROVRegisterIndex(uint32_t field_index) {
         auto idx = cfg.pls_member_to_rov_reg.Get(field_index);
         if (TINT_UNLIKELY(!idx)) {
-            b.Diagnostics().add_error(diag::System::Transform,
-                                      "PixelLocal::Config::attachments missing entry for field " +
-                                          std::to_string(field_index));
+            b.Diagnostics().AddError(diag::System::Transform,
+                                     "PixelLocal::Config::attachments missing entry for field " +
+                                         std::to_string(field_index));
             return 0;
         }
         return *idx;
@@ -466,9 +466,9 @@
     core::TexelFormat ROVTexelFormat(uint32_t field_index) {
         auto format = cfg.pls_member_to_rov_format.Get(field_index);
         if (TINT_UNLIKELY(!format)) {
-            b.Diagnostics().add_error(diag::System::Transform,
-                                      "PixelLocal::Config::attachments missing entry for field " +
-                                          std::to_string(field_index));
+            b.Diagnostics().AddError(diag::System::Transform,
+                                     "PixelLocal::Config::attachments missing entry for field " +
+                                         std::to_string(field_index));
             return core::TexelFormat::kUndefined;
         }
         return *format;
@@ -485,8 +485,8 @@
     auto* cfg = inputs.Get<Config>();
     if (!cfg) {
         ProgramBuilder b;
-        b.Diagnostics().add_error(diag::System::Transform,
-                                  "missing transform data for " + std::string(TypeInfo().name));
+        b.Diagnostics().AddError(diag::System::Transform,
+                                 "missing transform data for " + std::string(TypeInfo().name));
         return resolver::Resolve(b);
     }
 
diff --git a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc b/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc
index 5d38ff8..d6c1b25 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.cc
@@ -70,7 +70,7 @@
 
     const auto* data = config.Get<Config>();
     if (data == nullptr) {
-        b.Diagnostics().add_error(
+        b.Diagnostics().AddError(
             diag::System::Transform,
             "missing transform data for " +
                 std::string(tint::TypeInfo::Of<TruncateInterstageVariables>().name));
diff --git a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.h b/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.h
index ff2830b..d8a284a 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.h
+++ b/src/tint/lang/hlsl/writer/ast_raise/truncate_interstage_variables.h
@@ -124,9 +124,12 @@
         std::bitset<30> interstage_locations;
 
         /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-        TINT_REFLECT(interstage_variables);
+        TINT_REFLECT(Config, interstage_locations);
     };
 
+    /// Ensure that all the fields of Config are reflected.
+    TINT_ASSERT_ALL_FIELDS_REFLECTED(Config);
+
     /// Constructor using a the configuration provided in the input Data
     TruncateInterstageVariables();
 
diff --git a/src/tint/lang/hlsl/writer/common/BUILD.bazel b/src/tint/lang/hlsl/writer/common/BUILD.bazel
index 93cb98f..333c5e5 100644
--- a/src/tint/lang/hlsl/writer/common/BUILD.bazel
+++ b/src/tint/lang/hlsl/writer/common/BUILD.bazel
@@ -39,18 +39,27 @@
 cc_library(
   name = "common",
   srcs = [
+    "option_helpers.cc",
     "options.cc",
   ],
   hdrs = [
+    "option_helpers.h",
     "options.h",
   ],
   deps = [
     "//src/tint/api/common",
     "//src/tint/api/options",
     "//src/tint/lang/core",
+    "//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/reflection",
+    "//src/tint/utils/result",
+    "//src/tint/utils/rtti",
+    "//src/tint/utils/text",
     "//src/tint/utils/traits",
   ],
   copts = COPTS,
diff --git a/src/tint/lang/hlsl/writer/common/BUILD.cmake b/src/tint/lang/hlsl/writer/common/BUILD.cmake
index 1a5415e..75293b9 100644
--- a/src/tint/lang/hlsl/writer/common/BUILD.cmake
+++ b/src/tint/lang/hlsl/writer/common/BUILD.cmake
@@ -39,6 +39,8 @@
 # Kind:      lib
 ################################################################################
 tint_add_target(tint_lang_hlsl_writer_common lib
+  lang/hlsl/writer/common/option_helpers.cc
+  lang/hlsl/writer/common/option_helpers.h
   lang/hlsl/writer/common/options.cc
   lang/hlsl/writer/common/options.h
 )
@@ -47,8 +49,15 @@
   tint_api_common
   tint_api_options
   tint_lang_core
+  tint_utils_containers
+  tint_utils_diagnostic
+  tint_utils_ice
   tint_utils_macros
   tint_utils_math
+  tint_utils_memory
   tint_utils_reflection
+  tint_utils_result
+  tint_utils_rtti
+  tint_utils_text
   tint_utils_traits
 )
diff --git a/src/tint/lang/hlsl/writer/common/BUILD.gn b/src/tint/lang/hlsl/writer/common/BUILD.gn
index 39c9b06..b8d369d 100644
--- a/src/tint/lang/hlsl/writer/common/BUILD.gn
+++ b/src/tint/lang/hlsl/writer/common/BUILD.gn
@@ -40,6 +40,8 @@
 
 libtint_source_set("common") {
   sources = [
+    "option_helpers.cc",
+    "option_helpers.h",
     "options.cc",
     "options.h",
   ]
@@ -47,9 +49,16 @@
     "${tint_src_dir}/api/common",
     "${tint_src_dir}/api/options",
     "${tint_src_dir}/lang/core",
+    "${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/reflection",
+    "${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/hlsl/writer/common/option_helpers.cc b/src/tint/lang/hlsl/writer/common/option_helpers.cc
new file mode 100644
index 0000000..aace10b
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/common/option_helpers.cc
@@ -0,0 +1,231 @@
+/// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/hlsl/writer/common/option_helpers.h"
+
+#include <utility>
+
+#include "src/tint/utils/containers/hashset.h"
+
+namespace tint::hlsl::writer {
+
+/// binding::BindingInfo to tint::BindingPoint map
+using InfoToPointMap = tint::Hashmap<binding::BindingInfo, tint::BindingPoint, 8>;
+
+Result<SuccessType> ValidateBindingOptions(const Options& options) {
+    diag::List diagnostics;
+
+    tint::Hashmap<tint::BindingPoint, binding::BindingInfo, 8> seen_wgsl_bindings{};
+
+    InfoToPointMap seen_hlsl_buffer_bindings{};
+    InfoToPointMap seen_hlsl_texture_bindings{};
+    InfoToPointMap seen_hlsl_sampler_bindings{};
+
+    // Both wgsl_seen and spirv_seen check to see if the pair of [src, dst] are unique. If we have
+    // multiple entries that map the same [src, dst] pair, that's fine. We treat it as valid as it's
+    // possible for multiple entry points to use the remapper at the same time. If the pair doesn't
+    // match, then we report an error about a duplicate binding point.
+
+    auto wgsl_seen = [&diagnostics, &seen_wgsl_bindings](const tint::BindingPoint& src,
+                                                         const binding::BindingInfo& dst) -> bool {
+        if (auto binding = seen_wgsl_bindings.Get(src)) {
+            if (*binding != dst) {
+                std::stringstream str;
+                str << "found duplicate WGSL binding point: " << src;
+
+                diagnostics.AddError(diag::System::Writer, str.str());
+                return true;
+            }
+        }
+        seen_wgsl_bindings.Add(src, dst);
+        return false;
+    };
+
+    auto hlsl_seen = [&diagnostics](InfoToPointMap& map, const binding::BindingInfo& src,
+                                    const tint::BindingPoint& dst) -> bool {
+        if (auto binding = map.Get(src)) {
+            if (*binding != dst) {
+                std::stringstream str;
+                str << "found duplicate MSL binding point: [binding: " << src.binding << "]";
+                diagnostics.AddError(diag::System::Writer, str.str());
+                return true;
+            }
+        }
+        map.Add(src, dst);
+        return false;
+    };
+
+    auto valid = [&wgsl_seen, &hlsl_seen](InfoToPointMap& map, const auto& hsh) -> bool {
+        for (const auto& it : hsh) {
+            const auto& src_binding = it.first;
+            const auto& dst_binding = it.second;
+
+            if (wgsl_seen(src_binding, dst_binding)) {
+                return false;
+            }
+
+            if (hlsl_seen(map, dst_binding, src_binding)) {
+                return false;
+            }
+        }
+        return true;
+    };
+
+    // Storage and uniform are both [[buffer()]]
+    if (!valid(seen_hlsl_buffer_bindings, options.bindings.uniform)) {
+        diagnostics.AddNote(diag::System::Writer, "when processing uniform", {});
+        return Failure{std::move(diagnostics)};
+    }
+    if (!valid(seen_hlsl_buffer_bindings, options.bindings.storage)) {
+        diagnostics.AddNote(diag::System::Writer, "when processing storage", {});
+        return Failure{std::move(diagnostics)};
+    }
+
+    // Sampler is [[sampler()]]
+    if (!valid(seen_hlsl_sampler_bindings, options.bindings.sampler)) {
+        diagnostics.AddNote(diag::System::Writer, "when processing sampler", {});
+        return Failure{std::move(diagnostics)};
+    }
+
+    // Texture and storage texture are [[texture()]]
+    if (!valid(seen_hlsl_texture_bindings, options.bindings.texture)) {
+        diagnostics.AddNote(diag::System::Writer, "when processing texture", {});
+        return Failure{std::move(diagnostics)};
+    }
+    if (!valid(seen_hlsl_texture_bindings, options.bindings.storage_texture)) {
+        diagnostics.AddNote(diag::System::Writer, "when processing storage_texture", {});
+        return Failure{std::move(diagnostics)};
+    }
+
+    for (const auto& it : options.bindings.external_texture) {
+        const auto& src_binding = it.first;
+        const auto& plane0 = it.second.plane0;
+        const auto& plane1 = it.second.plane1;
+        const auto& metadata = it.second.metadata;
+
+        // Validate with the actual source regardless of what the remapper will do
+        if (wgsl_seen(src_binding, plane0)) {
+            diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+            return Failure{std::move(diagnostics)};
+        }
+
+        // Plane0 & Plane1 are [[texture()]]
+        if (hlsl_seen(seen_hlsl_texture_bindings, plane0, src_binding)) {
+            diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+            return Failure{std::move(diagnostics)};
+        }
+        if (hlsl_seen(seen_hlsl_texture_bindings, plane1, src_binding)) {
+            diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+            return Failure{std::move(diagnostics)};
+        }
+        // Metadata is [[buffer()]]
+        if (hlsl_seen(seen_hlsl_buffer_bindings, metadata, src_binding)) {
+            diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
+            return Failure{std::move(diagnostics)};
+        }
+    }
+
+    return Success;
+}
+
+// The remapped binding data and external texture data need to coordinate in order to put things in
+// the correct place when we're done. The binding remapper is run first, so make sure that the
+// external texture uses the new binding point.
+//
+// When the data comes in we have a list of all WGSL origin (group,binding) pairs to HLSL
+// (group,binding) in the `uniform`, `storage`, `texture`, and `sampler` arrays.
+void PopulateBindingRelatedOptions(
+    const Options& options,
+    RemapperData& remapper_data,
+    ExternalTextureOptions& external_texture,
+    ArrayLengthFromUniformOptions& array_length_from_uniform_options) {
+    auto create_remappings = [&remapper_data](const auto& hsh) {
+        for (const auto& it : hsh) {
+            const BindingPoint& src_binding_point = it.first;
+            const binding::BindingInfo& dst_binding_info = it.second;
+
+            BindingPoint dst_binding_point{dst_binding_info.group, dst_binding_info.binding};
+
+            // Skip redundant bindings
+            if (src_binding_point == dst_binding_point) {
+                continue;
+            }
+
+            remapper_data.emplace(src_binding_point, dst_binding_point);
+        }
+    };
+
+    create_remappings(options.bindings.uniform);
+    create_remappings(options.bindings.storage);
+    create_remappings(options.bindings.texture);
+    create_remappings(options.bindings.storage_texture);
+    create_remappings(options.bindings.sampler);
+
+    // External textures are re-bound to their plane0 location
+    for (const auto& it : options.bindings.external_texture) {
+        const BindingPoint& src_binding_point = it.first;
+        const binding::BindingInfo& plane0 = it.second.plane0;
+        const binding::BindingInfo& plane1 = it.second.plane1;
+        const binding::BindingInfo& metadata = it.second.metadata;
+
+        BindingPoint plane0_binding_point{plane0.group, plane0.binding};
+        BindingPoint plane1_binding_point{plane1.group, plane1.binding};
+        BindingPoint metadata_binding_point{metadata.group, metadata.binding};
+
+        // Use the re-bound HLSL plane0 value for the lookup key.
+        external_texture.bindings_map.emplace(
+            plane0_binding_point,
+            ExternalTextureOptions::BindingPoints{plane1_binding_point, metadata_binding_point});
+
+        // Bindings which go to the same slot in HLSL do not need to be re-bound.
+        if (src_binding_point == plane0_binding_point) {
+            continue;
+        }
+
+        remapper_data.emplace(src_binding_point, plane0_binding_point);
+    }
+
+    // ArrayLengthFromUniformOptions bindpoints may need to be remapped
+    {
+        std::unordered_map<BindingPoint, uint32_t> bindpoint_to_size_index;
+        for (auto& [bindpoint, index] : options.array_length_from_uniform.bindpoint_to_size_index) {
+            auto it = remapper_data.find(bindpoint);
+            if (it != remapper_data.end()) {
+                bindpoint_to_size_index.emplace(it->second, index);
+            } else {
+                bindpoint_to_size_index.emplace(bindpoint, index);
+            }
+        }
+
+        array_length_from_uniform_options.ubo_binding =
+            options.array_length_from_uniform.ubo_binding;
+        array_length_from_uniform_options.bindpoint_to_size_index =
+            std::move(bindpoint_to_size_index);
+    }
+}
+
+}  // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/common/option_helpers.h b/src/tint/lang/hlsl/writer/common/option_helpers.h
new file mode 100644
index 0000000..bcfc083
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/common/option_helpers.h
@@ -0,0 +1,62 @@
+/// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_HLSL_WRITER_COMMON_OPTION_HELPERS_H_
+#define SRC_TINT_LANG_HLSL_WRITER_COMMON_OPTION_HELPERS_H_
+
+#include <unordered_map>
+
+#include "src/tint/api/common/binding_point.h"
+#include "src/tint/api/options/external_texture.h"
+#include "src/tint/lang/hlsl/writer/common/options.h"
+#include "src/tint/utils/diagnostic/diagnostic.h"
+#include "src/tint/utils/result/result.h"
+
+namespace tint::hlsl::writer {
+
+/// The remapper data
+using RemapperData = std::unordered_map<BindingPoint, BindingPoint>;
+
+/// @param options the options
+/// @returns success or failure
+Result<SuccessType> ValidateBindingOptions(const Options& options);
+
+/// Populates binding-related option from the writer options
+/// @param options the writer options
+/// @param remapper_data where to put the remapper data
+/// @param external_texture where to store the external texture options
+/// @param array_length_from_uniform_options where to store the ArrayLengthFromUniform options
+/// Note, these are populated together because there are dependencies between the two types of data.
+void PopulateBindingRelatedOptions(
+    const Options& options,
+    RemapperData& remapper_data,
+    ExternalTextureOptions& external_texture,
+    ArrayLengthFromUniformOptions& array_length_from_uniform_options);
+
+}  // namespace tint::hlsl::writer
+
+#endif  // SRC_TINT_LANG_HLSL_WRITER_COMMON_OPTION_HELPERS_H_
diff --git a/src/tint/lang/hlsl/writer/common/options.h b/src/tint/lang/hlsl/writer/common/options.h
index 50cf766..781ca12 100644
--- a/src/tint/lang/hlsl/writer/common/options.h
+++ b/src/tint/lang/hlsl/writer/common/options.h
@@ -39,10 +39,111 @@
 #include "src/tint/api/options/external_texture.h"
 #include "src/tint/api/options/pixel_local.h"
 #include "src/tint/lang/core/access.h"
+#include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/reflection/reflection.h"
 
 namespace tint::hlsl::writer {
 
+namespace binding {
+
+/// Generic binding point
+struct BindingInfo {
+    /// The group
+    uint32_t group = 0;
+    /// The binding
+    uint32_t binding = 0;
+
+    /// Equality operator
+    /// @param rhs the BindingInfo to compare against
+    /// @returns true if this BindingInfo is equal to `rhs`
+    inline bool operator==(const BindingInfo& rhs) const {
+        return group == rhs.group && binding == rhs.binding;
+    }
+    /// Inequality operator
+    /// @param rhs the BindingInfo to compare against
+    /// @returns true if this BindingInfo is not equal to `rhs`
+    inline bool operator!=(const BindingInfo& rhs) const { return !(*this == rhs); }
+
+    /// @returns the hash code of the BindingInfo
+    tint::HashCode HashCode() const { return Hash(group, binding); }
+
+    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
+    TINT_REFLECT(BindingInfo, group, binding);
+};
+/// Ensure that all the fields of BindingInfo are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(BindingInfo);
+
+using Uniform = BindingInfo;
+using Storage = BindingInfo;
+using Texture = BindingInfo;
+using StorageTexture = BindingInfo;
+using Sampler = BindingInfo;
+
+/// An external texture
+struct ExternalTexture {
+    /// Metadata
+    BindingInfo metadata{};
+    /// Plane0 binding data
+    BindingInfo plane0{};
+    /// Plane1 binding data;
+    BindingInfo plane1{};
+
+    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
+    TINT_REFLECT(ExternalTexture, metadata, plane0, plane1);
+};
+
+/// Ensure that all the fields of ExternalTexture are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(ExternalTexture);
+
+}  // namespace binding
+
+/// Maps the WGSL binding point to the SPIR-V group,binding for uniforms
+using UniformBindings = std::unordered_map<BindingPoint, binding::Uniform>;
+/// Maps the WGSL binding point to the SPIR-V group,binding for storage
+using StorageBindings = std::unordered_map<BindingPoint, binding::Storage>;
+/// Maps the WGSL binding point to the SPIR-V group,binding for textures
+using TextureBindings = std::unordered_map<BindingPoint, binding::Texture>;
+/// Maps the WGSL binding point to the SPIR-V group,binding for storage textures
+using StorageTextureBindings = std::unordered_map<BindingPoint, binding::StorageTexture>;
+/// Maps the WGSL binding point to the SPIR-V group,binding for samplers
+using SamplerBindings = std::unordered_map<BindingPoint, binding::Sampler>;
+/// Maps the WGSL binding point to the plane0, plane1, and metadata for external textures
+using ExternalTextureBindings = std::unordered_map<BindingPoint, binding::ExternalTexture>;
+
+/// Binding information
+struct Bindings {
+    /// Uniform bindings
+    UniformBindings uniform{};
+    /// Storage bindings
+    StorageBindings storage{};
+    /// Texture bindings
+    TextureBindings texture{};
+    /// Storage texture bindings
+    StorageTextureBindings storage_texture{};
+    /// Sampler bindings
+    SamplerBindings sampler{};
+    /// External bindings
+    ExternalTextureBindings external_texture{};
+    /// Mapping of BindingPoint to new Access
+    std::unordered_map<BindingPoint, tint::core::Access> access_controls;
+    /// The binding points that will be ignored by the rebustness transform.
+    std::vector<BindingPoint> ignored_by_robustness_transform;
+
+    /// Reflect the fields of this class so that it can be used by tint::ForeachField()
+    TINT_REFLECT(Bindings,
+                 uniform,
+                 storage,
+                 texture,
+                 storage_texture,
+                 sampler,
+                 external_texture,
+                 access_controls,
+                 ignored_by_robustness_transform);
+};
+
+/// Ensure that all the fields of Bindings are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Bindings);
+
 /// kMaxInterStageLocations == D3D11_PS_INPUT_REGISTER_COUNT - 2
 /// D3D11_PS_INPUT_REGISTER_COUNT == D3D12_PS_INPUT_REGISTER_COUNT
 constexpr uint32_t kMaxInterStageLocations = 30;
@@ -92,23 +193,15 @@
     /// 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;
+    /// The bindings
+    Bindings bindings;
 
     /// Options used to deal with pixel local storage variables
     PixelLocalOptions pixel_local_options = {};
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(disable_robustness,
+    TINT_REFLECT(Options,
+                 disable_robustness,
                  disable_workgroup_init,
                  truncate_interstage_variables,
                  polyfill_reflect_vec2_f32,
@@ -118,13 +211,13 @@
                  array_length_from_uniform,
                  interstage_locations,
                  root_constant_binding_point,
-                 external_texture_options,
-                 binding_remapper_options,
-                 binding_points_ignored_in_robustness_transform,
-                 access_controls,
+                 bindings,
                  pixel_local_options);
 };
 
+/// Ensure that all the fields of Options are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Options);
+
 }  // namespace tint::hlsl::writer
 
 #endif  // SRC_TINT_LANG_HLSL_WRITER_COMMON_OPTIONS_H_
diff --git a/src/tint/lang/hlsl/writer/helpers/BUILD.bazel b/src/tint/lang/hlsl/writer/helpers/BUILD.bazel
new file mode 100644
index 0000000..24a3b69
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/helpers/BUILD.bazel
@@ -0,0 +1,76 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+#    list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+#    contributors may be used to endorse or promote products derived from
+#    this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# 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 = "helpers",
+  srcs = [
+    "generate_bindings.cc",
+  ],
+  hdrs = [
+    "generate_bindings.h",
+  ],
+  deps = [
+    "//src/tint/api/common",
+    "//src/tint/api/options",
+    "//src/tint/lang/core",
+    "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/type",
+    "//src/tint/lang/hlsl/writer/common",
+    "//src/tint/lang/wgsl",
+    "//src/tint/lang/wgsl/ast",
+    "//src/tint/lang/wgsl/features",
+    "//src/tint/lang/wgsl/program",
+    "//src/tint/lang/wgsl/sem",
+    "//src/tint/utils/containers",
+    "//src/tint/utils/diagnostic",
+    "//src/tint/utils/ice",
+    "//src/tint/utils/id",
+    "//src/tint/utils/macros",
+    "//src/tint/utils/math",
+    "//src/tint/utils/memory",
+    "//src/tint/utils/reflection",
+    "//src/tint/utils/result",
+    "//src/tint/utils/rtti",
+    "//src/tint/utils/symbol",
+    "//src/tint/utils/text",
+    "//src/tint/utils/traits",
+  ],
+  copts = COPTS,
+  visibility = ["//visibility:public"],
+)
+
diff --git a/src/tint/lang/hlsl/writer/helpers/BUILD.cmake b/src/tint/lang/hlsl/writer/helpers/BUILD.cmake
new file mode 100644
index 0000000..6332974
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/helpers/BUILD.cmake
@@ -0,0 +1,71 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+#    list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+#    contributors may be used to endorse or promote products derived from
+#    this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+#   tools/src/cmd/gen/build/BUILD.cmake.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+#                       Do not modify this file directly
+################################################################################
+
+################################################################################
+# Target:    tint_lang_hlsl_writer_helpers
+# Kind:      lib
+################################################################################
+tint_add_target(tint_lang_hlsl_writer_helpers lib
+  lang/hlsl/writer/helpers/generate_bindings.cc
+  lang/hlsl/writer/helpers/generate_bindings.h
+)
+
+tint_target_add_dependencies(tint_lang_hlsl_writer_helpers lib
+  tint_api_common
+  tint_api_options
+  tint_lang_core
+  tint_lang_core_constant
+  tint_lang_core_type
+  tint_lang_hlsl_writer_common
+  tint_lang_wgsl
+  tint_lang_wgsl_ast
+  tint_lang_wgsl_features
+  tint_lang_wgsl_program
+  tint_lang_wgsl_sem
+  tint_utils_containers
+  tint_utils_diagnostic
+  tint_utils_ice
+  tint_utils_id
+  tint_utils_macros
+  tint_utils_math
+  tint_utils_memory
+  tint_utils_reflection
+  tint_utils_result
+  tint_utils_rtti
+  tint_utils_symbol
+  tint_utils_text
+  tint_utils_traits
+)
diff --git a/src/tint/lang/hlsl/writer/helpers/BUILD.gn b/src/tint/lang/hlsl/writer/helpers/BUILD.gn
new file mode 100644
index 0000000..8583f77
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/helpers/BUILD.gn
@@ -0,0 +1,72 @@
+# Copyright 2024 The Dawn & Tint Authors
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+#    list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+#    this list of conditions and the following disclaimer in the documentation
+#    and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its
+#    contributors may be used to endorse or promote products derived from
+#    this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+################################################################################
+# File generated by 'tools/src/cmd/gen' using the template:
+#   tools/src/cmd/gen/build/BUILD.gn.tmpl
+#
+# To regenerate run: './tools/run gen'
+#
+#                       Do not modify this file directly
+################################################################################
+
+import("../../../../../../scripts/tint_overrides_with_defaults.gni")
+
+import("${tint_src_dir}/tint.gni")
+
+libtint_source_set("helpers") {
+  sources = [
+    "generate_bindings.cc",
+    "generate_bindings.h",
+  ]
+  deps = [
+    "${tint_src_dir}/api/common",
+    "${tint_src_dir}/api/options",
+    "${tint_src_dir}/lang/core",
+    "${tint_src_dir}/lang/core/constant",
+    "${tint_src_dir}/lang/core/type",
+    "${tint_src_dir}/lang/hlsl/writer/common",
+    "${tint_src_dir}/lang/wgsl",
+    "${tint_src_dir}/lang/wgsl/ast",
+    "${tint_src_dir}/lang/wgsl/features",
+    "${tint_src_dir}/lang/wgsl/program",
+    "${tint_src_dir}/lang/wgsl/sem",
+    "${tint_src_dir}/utils/containers",
+    "${tint_src_dir}/utils/diagnostic",
+    "${tint_src_dir}/utils/ice",
+    "${tint_src_dir}/utils/id",
+    "${tint_src_dir}/utils/macros",
+    "${tint_src_dir}/utils/math",
+    "${tint_src_dir}/utils/memory",
+    "${tint_src_dir}/utils/reflection",
+    "${tint_src_dir}/utils/result",
+    "${tint_src_dir}/utils/rtti",
+    "${tint_src_dir}/utils/symbol",
+    "${tint_src_dir}/utils/text",
+    "${tint_src_dir}/utils/traits",
+  ]
+}
diff --git a/src/tint/lang/hlsl/writer/helpers/generate_bindings.cc b/src/tint/lang/hlsl/writer/helpers/generate_bindings.cc
new file mode 100644
index 0000000..b10d2f6
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/helpers/generate_bindings.cc
@@ -0,0 +1,121 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/hlsl/writer/helpers/generate_bindings.h"
+
+#include <algorithm>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "src/tint/api/common/binding_point.h"
+#include "src/tint/lang/core/type/external_texture.h"
+#include "src/tint/lang/core/type/storage_texture.h"
+#include "src/tint/lang/wgsl/ast/module.h"
+#include "src/tint/lang/wgsl/program/program.h"
+#include "src/tint/lang/wgsl/sem/variable.h"
+#include "src/tint/utils/containers/hashmap.h"
+#include "src/tint/utils/containers/vector.h"
+#include "src/tint/utils/rtti/switch.h"
+
+namespace tint::hlsl::writer {
+
+Bindings GenerateBindings(const Program& program) {
+    // TODO(tint:1491): Use Inspector once we can get binding info for all
+    // variables, not just those referenced by entry points.
+
+    Bindings bindings{};
+
+    // Collect next valid binding number per group
+    Hashmap<uint32_t, uint32_t, 4> group_to_next_binding_number;
+    Vector<tint::BindingPoint, 4> ext_tex_bps;
+    for (auto* var : program.AST().GlobalVariables()) {
+        if (auto* sem_var = program.Sem().Get(var)->As<sem::GlobalVariable>()) {
+            if (auto bp = sem_var->Attributes().binding_point) {
+                if (auto val = group_to_next_binding_number.Get(bp->group)) {
+                    *val = std::max(*val, bp->binding + 1);
+                } else {
+                    group_to_next_binding_number.Add(bp->group, bp->binding + 1);
+                }
+
+                // Store up the external textures, we'll add them in the next step
+                if (sem_var->Type()->UnwrapRef()->Is<core::type::ExternalTexture>()) {
+                    ext_tex_bps.Push(*bp);
+                    continue;
+                }
+
+                binding::BindingInfo info{bp->group, bp->binding};
+                switch (sem_var->AddressSpace()) {
+                    case core::AddressSpace::kHandle:
+                        Switch(
+                            sem_var->Type()->UnwrapRef(),  //
+                            [&](const core::type::Sampler*) {
+                                bindings.sampler.emplace(*bp, info);
+                            },
+                            [&](const core::type::StorageTexture*) {
+                                bindings.storage_texture.emplace(*bp, info);
+                            },
+                            [&](const core::type::Texture*) {
+                                bindings.texture.emplace(*bp, info);
+                            });
+                        break;
+                    case core::AddressSpace::kStorage:
+                        bindings.storage.emplace(*bp, info);
+                        break;
+                    case core::AddressSpace::kUniform:
+                        bindings.uniform.emplace(*bp, info);
+                        break;
+
+                    case core::AddressSpace::kUndefined:
+                    case core::AddressSpace::kPixelLocal:
+                    case core::AddressSpace::kPrivate:
+                    case core::AddressSpace::kPushConstant:
+                    case core::AddressSpace::kIn:
+                    case core::AddressSpace::kOut:
+                    case core::AddressSpace::kFunction:
+                    case core::AddressSpace::kWorkgroup:
+                        break;
+                }
+            }
+        }
+    }
+
+    for (auto bp : ext_tex_bps) {
+        uint32_t g = bp.group;
+        uint32_t& next_num = group_to_next_binding_number.GetOrAddZero(g);
+
+        binding::BindingInfo plane0{bp.group, bp.binding};
+        binding::BindingInfo plane1{g, next_num++};
+        binding::BindingInfo metadata{g, next_num++};
+
+        bindings.external_texture.emplace(bp, binding::ExternalTexture{metadata, plane0, plane1});
+    }
+
+    return bindings;
+}
+
+}  // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/helpers/generate_bindings.h b/src/tint/lang/hlsl/writer/helpers/generate_bindings.h
new file mode 100644
index 0000000..249075a
--- /dev/null
+++ b/src/tint/lang/hlsl/writer/helpers/generate_bindings.h
@@ -0,0 +1,44 @@
+// Copyright 2023 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_HLSL_WRITER_HELPERS_GENERATE_BINDINGS_H_
+#define SRC_TINT_LANG_HLSL_WRITER_HELPERS_GENERATE_BINDINGS_H_
+
+#include "src/tint/lang/hlsl/writer/common/options.h"
+
+// Forward declarations
+namespace tint {
+class Program;
+}
+
+namespace tint::hlsl::writer {
+
+Bindings GenerateBindings(const Program& program);
+
+}  // namespace tint::hlsl::writer
+
+#endif  // SRC_TINT_LANG_HLSL_WRITER_HELPERS_GENERATE_BINDINGS_H_
diff --git a/src/tint/lang/hlsl/writer/writer_bench.cc b/src/tint/lang/hlsl/writer/writer_bench.cc
index 4e9a856..55939cf 100644
--- a/src/tint/lang/hlsl/writer/writer_bench.cc
+++ b/src/tint/lang/hlsl/writer/writer_bench.cc
@@ -36,13 +36,13 @@
 void GenerateHLSL(benchmark::State& state, std::string input_name) {
     auto res = bench::LoadProgram(input_name);
     if (res != Success) {
-        state.SkipWithError(res.Failure().reason.str());
+        state.SkipWithError(res.Failure().reason.Str());
         return;
     }
     for (auto _ : state) {
         auto gen_res = Generate(res->program, {});
         if (gen_res != Success) {
-            state.SkipWithError(gen_res.Failure().reason.str());
+            state.SkipWithError(gen_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 4c987c9..746afae 100644
--- a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
@@ -309,9 +309,9 @@
             },
             [&](const ast::Override*) {
                 // Override is removed with SubstituteOverride
-                diagnostics_.add_error(diag::System::Writer,
-                                       "override-expressions should have been removed with the "
-                                       "SubstituteOverride transform.");
+                diagnostics_.AddError(diag::System::Writer,
+                                      "override-expressions should have been removed with the "
+                                      "SubstituteOverride transform.");
                 return false;
             },
             [&](const ast::Function* func) {
@@ -368,7 +368,7 @@
             return false;
         }
     } else {
-        diagnostics_.add_error(diag::System::Writer, "unknown alias type: " + ty->FriendlyName());
+        diagnostics_.AddError(diag::System::Writer, "unknown alias type: " + ty->FriendlyName());
         return false;
     }
 
@@ -1062,7 +1062,7 @@
             std::vector<const char*> dims;
             switch (texture_type->dim()) {
                 case core::type::TextureDimension::kNone:
-                    diagnostics_.add_error(diag::System::Writer, "texture dimension is kNone");
+                    diagnostics_.AddError(diag::System::Writer, "texture dimension is kNone");
                     return false;
                 case core::type::TextureDimension::k1d:
                     dims = {"width"};
@@ -1263,7 +1263,7 @@
             default: {
                 StringStream err;
                 err << "MSL does not support gradients for " << dim << " textures";
-                diagnostics_.add_error(diag::System::Writer, err.str());
+                diagnostics_.AddError(diag::System::Writer, err.str());
                 return false;
             }
         }
@@ -1619,15 +1619,15 @@
             out += "unpack_unorm2x16_to_float";
             break;
         case wgsl::BuiltinFn::kArrayLength:
-            diagnostics_.add_error(
+            diagnostics_.AddError(
                 diag::System::Writer,
                 "Unable to translate builtin: " + std::string(builtin->str()) +
                     "\nDid you forget to pass array_length_from_uniform generator "
                     "options?");
             return "";
         default:
-            diagnostics_.add_error(diag::System::Writer,
-                                   "Unknown import method: " + std::string(builtin->str()));
+            diagnostics_.AddError(diag::System::Writer,
+                                  "Unknown import method: " + std::string(builtin->str()));
             return "";
     }
     return out;
@@ -1802,8 +1802,8 @@
 
             auto count = a->ConstantCount();
             if (!count) {
-                diagnostics_.add_error(diag::System::Writer,
-                                       core::type::Array::kErrExpectedConstantCount);
+                diagnostics_.AddError(diag::System::Writer,
+                                      core::type::Array::kErrExpectedConstantCount);
                 return false;
             }
 
@@ -1873,7 +1873,7 @@
                     return true;
                 }
             }
-            diagnostics_.add_error(diag::System::Writer, "unknown integer literal suffix type");
+            diagnostics_.AddError(diag::System::Writer, "unknown integer literal suffix type");
             return false;
         },  //
         TINT_ICE_ON_NO_MATCH);
@@ -2069,7 +2069,7 @@
 
                         auto name = BuiltinToAttribute(builtin);
                         if (name.empty()) {
-                            diagnostics_.add_error(diag::System::Writer, "unknown builtin");
+                            diagnostics_.AddError(diag::System::Writer, "unknown builtin");
                             return false;
                         }
                         out << " [[" << name << "]]";
@@ -2526,8 +2526,8 @@
             } else {
                 auto count = arr->ConstantCount();
                 if (!count) {
-                    diagnostics_.add_error(diag::System::Writer,
-                                           core::type::Array::kErrExpectedConstantCount);
+                    diagnostics_.AddError(diag::System::Writer,
+                                          core::type::Array::kErrExpectedConstantCount);
                     return false;
                 }
 
@@ -2615,7 +2615,7 @@
                     out << "cube_array";
                     break;
                 default:
-                    diagnostics_.add_error(diag::System::Writer, "Invalid texture dimensions");
+                    diagnostics_.AddError(diag::System::Writer, "Invalid texture dimensions");
                     return false;
             }
             if (tex->IsAnyOf<core::type::MultisampledTexture,
@@ -2648,8 +2648,8 @@
                     } else if (storage->access() == core::Access::kWrite) {
                         out << ", access::write";
                     } else {
-                        diagnostics_.add_error(diag::System::Writer,
-                                               "Invalid access control for storage texture");
+                        diagnostics_.AddError(diag::System::Writer,
+                                              "Invalid access control for storage texture");
                         return false;
                     }
                     return true;
@@ -2790,7 +2790,7 @@
         if (auto builtin = attributes.builtin) {
             auto name = BuiltinToAttribute(builtin.value());
             if (name.empty()) {
-                diagnostics_.add_error(diag::System::Writer, "unknown builtin");
+                diagnostics_.AddError(diag::System::Writer, "unknown builtin");
                 return false;
             }
             out << " [[" << name << "]]";
@@ -2832,7 +2832,7 @@
         if (auto interpolation = attributes.interpolation) {
             auto name = InterpolationToAttribute(interpolation->type, interpolation->sampling);
             if (name.empty()) {
-                diagnostics_.add_error(diag::System::Writer, "unknown interpolation attribute");
+                diagnostics_.AddError(diag::System::Writer, "unknown interpolation attribute");
                 return false;
             }
             out << " [[" << name << "]]";
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 28a2d3e..ab858e3 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
@@ -39,13 +39,13 @@
 using MslASTPrinterTest = TestHelper;
 
 TEST_F(MslASTPrinterTest, InvalidProgram) {
-    Diagnostics().add_error(diag::System::Writer, "make the program invalid");
+    Diagnostics().AddError(diag::System::Writer, "make the program invalid");
     ASSERT_FALSE(IsValid());
     auto program = resolver::Resolve(*this);
     ASSERT_FALSE(program.IsValid());
     auto result = Generate(program, Options{});
     EXPECT_NE(result, Success);
-    EXPECT_EQ(result.Failure().reason.str(), "error: make the program invalid");
+    EXPECT_EQ(result.Failure().reason.Str(), "error: make the program invalid");
 }
 
 TEST_F(MslASTPrinterTest, UnsupportedExtension) {
@@ -55,7 +55,7 @@
 
     ASSERT_FALSE(gen.Generate());
     EXPECT_EQ(
-        gen.Diagnostics().str(),
+        gen.Diagnostics().Str(),
         R"(12:34 error: MSL backend does not support extension 'chromium_experimental_push_constant')");
 }
 
@@ -173,21 +173,25 @@
     EXPECT_EQ(gen.Result(), R"(#include <metal_stdlib>
 
 using namespace metal;
-struct tint_symbol_3 {
+struct tint_symbol_4 {
   float2x2 m;
 };
 
-void comp_main_inner(uint local_invocation_index, threadgroup float2x2* const tint_symbol) {
+void tint_zero_workgroup_memory(uint local_idx, threadgroup float2x2* const tint_symbol) {
   {
     *(tint_symbol) = float2x2(float2(0.0f), float2(0.0f));
   }
   threadgroup_barrier(mem_flags::mem_threadgroup);
-  float2x2 const x = *(tint_symbol);
 }
 
-kernel void comp_main(threadgroup tint_symbol_3* tint_symbol_2 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
-  threadgroup float2x2* const tint_symbol_1 = &((*(tint_symbol_2)).m);
-  comp_main_inner(local_invocation_index, tint_symbol_1);
+void comp_main_inner(uint local_invocation_index, threadgroup float2x2* const tint_symbol_1) {
+  tint_zero_workgroup_memory(local_invocation_index, tint_symbol_1);
+  float2x2 const x = *(tint_symbol_1);
+}
+
+kernel void comp_main(threadgroup tint_symbol_4* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup float2x2* const tint_symbol_2 = &((*(tint_symbol_3)).m);
+  comp_main_inner(local_invocation_index, tint_symbol_2);
   return;
 }
 
@@ -230,22 +234,26 @@
   volatile bool VOLATILE_NAME = true; \
   if (VOLATILE_NAME)
 
-struct tint_symbol_3 {
+struct tint_symbol_4 {
   tint_array<float2x2, 4> m;
 };
 
-void comp_main_inner(uint local_invocation_index, threadgroup tint_array<float2x2, 4>* const tint_symbol) {
-  TINT_ISOLATE_UB(tint_volatile_true) for(uint idx = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+void tint_zero_workgroup_memory(uint local_idx, threadgroup tint_array<float2x2, 4>* const tint_symbol) {
+  TINT_ISOLATE_UB(tint_volatile_true) for(uint idx = local_idx; (idx < 4u); idx = (idx + 1u)) {
     uint const i = idx;
     (*(tint_symbol))[i] = float2x2(float2(0.0f), float2(0.0f));
   }
   threadgroup_barrier(mem_flags::mem_threadgroup);
-  tint_array<float2x2, 4> const x = *(tint_symbol);
 }
 
-kernel void comp_main(threadgroup tint_symbol_3* tint_symbol_2 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
-  threadgroup tint_array<float2x2, 4>* const tint_symbol_1 = &((*(tint_symbol_2)).m);
-  comp_main_inner(local_invocation_index, tint_symbol_1);
+void comp_main_inner(uint local_invocation_index, threadgroup tint_array<float2x2, 4>* const tint_symbol_1) {
+  tint_zero_workgroup_memory(local_invocation_index, tint_symbol_1);
+  tint_array<float2x2, 4> const x = *(tint_symbol_1);
+}
+
+kernel void comp_main(threadgroup tint_symbol_4* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup tint_array<float2x2, 4>* const tint_symbol_2 = &((*(tint_symbol_3)).m);
+  comp_main_inner(local_invocation_index, tint_symbol_2);
   return;
 }
 
@@ -287,22 +295,26 @@
   S1 s;
 };
 
-struct tint_symbol_4 {
+struct tint_symbol_5 {
   S2 s;
 };
 
-void comp_main_inner(uint local_invocation_index, threadgroup S2* const tint_symbol_1) {
+void tint_zero_workgroup_memory(uint local_idx, threadgroup S2* const tint_symbol_1) {
   {
     S2 const tint_symbol = S2{};
     *(tint_symbol_1) = tint_symbol;
   }
   threadgroup_barrier(mem_flags::mem_threadgroup);
-  S2 const x = *(tint_symbol_1);
 }
 
-kernel void comp_main(threadgroup tint_symbol_4* tint_symbol_3 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
-  threadgroup S2* const tint_symbol_2 = &((*(tint_symbol_3)).s);
-  comp_main_inner(local_invocation_index, tint_symbol_2);
+void comp_main_inner(uint local_invocation_index, threadgroup S2* const tint_symbol_2) {
+  tint_zero_workgroup_memory(local_invocation_index, tint_symbol_2);
+  S2 const x = *(tint_symbol_2);
+}
+
+kernel void comp_main(threadgroup tint_symbol_5* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup S2* const tint_symbol_3 = &((*(tint_symbol_4)).s);
+  comp_main_inner(local_invocation_index, tint_symbol_3);
   return;
 }
 
@@ -366,81 +378,93 @@
     EXPECT_EQ(gen.Result(), R"(#include <metal_stdlib>
 
 using namespace metal;
-struct tint_symbol_7 {
+struct tint_symbol_16 {
   float2x2 m1;
   float2x3 m2;
   float2x4 m3;
 };
 
-struct tint_symbol_15 {
+struct tint_symbol_24 {
   float3x2 m4;
   float3x3 m5;
   float3x4 m6;
 };
 
-struct tint_symbol_23 {
+struct tint_symbol_32 {
   float4x2 m7;
   float4x3 m8;
   float4x4 m9;
 };
 
-void main1_inner(uint local_invocation_index, threadgroup float2x2* const tint_symbol, threadgroup float2x3* const tint_symbol_1, threadgroup float2x4* const tint_symbol_2) {
+void tint_zero_workgroup_memory(uint local_idx, threadgroup float2x2* const tint_symbol, threadgroup float2x3* const tint_symbol_1, threadgroup float2x4* const tint_symbol_2) {
   {
     *(tint_symbol) = float2x2(float2(0.0f), float2(0.0f));
     *(tint_symbol_1) = float2x3(float3(0.0f), float3(0.0f));
     *(tint_symbol_2) = float2x4(float4(0.0f), float4(0.0f));
   }
   threadgroup_barrier(mem_flags::mem_threadgroup);
-  float2x2 const a1 = *(tint_symbol);
-  float2x3 const a2 = *(tint_symbol_1);
-  float2x4 const a3 = *(tint_symbol_2);
 }
 
-kernel void main1(threadgroup tint_symbol_7* tint_symbol_4 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
-  threadgroup float2x2* const tint_symbol_3 = &((*(tint_symbol_4)).m1);
-  threadgroup float2x3* const tint_symbol_5 = &((*(tint_symbol_4)).m2);
-  threadgroup float2x4* const tint_symbol_6 = &((*(tint_symbol_4)).m3);
-  main1_inner(local_invocation_index, tint_symbol_3, tint_symbol_5, tint_symbol_6);
+void tint_zero_workgroup_memory_1(uint local_idx_1, threadgroup float3x2* const tint_symbol_3, threadgroup float3x3* const tint_symbol_4, threadgroup float3x4* const tint_symbol_5) {
+  {
+    *(tint_symbol_3) = float3x2(float2(0.0f), float2(0.0f), float2(0.0f));
+    *(tint_symbol_4) = float3x3(float3(0.0f), float3(0.0f), float3(0.0f));
+    *(tint_symbol_5) = float3x4(float4(0.0f), float4(0.0f), float4(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+}
+
+void tint_zero_workgroup_memory_2(uint local_idx_2, threadgroup float4x2* const tint_symbol_6, threadgroup float4x3* const tint_symbol_7, threadgroup float4x4* const tint_symbol_8) {
+  {
+    *(tint_symbol_6) = float4x2(float2(0.0f), float2(0.0f), float2(0.0f), float2(0.0f));
+    *(tint_symbol_7) = float4x3(float3(0.0f), float3(0.0f), float3(0.0f), float3(0.0f));
+    *(tint_symbol_8) = float4x4(float4(0.0f), float4(0.0f), float4(0.0f), float4(0.0f));
+  }
+  threadgroup_barrier(mem_flags::mem_threadgroup);
+}
+
+void main1_inner(uint local_invocation_index, threadgroup float2x2* const tint_symbol_9, threadgroup float2x3* const tint_symbol_10, threadgroup float2x4* const tint_symbol_11) {
+  tint_zero_workgroup_memory(local_invocation_index, tint_symbol_9, tint_symbol_10, tint_symbol_11);
+  float2x2 const a1 = *(tint_symbol_9);
+  float2x3 const a2 = *(tint_symbol_10);
+  float2x4 const a3 = *(tint_symbol_11);
+}
+
+kernel void main1(threadgroup tint_symbol_16* tint_symbol_13 [[threadgroup(0)]], uint local_invocation_index [[thread_index_in_threadgroup]]) {
+  threadgroup float2x2* const tint_symbol_12 = &((*(tint_symbol_13)).m1);
+  threadgroup float2x3* const tint_symbol_14 = &((*(tint_symbol_13)).m2);
+  threadgroup float2x4* const tint_symbol_15 = &((*(tint_symbol_13)).m3);
+  main1_inner(local_invocation_index, tint_symbol_12, tint_symbol_14, tint_symbol_15);
   return;
 }
 
-void main2_inner(uint local_invocation_index_1, threadgroup float3x2* const tint_symbol_8, threadgroup float3x3* const tint_symbol_9, threadgroup float3x4* const tint_symbol_10) {
-  {
-    *(tint_symbol_8) = float3x2(float2(0.0f), float2(0.0f), float2(0.0f));
-    *(tint_symbol_9) = float3x3(float3(0.0f), float3(0.0f), float3(0.0f));
-    *(tint_symbol_10) = float3x4(float4(0.0f), float4(0.0f), float4(0.0f));
-  }
-  threadgroup_barrier(mem_flags::mem_threadgroup);
-  float3x2 const a1 = *(tint_symbol_8);
-  float3x3 const a2 = *(tint_symbol_9);
-  float3x4 const a3 = *(tint_symbol_10);
+void main2_inner(uint local_invocation_index_1, threadgroup float3x2* const tint_symbol_17, threadgroup float3x3* const tint_symbol_18, threadgroup float3x4* const tint_symbol_19) {
+  tint_zero_workgroup_memory_1(local_invocation_index_1, tint_symbol_17, tint_symbol_18, tint_symbol_19);
+  float3x2 const a1 = *(tint_symbol_17);
+  float3x3 const a2 = *(tint_symbol_18);
+  float3x4 const a3 = *(tint_symbol_19);
 }
 
-kernel void main2(threadgroup tint_symbol_15* tint_symbol_12 [[threadgroup(0)]], uint local_invocation_index_1 [[thread_index_in_threadgroup]]) {
-  threadgroup float3x2* const tint_symbol_11 = &((*(tint_symbol_12)).m4);
-  threadgroup float3x3* const tint_symbol_13 = &((*(tint_symbol_12)).m5);
-  threadgroup float3x4* const tint_symbol_14 = &((*(tint_symbol_12)).m6);
-  main2_inner(local_invocation_index_1, tint_symbol_11, tint_symbol_13, tint_symbol_14);
+kernel void main2(threadgroup tint_symbol_24* tint_symbol_21 [[threadgroup(0)]], uint local_invocation_index_1 [[thread_index_in_threadgroup]]) {
+  threadgroup float3x2* const tint_symbol_20 = &((*(tint_symbol_21)).m4);
+  threadgroup float3x3* const tint_symbol_22 = &((*(tint_symbol_21)).m5);
+  threadgroup float3x4* const tint_symbol_23 = &((*(tint_symbol_21)).m6);
+  main2_inner(local_invocation_index_1, tint_symbol_20, tint_symbol_22, tint_symbol_23);
   return;
 }
 
-void main3_inner(uint local_invocation_index_2, threadgroup float4x2* const tint_symbol_16, threadgroup float4x3* const tint_symbol_17, threadgroup float4x4* const tint_symbol_18) {
-  {
-    *(tint_symbol_16) = float4x2(float2(0.0f), float2(0.0f), float2(0.0f), float2(0.0f));
-    *(tint_symbol_17) = float4x3(float3(0.0f), float3(0.0f), float3(0.0f), float3(0.0f));
-    *(tint_symbol_18) = float4x4(float4(0.0f), float4(0.0f), float4(0.0f), float4(0.0f));
-  }
-  threadgroup_barrier(mem_flags::mem_threadgroup);
-  float4x2 const a1 = *(tint_symbol_16);
-  float4x3 const a2 = *(tint_symbol_17);
-  float4x4 const a3 = *(tint_symbol_18);
+void main3_inner(uint local_invocation_index_2, threadgroup float4x2* const tint_symbol_25, threadgroup float4x3* const tint_symbol_26, threadgroup float4x4* const tint_symbol_27) {
+  tint_zero_workgroup_memory_2(local_invocation_index_2, tint_symbol_25, tint_symbol_26, tint_symbol_27);
+  float4x2 const a1 = *(tint_symbol_25);
+  float4x3 const a2 = *(tint_symbol_26);
+  float4x4 const a3 = *(tint_symbol_27);
 }
 
-kernel void main3(threadgroup tint_symbol_23* tint_symbol_20 [[threadgroup(0)]], uint local_invocation_index_2 [[thread_index_in_threadgroup]]) {
-  threadgroup float4x2* const tint_symbol_19 = &((*(tint_symbol_20)).m7);
-  threadgroup float4x3* const tint_symbol_21 = &((*(tint_symbol_20)).m8);
-  threadgroup float4x4* const tint_symbol_22 = &((*(tint_symbol_20)).m9);
-  main3_inner(local_invocation_index_2, tint_symbol_19, tint_symbol_21, tint_symbol_22);
+kernel void main3(threadgroup tint_symbol_32* tint_symbol_29 [[threadgroup(0)]], uint local_invocation_index_2 [[thread_index_in_threadgroup]]) {
+  threadgroup float4x2* const tint_symbol_28 = &((*(tint_symbol_29)).m7);
+  threadgroup float4x3* const tint_symbol_30 = &((*(tint_symbol_29)).m8);
+  threadgroup float4x4* const tint_symbol_31 = &((*(tint_symbol_29)).m9);
+  main3_inner(local_invocation_index_2, tint_symbol_28, tint_symbol_30, tint_symbol_31);
   return;
 }
 
diff --git a/src/tint/lang/msl/writer/ast_printer/sanitizer_test.cc b/src/tint/lang/msl/writer/ast_printer/sanitizer_test.cc
index 57dc161..4745f0c 100644
--- a/src/tint/lang/msl/writer/ast_printer/sanitizer_test.cc
+++ b/src/tint/lang/msl/writer/ast_printer/sanitizer_test.cc
@@ -296,7 +296,7 @@
     ASTPrinter& gen = SanitizeAndBuild(options);
 
     ASSERT_FALSE(gen.Generate());
-    EXPECT_THAT(gen.Diagnostics().str(), HasSubstr("Unable to translate builtin: arrayLength"));
+    EXPECT_THAT(gen.Diagnostics().Str(), HasSubstr("Unable to translate builtin: arrayLength"));
 }
 
 }  // namespace
diff --git a/src/tint/lang/msl/writer/ast_printer/variable_decl_statement_test.cc b/src/tint/lang/msl/writer/ast_printer/variable_decl_statement_test.cc
index 6bd47d9..ba3a4f2 100644
--- a/src/tint/lang/msl/writer/ast_printer/variable_decl_statement_test.cc
+++ b/src/tint/lang/msl/writer/ast_printer/variable_decl_statement_test.cc
@@ -556,7 +556,7 @@
     gen.IncrementIndent();
 
     ASSERT_TRUE(gen.Generate()) << gen.Diagnostics();
-    EXPECT_THAT(gen.Result(), HasSubstr("threadgroup float tint_symbol_2;\n"));
+    EXPECT_THAT(gen.Result(), HasSubstr("threadgroup float tint_symbol_"));
 }
 
 }  // namespace
diff --git a/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param.cc b/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param.cc
index 8335eac..2dd707d 100644
--- a/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param.cc
+++ b/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param.cc
@@ -200,8 +200,7 @@
                     // Create a function-scope variable that is a pointer to the member.
                     auto* member_ptr = ctx.dst->AddressOf(
                         ctx.dst->MemberAccessor(ctx.dst->Deref(workgroup_param()), member));
-                    auto* local_var = ctx.dst->Let(
-                        new_var_symbol, ctx.dst->ty.ptr<workgroup>(store_type()), member_ptr);
+                    auto* local_var = ctx.dst->Let(new_var_symbol, member_ptr);
                     ctx.InsertFront(func->body->statements, ctx.dst->Decl(local_var));
                     is_pointer = true;
                 } else {
@@ -246,7 +245,7 @@
             case core::AddressSpace::kWorkgroup:
                 break;
             case core::AddressSpace::kPushConstant: {
-                ctx.dst->Diagnostics().add_error(
+                ctx.dst->Diagnostics().AddError(
                     diag::System::Transform,
                     "unhandled module-scope address space (" + tint::ToString(sc) + ")");
                 break;
diff --git a/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param_test.cc b/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param_test.cc
index 3bbb4fe..8a24325 100644
--- a/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param_test.cc
+++ b/src/tint/lang/msl/writer/ast_raise/module_scope_var_to_entry_point_param_test.cc
@@ -1056,7 +1056,7 @@
 
 @compute @workgroup_size(1)
 fn main(@internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_1 : ptr<workgroup, tint_symbol_2>) {
-  let tint_symbol : ptr<workgroup, mat2x2<f32>> = &((*(tint_symbol_1)).m);
+  let tint_symbol = &((*(tint_symbol_1)).m);
   let x = *(tint_symbol);
 }
 )";
@@ -1097,7 +1097,7 @@
 
 @compute @workgroup_size(1)
 fn main(@internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_1 : ptr<workgroup, tint_symbol_2>) {
-  let tint_symbol : ptr<workgroup, array<S2, 4u>> = &((*(tint_symbol_1)).m);
+  let tint_symbol = &((*(tint_symbol_1)).m);
   let x = *(tint_symbol);
 }
 )";
@@ -1138,8 +1138,8 @@
 
 @compute @workgroup_size(1)
 fn main(@internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_1 : ptr<workgroup, tint_symbol_3>) {
-  let tint_symbol : ptr<workgroup, S> = &((*(tint_symbol_1)).a);
-  let tint_symbol_2 : ptr<workgroup, S> = &((*(tint_symbol_1)).b);
+  let tint_symbol = &((*(tint_symbol_1)).a);
+  let tint_symbol_2 = &((*(tint_symbol_1)).b);
   let x = *(tint_symbol);
   let y = *(tint_symbol_2);
 }
@@ -1180,8 +1180,8 @@
 
 @compute @workgroup_size(1)
 fn main(@internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_address_space) tint_symbol_1 : ptr<workgroup, tint_symbol_3>) {
-  let tint_symbol : ptr<workgroup, S> = &((*(tint_symbol_1)).a);
-  let tint_symbol_2 : ptr<workgroup, S> = &((*(tint_symbol_1)).b);
+  let tint_symbol = &((*(tint_symbol_1)).a);
+  let tint_symbol_2 = &((*(tint_symbol_1)).b);
   let x = *(tint_symbol);
   let y = *(tint_symbol_2);
 }
diff --git a/src/tint/lang/msl/writer/ast_raise/pixel_local.cc b/src/tint/lang/msl/writer/ast_raise/pixel_local.cc
index 1d6fb0a..2f2a216 100644
--- a/src/tint/lang/msl/writer/ast_raise/pixel_local.cc
+++ b/src/tint/lang/msl/writer/ast_raise/pixel_local.cc
@@ -257,9 +257,9 @@
     uint32_t AttachmentIndex(uint32_t field_index) {
         auto idx = cfg.attachments.Get(field_index);
         if (TINT_UNLIKELY(!idx)) {
-            b.Diagnostics().add_error(diag::System::Transform,
-                                      "PixelLocal::Config::attachments missing entry for field " +
-                                          std::to_string(field_index));
+            b.Diagnostics().AddError(diag::System::Transform,
+                                     "PixelLocal::Config::attachments missing entry for field " +
+                                         std::to_string(field_index));
             return 0;
         }
         return *idx;
@@ -276,8 +276,8 @@
     auto* cfg = inputs.Get<Config>();
     if (!cfg) {
         ProgramBuilder b;
-        b.Diagnostics().add_error(diag::System::Transform,
-                                  "missing transform data for " + std::string(TypeInfo().name));
+        b.Diagnostics().AddError(diag::System::Transform,
+                                 "missing transform data for " + std::string(TypeInfo().name));
         return resolver::Resolve(b);
     }
 
diff --git a/src/tint/lang/msl/writer/common/option_helpers.cc b/src/tint/lang/msl/writer/common/option_helpers.cc
index b655301..d72d984 100644
--- a/src/tint/lang/msl/writer/common/option_helpers.cc
+++ b/src/tint/lang/msl/writer/common/option_helpers.cc
@@ -57,7 +57,7 @@
                 std::stringstream str;
                 str << "found duplicate WGSL binding point: " << src;
 
-                diagnostics.add_error(diag::System::Writer, str.str());
+                diagnostics.AddError(diag::System::Writer, str.str());
                 return true;
             }
         }
@@ -71,7 +71,7 @@
             if (*binding != dst) {
                 std::stringstream str;
                 str << "found duplicate MSL binding point: [binding: " << src.binding << "]";
-                diagnostics.add_error(diag::System::Writer, str.str());
+                diagnostics.AddError(diag::System::Writer, str.str());
                 return true;
             }
         }
@@ -97,27 +97,27 @@
 
     // Storage and uniform are both [[buffer()]]
     if (!valid(seen_msl_buffer_bindings, options.bindings.uniform)) {
-        diagnostics.add_note(diag::System::Writer, "when processing uniform", {});
+        diagnostics.AddNote(diag::System::Writer, "when processing uniform", {});
         return Failure{std::move(diagnostics)};
     }
     if (!valid(seen_msl_buffer_bindings, options.bindings.storage)) {
-        diagnostics.add_note(diag::System::Writer, "when processing storage", {});
+        diagnostics.AddNote(diag::System::Writer, "when processing storage", {});
         return Failure{std::move(diagnostics)};
     }
 
     // Sampler is [[sampler()]]
     if (!valid(seen_msl_sampler_bindings, options.bindings.sampler)) {
-        diagnostics.add_note(diag::System::Writer, "when processing sampler", {});
+        diagnostics.AddNote(diag::System::Writer, "when processing sampler", {});
         return Failure{std::move(diagnostics)};
     }
 
     // Texture and storage texture are [[texture()]]
     if (!valid(seen_msl_texture_bindings, options.bindings.texture)) {
-        diagnostics.add_note(diag::System::Writer, "when processing texture", {});
+        diagnostics.AddNote(diag::System::Writer, "when processing texture", {});
         return Failure{std::move(diagnostics)};
     }
     if (!valid(seen_msl_texture_bindings, options.bindings.storage_texture)) {
-        diagnostics.add_note(diag::System::Writer, "when processing storage_texture", {});
+        diagnostics.AddNote(diag::System::Writer, "when processing storage_texture", {});
         return Failure{std::move(diagnostics)};
     }
 
@@ -129,22 +129,22 @@
 
         // Validate with the actual source regardless of what the remapper will do
         if (wgsl_seen(src_binding, plane0)) {
-            diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
+            diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
             return Failure{std::move(diagnostics)};
         }
 
         // Plane0 & Plane1 are [[texture()]]
         if (msl_seen(seen_msl_texture_bindings, plane0, src_binding)) {
-            diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
+            diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
             return Failure{std::move(diagnostics)};
         }
         if (msl_seen(seen_msl_texture_bindings, plane1, src_binding)) {
-            diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
+            diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
             return Failure{std::move(diagnostics)};
         }
         // Metadata is [[buffer()]]
         if (msl_seen(seen_msl_buffer_bindings, metadata, src_binding)) {
-            diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
+            diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
             return Failure{std::move(diagnostics)};
         }
     }
@@ -164,7 +164,7 @@
     auto create_remappings = [&remapper_data](const auto& hsh) {
         for (const auto& it : hsh) {
             const BindingPoint& src_binding_point = it.first;
-            const binding::Uniform& dst_binding_point = it.second;
+            const binding::BindingInfo& dst_binding_point = it.second;
 
             // Bindings which go to the same slot in MSL do not need to be re-bound.
             if (src_binding_point.group == 0 &&
@@ -210,19 +210,3 @@
 }
 
 }  // namespace tint::msl::writer
-
-namespace std {
-
-/// Custom std::hash specialization for tint::msl::writer::binding::BindingInfo so
-/// they can be used as keys for std::unordered_map and std::unordered_set.
-template <>
-class hash<tint::msl::writer::binding::BindingInfo> {
-  public:
-    /// @param info the binding to create a hash for
-    /// @return the hash value
-    inline std::size_t operator()(const tint::msl::writer::binding::BindingInfo& info) const {
-        return tint::Hash(info.binding);
-    }
-};
-
-}  // namespace std
diff --git a/src/tint/lang/msl/writer/common/options.h b/src/tint/lang/msl/writer/common/options.h
index 1004293..b1d4ff1 100644
--- a/src/tint/lang/msl/writer/common/options.h
+++ b/src/tint/lang/msl/writer/common/options.h
@@ -52,9 +52,16 @@
     /// @returns true if this BindingInfo is not equal to `rhs`
     inline bool operator!=(const BindingInfo& rhs) const { return !(*this == rhs); }
 
+    /// @returns the hash code of the BindingInfo
+    tint::HashCode HashCode() const { return Hash(binding); }
+
     /// Reflect the fields of this class so taht it can be used by tint::ForeachField()
-    TINT_REFLECT(binding);
+    TINT_REFLECT(BindingInfo, binding);
 };
+
+/// Ensure that all the fields of BindingInfo are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(BindingInfo);
+
 using Uniform = BindingInfo;
 using Storage = BindingInfo;
 using Texture = BindingInfo;
@@ -71,9 +78,12 @@
     BindingInfo plane1{};
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(metadata, plane0, plane1);
+    TINT_REFLECT(ExternalTexture, metadata, plane0, plane1);
 };
 
+/// Ensure that all the fields of ExternalTexture are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(ExternalTexture);
+
 }  // namespace binding
 
 /// Maps the WGSL binding point to the SPIR-V group,binding for uniforms
@@ -105,9 +115,12 @@
     ExternalTextureBindings external_texture{};
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(uniform, storage, texture, storage_texture, sampler, external_texture);
+    TINT_REFLECT(Bindings, uniform, storage, texture, storage_texture, sampler, external_texture);
 };
 
+/// Ensure that all the fields of Bindings are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Bindings);
+
 /// Configuration options used for generating MSL.
 struct Options {
     /// Constructor
@@ -152,7 +165,8 @@
     Bindings bindings;
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(disable_robustness,
+    TINT_REFLECT(Options,
+                 disable_robustness,
                  disable_workgroup_init,
                  emit_vertex_point_size,
                  disable_polyfill_integer_div_mod,
@@ -163,6 +177,9 @@
                  bindings);
 };
 
+/// Ensure that all the fields of Options are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Options);
+
 }  // namespace tint::msl::writer
 
 #endif  // SRC_TINT_LANG_MSL_WRITER_COMMON_OPTIONS_H_
diff --git a/src/tint/lang/msl/writer/printer/helper_test.h b/src/tint/lang/msl/writer/printer/helper_test.h
index 410153b..2af6bb2 100644
--- a/src/tint/lang/msl/writer/printer/helper_test.h
+++ b/src/tint/lang/msl/writer/printer/helper_test.h
@@ -81,13 +81,13 @@
     /// @returns true if generation and validation succeeded
     bool Generate() {
         if (auto raised = Raise(mod, {}); raised != Success) {
-            err_ = raised.Failure().reason.str();
+            err_ = raised.Failure().reason.Str();
             return false;
         }
 
         auto result = Print(mod);
         if (result != Success) {
-            err_ = result.Failure().reason.str();
+            err_ = result.Failure().reason.Str();
             return false;
         }
         output_ = result.Get();
diff --git a/src/tint/lang/msl/writer/writer_bench.cc b/src/tint/lang/msl/writer/writer_bench.cc
index d597dbd..455b501 100644
--- a/src/tint/lang/msl/writer/writer_bench.cc
+++ b/src/tint/lang/msl/writer/writer_bench.cc
@@ -39,7 +39,7 @@
 void GenerateMSL(benchmark::State& state, std::string input_name) {
     auto res = bench::LoadProgram(input_name);
     if (res != Success) {
-        state.SkipWithError(res.Failure().reason.str());
+        state.SkipWithError(res.Failure().reason.Str());
         return;
     }
     auto& program = res->program;
@@ -67,7 +67,7 @@
     for (auto _ : state) {
         auto gen_res = Generate(program, gen_options);
         if (gen_res != Success) {
-            state.SkipWithError(gen_res.Failure().reason.str());
+            state.SkipWithError(gen_res.Failure().reason.Str());
         }
     }
 }
diff --git a/src/tint/lang/spirv/reader/ast_lower/atomics.cc b/src/tint/lang/spirv/reader/ast_lower/atomics.cc
index fa1f371..06e9d43 100644
--- a/src/tint/lang/spirv/reader/ast_lower/atomics.cc
+++ b/src/tint/lang/spirv/reader/ast_lower/atomics.cc
@@ -224,7 +224,7 @@
                 }
                 auto count = arr->ConstantCount();
                 if (!count) {
-                    ctx.dst->Diagnostics().add_error(
+                    ctx.dst->Diagnostics().AddError(
                         diag::System::Transform,
                         "the Atomics transform does not currently support array counts that "
                         "use override values");
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 ad5c82f..d106222 100644
--- a/src/tint/lang/spirv/reader/ast_parser/barrier_test.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/barrier_test.cc
@@ -51,7 +51,7 @@
     auto p = std::make_unique<ASTParser>(test::Assemble(preamble + spirv));
     if (!p->BuildAndParseInternalModule()) {
         ProgramBuilder builder;
-        builder.Diagnostics().add_error(diag::System::Reader, p->error());
+        builder.Diagnostics().AddError(diag::System::Reader, p->error());
         return Program(std::move(builder));
     }
     return p->Program();
@@ -227,7 +227,7 @@
                OpFunctionEnd
   )");
     EXPECT_FALSE(program.IsValid());
-    EXPECT_THAT(program.Diagnostics().str(),
+    EXPECT_THAT(program.Diagnostics().Str(),
                 HasSubstr("unsupported control barrier execution scope"));
 }
 
@@ -245,7 +245,7 @@
                OpFunctionEnd
   )");
     EXPECT_FALSE(program.IsValid());
-    EXPECT_THAT(program.Diagnostics().str(),
+    EXPECT_THAT(program.Diagnostics().Str(),
                 HasSubstr("control barrier semantics requires acquire and release"));
 }
 
@@ -263,7 +263,7 @@
                OpFunctionEnd
   )");
     EXPECT_FALSE(program.IsValid());
-    EXPECT_THAT(program.Diagnostics().str(), HasSubstr("unsupported control barrier semantics"));
+    EXPECT_THAT(program.Diagnostics().Str(), HasSubstr("unsupported control barrier semantics"));
 }
 
 TEST_F(SpirvASTParserTest, ErrWorkgroupBarrierInvalidMemory) {
@@ -281,7 +281,7 @@
                OpFunctionEnd
   )");
     EXPECT_FALSE(program.IsValid());
-    EXPECT_THAT(program.Diagnostics().str(),
+    EXPECT_THAT(program.Diagnostics().Str(),
                 HasSubstr("workgroupBarrier requires workgroup memory scope"));
 }
 
@@ -300,7 +300,7 @@
                OpFunctionEnd
   )");
     EXPECT_FALSE(program.IsValid());
-    EXPECT_THAT(program.Diagnostics().str(),
+    EXPECT_THAT(program.Diagnostics().Str(),
                 HasSubstr("storageBarrier requires workgroup memory scope"));
 }
 
@@ -319,7 +319,7 @@
                OpFunctionEnd
   )");
     EXPECT_FALSE(program.IsValid());
-    EXPECT_THAT(program.Diagnostics().str(),
+    EXPECT_THAT(program.Diagnostics().Str(),
                 HasSubstr("textureBarrier requires workgroup memory scope"));
 }
 
diff --git a/src/tint/lang/spirv/reader/ast_parser/helper_test.cc b/src/tint/lang/spirv/reader/ast_parser/helper_test.cc
index a417c51..5091bbe 100644
--- a/src/tint/lang/spirv/reader/ast_parser/helper_test.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/helper_test.cc
@@ -53,7 +53,7 @@
     writer.Generate();
 
     if (!writer.Diagnostics().empty()) {
-        return "WGSL writer error: " + writer.Diagnostics().str();
+        return "WGSL writer error: " + writer.Diagnostics().Str();
     }
     return writer.Result();
 }
@@ -64,7 +64,7 @@
         writer.EmitStatement(stmt);
     }
     if (!writer.Diagnostics().empty()) {
-        return "WGSL writer error: " + writer.Diagnostics().str();
+        return "WGSL writer error: " + writer.Diagnostics().Str();
     }
     return writer.Result();
 }
@@ -77,14 +77,14 @@
             StringStream out;
             writer.EmitExpression(out, expr);
             if (!writer.Diagnostics().empty()) {
-                return "WGSL writer error: " + writer.Diagnostics().str();
+                return "WGSL writer error: " + writer.Diagnostics().Str();
             }
             return out.str();
         },
         [&](const ast::Statement* stmt) {
             writer.EmitStatement(stmt);
             if (!writer.Diagnostics().empty()) {
-                return "WGSL writer error: " + writer.Diagnostics().str();
+                return "WGSL writer error: " + writer.Diagnostics().Str();
             }
             return writer.Result();
         },
diff --git a/src/tint/lang/spirv/reader/ast_parser/parse.cc b/src/tint/lang/spirv/reader/ast_parser/parse.cc
index c1b6af7..988fc08 100644
--- a/src/tint/lang/spirv/reader/ast_parser/parse.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/parse.cc
@@ -83,7 +83,7 @@
     ProgramBuilder& builder = parser.builder();
     if (!parsed) {
         // TODO(bclayton): Migrate ASTParser to using diagnostics.
-        builder.Diagnostics().add_error(diag::System::Reader, parser.error());
+        builder.Diagnostics().AddError(diag::System::Reader, parser.error());
         return Program(std::move(builder));
     }
 
diff --git a/src/tint/lang/spirv/reader/ast_parser/parse.h b/src/tint/lang/spirv/reader/ast_parser/parse.h
index feb66e3..6c6e845 100644
--- a/src/tint/lang/spirv/reader/ast_parser/parse.h
+++ b/src/tint/lang/spirv/reader/ast_parser/parse.h
@@ -36,7 +36,7 @@
 namespace tint::spirv::reader::ast_parser {
 
 /// Parses the SPIR-V source data, returning the parsed program.
-/// If the source data fails to parse then the returned `program.Diagnostics.contains_errors()` will
+/// If the source data fails to parse then the returned `program.Diagnostics.ContainsErrors()` will
 /// be true, and the `program.Diagnostics()` will describe the error.
 /// @param input the source data
 /// @param options the parser options
diff --git a/src/tint/lang/spirv/reader/ast_parser/parser_test.cc b/src/tint/lang/spirv/reader/ast_parser/parser_test.cc
index 5805440..a0fc6b1 100644
--- a/src/tint/lang/spirv/reader/ast_parser/parser_test.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/parser_test.cc
@@ -39,7 +39,7 @@
 TEST_F(ParserTest, DataEmpty) {
     std::vector<uint32_t> data;
     auto program = Parse(data, {});
-    auto errs = program.Diagnostics().str();
+    auto errs = program.Diagnostics().Str();
     ASSERT_FALSE(program.IsValid()) << errs;
     EXPECT_EQ(errs, "error: line:0: Invalid SPIR-V magic number.");
 }
@@ -76,7 +76,7 @@
     Options options;
     options.allow_non_uniform_derivatives = false;
     auto program = Parse(spv, options);
-    auto errs = program.Diagnostics().str();
+    auto errs = program.Diagnostics().Str();
     EXPECT_FALSE(program.IsValid()) << errs;
     EXPECT_THAT(errs, ::testing::HasSubstr("'dpdx' must only be called from uniform control flow"));
 }
@@ -86,9 +86,9 @@
     Options options;
     options.allow_non_uniform_derivatives = true;
     auto program = Parse(spv, options);
-    auto errs = program.Diagnostics().str();
+    auto errs = program.Diagnostics().Str();
     EXPECT_TRUE(program.IsValid()) << errs;
-    EXPECT_EQ(program.Diagnostics().count(), 0u) << errs;
+    EXPECT_EQ(program.Diagnostics().Count(), 0u) << errs;
 }
 
 TEST_F(ParserTest, WorkgroupIdGuardingBarrier) {
@@ -123,9 +123,9 @@
                OpFunctionEnd
 )");
     auto program = Parse(spv, {});
-    auto errs = program.Diagnostics().str();
+    auto errs = program.Diagnostics().Str();
     EXPECT_TRUE(program.IsValid()) << errs;
-    EXPECT_EQ(program.Diagnostics().count(), 0u) << errs;
+    EXPECT_EQ(program.Diagnostics().Count(), 0u) << errs;
 }
 
 // TODO(dneto): uint32 vec, valid SPIR-V
diff --git a/src/tint/lang/spirv/reader/ast_parser/type.cc b/src/tint/lang/spirv/reader/ast_parser/type.cc
index 2c29979..5c62f29 100644
--- a/src/tint/lang/spirv/reader/ast_parser/type.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/type.cc
@@ -70,55 +70,57 @@
 namespace {
 
 struct PointerHasher {
-    size_t operator()(const Pointer& t) const { return Hash(t.address_space, t.type, t.access); }
+    HashCode operator()(const Pointer& t) const { return Hash(t.address_space, t.type, t.access); }
 };
 
 struct ReferenceHasher {
-    size_t operator()(const Reference& t) const { return Hash(t.address_space, t.type, t.access); }
+    HashCode operator()(const Reference& t) const {
+        return Hash(t.address_space, t.type, t.access);
+    }
 };
 
 struct VectorHasher {
-    size_t operator()(const Vector& t) const { return Hash(t.type, t.size); }
+    HashCode operator()(const Vector& t) const { return Hash(t.type, t.size); }
 };
 
 struct MatrixHasher {
-    size_t operator()(const Matrix& t) const { return Hash(t.type, t.columns, t.rows); }
+    HashCode operator()(const Matrix& t) const { return Hash(t.type, t.columns, t.rows); }
 };
 
 struct ArrayHasher {
-    size_t operator()(const Array& t) const { return Hash(t.type, t.size, t.stride); }
+    HashCode operator()(const Array& t) const { return Hash(t.type, t.size, t.stride); }
 };
 
 struct AliasHasher {
-    size_t operator()(const Alias& t) const { return Hash(t.name); }
+    HashCode operator()(const Alias& t) const { return Hash(t.name); }
 };
 
 struct StructHasher {
-    size_t operator()(const Struct& t) const { return Hash(t.name); }
+    HashCode operator()(const Struct& t) const { return Hash(t.name); }
 };
 
 struct SamplerHasher {
-    size_t operator()(const Sampler& s) const { return Hash(s.kind); }
+    HashCode operator()(const Sampler& s) const { return Hash(s.kind); }
 };
 
 struct DepthTextureHasher {
-    size_t operator()(const DepthTexture& t) const { return Hash(t.dims); }
+    HashCode operator()(const DepthTexture& t) const { return Hash(t.dims); }
 };
 
 struct DepthMultisampledTextureHasher {
-    size_t operator()(const DepthMultisampledTexture& t) const { return Hash(t.dims); }
+    HashCode operator()(const DepthMultisampledTexture& t) const { return Hash(t.dims); }
 };
 
 struct MultisampledTextureHasher {
-    size_t operator()(const MultisampledTexture& t) const { return Hash(t.dims, t.type); }
+    HashCode operator()(const MultisampledTexture& t) const { return Hash(t.dims, t.type); }
 };
 
 struct SampledTextureHasher {
-    size_t operator()(const SampledTexture& t) const { return Hash(t.dims, t.type); }
+    HashCode operator()(const SampledTexture& t) const { return Hash(t.dims, t.type); }
 };
 
 struct StorageTextureHasher {
-    size_t operator()(const StorageTexture& t) const { return Hash(t.dims, t.format, t.access); }
+    HashCode operator()(const StorageTexture& t) const { return Hash(t.dims, t.format, t.access); }
 };
 }  // namespace
 
diff --git a/src/tint/lang/spirv/reader/parser/helper_test.h b/src/tint/lang/spirv/reader/parser/helper_test.h
index c7fc02a..6842aee 100644
--- a/src/tint/lang/spirv/reader/parser/helper_test.h
+++ b/src/tint/lang/spirv/reader/parser/helper_test.h
@@ -47,7 +47,7 @@
 #define EXPECT_IR(asm, ir)                                           \
     do {                                                             \
         auto result = Run(asm);                                      \
-        ASSERT_EQ(result, Success) << result.Failure().reason.str(); \
+        ASSERT_EQ(result, Success) << result.Failure().reason.Str(); \
         auto got = "\n" + result.Get();                              \
         ASSERT_THAT(got, testing::HasSubstr(ir)) << got;             \
     } while (false)
diff --git a/src/tint/lang/spirv/reader/parser/parser.cc b/src/tint/lang/spirv/reader/parser/parser.cc
index 1976c38..6023194 100644
--- a/src/tint/lang/spirv/reader/parser/parser.cc
+++ b/src/tint/lang/spirv/reader/parser/parser.cc
@@ -669,14 +669,8 @@
             return type == other.type && access_mode == other.access_mode;
         }
 
-        /// Hasher provides a hash function for the TypeKey.
-        struct Hasher {
-            /// @param tk the TypeKey to create a hash for
-            /// @return the hash value
-            inline std::size_t operator()(const TypeKey& tk) const {
-                return HashCombine(Hash(tk.type), tk.access_mode);
-            }
-        };
+        /// @returns the hash code of the TypeKey
+        tint::HashCode HashCode() const { return Hash(type, access_mode); }
     };
 
     /// The generated IR module.
@@ -691,7 +685,7 @@
     /// The Tint IR block that is currently being emitted.
     core::ir::Block* current_block_ = nullptr;
     /// A map from a SPIR-V type declaration to the corresponding Tint type object.
-    Hashmap<TypeKey, const core::type::Type*, 16, TypeKey::Hasher> types_;
+    Hashmap<TypeKey, const core::type::Type*, 16> types_;
     /// A map from a SPIR-V function definition result ID to the corresponding Tint function object.
     Hashmap<uint32_t, core::ir::Function*, 8> functions_;
     /// A map from a SPIR-V result ID to the corresponding Tint value object.
diff --git a/src/tint/lang/spirv/reader/reader.h b/src/tint/lang/spirv/reader/reader.h
index 9bcd99e..e67f6a7 100644
--- a/src/tint/lang/spirv/reader/reader.h
+++ b/src/tint/lang/spirv/reader/reader.h
@@ -49,7 +49,7 @@
 
 /// Reads the SPIR-V source data, returning the parsed program.
 /// If the source data fails to parse then the returned
-/// `program.Diagnostics.contains_errors()` will be true, and the
+/// `program.Diagnostics.ContainsErrors()` will be true, and the
 /// `program.Diagnostics()` will describe the error.
 /// @param input the source data
 /// @param options the parser options
diff --git a/src/tint/lang/spirv/reader/reader_test.cc b/src/tint/lang/spirv/reader/reader_test.cc
index 5313aaf..40c07da 100644
--- a/src/tint/lang/spirv/reader/reader_test.cc
+++ b/src/tint/lang/spirv/reader/reader_test.cc
@@ -83,7 +83,7 @@
                OpFunctionEnd
 )");
     ASSERT_NE(got, Success);
-    EXPECT_EQ(got.Failure().reason.str(),
+    EXPECT_EQ(got.Failure().reason.Str(),
               "error: SPIR-V extension 'SPV_KHR_variable_pointers' is not supported");
 }
 
diff --git a/src/tint/lang/spirv/type/sampled_image.cc b/src/tint/lang/spirv/type/sampled_image.cc
index b8f2c40..7d09f21 100644
--- a/src/tint/lang/spirv/type/sampled_image.cc
+++ b/src/tint/lang/spirv/type/sampled_image.cc
@@ -34,7 +34,7 @@
 namespace tint::spirv::type {
 
 SampledImage::SampledImage(const core::type::Type* image)
-    : Base(static_cast<size_t>(Hash(tint::TypeInfo::Of<SampledImage>().full_hashcode, image)),
+    : Base(static_cast<size_t>(Hash(tint::TypeCode::Of<SampledImage>().bits, image)),
            core::type::Flags{}),
       image_(image) {}
 
diff --git a/src/tint/lang/spirv/validate/validate_test.cc b/src/tint/lang/spirv/validate/validate_test.cc
index 270f065..70021b4 100644
--- a/src/tint/lang/spirv/validate/validate_test.cc
+++ b/src/tint/lang/spirv/validate/validate_test.cc
@@ -70,7 +70,7 @@
     };
     auto res = Validate(spirv, SPV_ENV_VULKAN_1_3);
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(), R"(spirv error: SPIR-V failed validation.
+    EXPECT_EQ(res.Failure().reason.Str(), R"(spirv error: SPIR-V failed validation.
 
 Disassembly:
 ; SPIR-V
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 346f46d..d76a591 100644
--- a/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/ast_printer.cc
@@ -109,10 +109,7 @@
     RemapperData remapper_data{};
     PopulateRemapperAndMultiplanarOptions(options, remapper_data, external_texture_options);
 
-    // BindingRemapper must come before MultiplanarExternalTexture. Note, this is flipped to the
-    // other generators which run Multiplanar first and then binding remapper.
     manager.Add<ast::transform::BindingRemapper>();
-
     data.Add<ast::transform::BindingRemapper::Remappings>(
         remapper_data, std::unordered_map<BindingPoint, core::Access>{},
         /* allow_collisions */ 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 bf096b9..ad5f484 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
@@ -34,13 +34,13 @@
 using SpirvASTPrinterTest = TestHelper;
 
 TEST_F(SpirvASTPrinterTest, InvalidProgram) {
-    Diagnostics().add_error(diag::System::Writer, "make the program invalid");
+    Diagnostics().AddError(diag::System::Writer, "make the program invalid");
     ASSERT_FALSE(IsValid());
     auto program = resolver::Resolve(*this);
     ASSERT_FALSE(program.IsValid());
     auto result = Generate(program, Options{});
     EXPECT_NE(result, Success);
-    EXPECT_EQ(result.Failure().reason.str(), "error: make the program invalid");
+    EXPECT_EQ(result.Failure().reason.Str(), "error: make the program invalid");
 }
 
 TEST_F(SpirvASTPrinterTest, UnsupportedExtension) {
@@ -50,7 +50,7 @@
     auto result = Generate(program, Options{});
     EXPECT_NE(result, Success);
     EXPECT_EQ(
-        result.Failure().reason.str(),
+        result.Failure().reason.Str(),
         R"(12:34 error: SPIR-V backend does not support extension 'chromium_internal_relaxed_uniform_layout')");
 }
 
diff --git a/src/tint/lang/spirv/writer/ast_printer/builder.cc b/src/tint/lang/spirv/writer/ast_printer/builder.cc
index bcd175e..eb393ca 100644
--- a/src/tint/lang/spirv/writer/ast_printer/builder.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/builder.cc
@@ -622,7 +622,7 @@
 }
 
 uint32_t Builder::GenerateFunctionTypeIfNeeded(const sem::Function* func) {
-    return tint::GetOrAdd(func_sig_to_id_, func->Signature(), [&]() -> uint32_t {
+    return func_sig_to_id_.GetOrAdd(func->Signature(), [&]() -> uint32_t {
         auto func_op = result_op();
         auto func_type_id = std::get<uint32_t>(func_op);
 
diff --git a/src/tint/lang/spirv/writer/ast_printer/builder.h b/src/tint/lang/spirv/writer/ast_printer/builder.h
index 21df95e..1e39a34 100644
--- a/src/tint/lang/spirv/writer/ast_printer/builder.h
+++ b/src/tint/lang/spirv/writer/ast_printer/builder.h
@@ -111,7 +111,7 @@
     const diag::List& Diagnostics() const { return builder_.Diagnostics(); }
 
     /// @returns true if the builder encountered an error
-    bool has_error() const { return Diagnostics().contains_errors(); }
+    bool has_error() const { return Diagnostics().ContainsErrors(); }
 
     /// @returns the module that this builder has produced
     writer::Module& Module() { return module_; }
@@ -549,7 +549,7 @@
     std::unordered_map<uint32_t, const sem::Variable*> id_to_var_;
     std::unordered_map<std::string, uint32_t> import_name_to_id_;
     std::unordered_map<Symbol, uint32_t> func_symbol_to_id_;
-    std::unordered_map<sem::CallTargetSignature, uint32_t> func_sig_to_id_;
+    Hashmap<sem::CallTargetSignature, uint32_t, 4> func_sig_to_id_;
     std::unordered_map<const core::type::Type*, uint32_t> type_to_id_;
     std::unordered_map<ScalarConstant, uint32_t> const_to_id_;
     std::unordered_map<const core::type::Type*, uint32_t> const_null_to_id_;
diff --git a/src/tint/lang/spirv/writer/common/helper_test.h b/src/tint/lang/spirv/writer/common/helper_test.h
index 1c08ab9..553b173 100644
--- a/src/tint/lang/spirv/writer/common/helper_test.h
+++ b/src/tint/lang/spirv/writer/common/helper_test.h
@@ -117,13 +117,13 @@
     bool Generate(Options options = {}, bool zero_init_workgroup_memory = false) {
         auto raised = Raise(mod, options);
         if (raised != Success) {
-            err_ = raised.Failure().reason.str();
+            err_ = raised.Failure().reason.Str();
             return false;
         }
 
         auto spirv = PrintModule(mod, zero_init_workgroup_memory);
         if (spirv != Success) {
-            err_ = spirv.Failure().reason.str();
+            err_ = spirv.Failure().reason.Str();
             return false;
         }
 
diff --git a/src/tint/lang/spirv/writer/common/option_helper.cc b/src/tint/lang/spirv/writer/common/option_helper.cc
index c1a9d10..37f2377 100644
--- a/src/tint/lang/spirv/writer/common/option_helper.cc
+++ b/src/tint/lang/spirv/writer/common/option_helper.cc
@@ -51,7 +51,7 @@
                 std::stringstream str;
                 str << "found duplicate WGSL binding point: " << src;
 
-                diagnostics.add_error(diag::System::Writer, str.str());
+                diagnostics.AddError(diag::System::Writer, str.str());
                 return true;
             }
         }
@@ -66,7 +66,7 @@
                 std::stringstream str;
                 str << "found duplicate SPIR-V binding point: [group: " << src.group
                     << ", binding: " << src.binding << "]";
-                diagnostics.add_error(diag::System::Writer, str.str());
+                diagnostics.AddError(diag::System::Writer, str.str());
                 return true;
             }
         }
@@ -91,23 +91,23 @@
     };
 
     if (!valid(options.bindings.uniform)) {
-        diagnostics.add_note(diag::System::Writer, "when processing uniform", {});
+        diagnostics.AddNote(diag::System::Writer, "when processing uniform", {});
         return Failure{std::move(diagnostics)};
     }
     if (!valid(options.bindings.storage)) {
-        diagnostics.add_note(diag::System::Writer, "when processing storage", {});
+        diagnostics.AddNote(diag::System::Writer, "when processing storage", {});
         return Failure{std::move(diagnostics)};
     }
     if (!valid(options.bindings.texture)) {
-        diagnostics.add_note(diag::System::Writer, "when processing texture", {});
+        diagnostics.AddNote(diag::System::Writer, "when processing texture", {});
         return Failure{std::move(diagnostics)};
     }
     if (!valid(options.bindings.storage_texture)) {
-        diagnostics.add_note(diag::System::Writer, "when processing storage_texture", {});
+        diagnostics.AddNote(diag::System::Writer, "when processing storage_texture", {});
         return Failure{std::move(diagnostics)};
     }
     if (!valid(options.bindings.sampler)) {
-        diagnostics.add_note(diag::System::Writer, "when processing sampler", {});
+        diagnostics.AddNote(diag::System::Writer, "when processing sampler", {});
         return Failure{std::move(diagnostics)};
     }
 
@@ -119,20 +119,20 @@
 
         // Validate with the actual source regardless of what the remapper will do
         if (wgsl_seen(src_binding, plane0)) {
-            diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
+            diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
             return Failure{std::move(diagnostics)};
         }
 
         if (spirv_seen(plane0, src_binding)) {
-            diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
+            diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
             return Failure{std::move(diagnostics)};
         }
         if (spirv_seen(plane1, src_binding)) {
-            diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
+            diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
             return Failure{std::move(diagnostics)};
         }
         if (spirv_seen(metadata, src_binding)) {
-            diagnostics.add_note(diag::System::Writer, "when processing external_texture", {});
+            diagnostics.AddNote(diag::System::Writer, "when processing external_texture", {});
             return Failure{std::move(diagnostics)};
         }
     }
@@ -187,7 +187,7 @@
     auto create_remappings = [&remapper_data](const auto& hsh) {
         for (const auto& it : hsh) {
             const BindingPoint& src_binding_point = it.first;
-            const binding::Uniform& dst_binding_point = it.second;
+            const binding::BindingInfo& dst_binding_point = it.second;
 
             // Bindings which go to the same slot in SPIR-V do not need to be re-bound.
             if (src_binding_point.group == dst_binding_point.group &&
@@ -233,19 +233,3 @@
 }
 
 }  // namespace tint::spirv::writer
-
-namespace std {
-
-/// Custom std::hash specialization for tint::spirv::writer::binding::BindingInfo so
-/// they can be used as keys for std::unordered_map and std::unordered_set.
-template <>
-class hash<tint::spirv::writer::binding::BindingInfo> {
-  public:
-    /// @param info the binding to create a hash for
-    /// @return the hash value
-    inline std::size_t operator()(const tint::spirv::writer::binding::BindingInfo& info) const {
-        return tint::Hash(info.group, info.binding);
-    }
-};
-
-}  // namespace std
diff --git a/src/tint/lang/spirv/writer/common/options.h b/src/tint/lang/spirv/writer/common/options.h
index 494369c..e16b267 100644
--- a/src/tint/lang/spirv/writer/common/options.h
+++ b/src/tint/lang/spirv/writer/common/options.h
@@ -54,9 +54,16 @@
     /// @returns true if this BindingInfo is not equal to `rhs`
     inline bool operator!=(const BindingInfo& rhs) const { return !(*this == rhs); }
 
+    /// @returns the hash code of the BindingInfo
+    tint::HashCode HashCode() const { return Hash(group, binding); }
+
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(group, binding);
+    TINT_REFLECT(BindingInfo, group, binding);
 };
+
+/// Ensure that all the fields of BindingInfo are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(BindingInfo);
+
 using Uniform = BindingInfo;
 using Storage = BindingInfo;
 using Texture = BindingInfo;
@@ -73,9 +80,12 @@
     BindingInfo plane1{};
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(metadata, plane0, plane1);
+    TINT_REFLECT(ExternalTexture, metadata, plane0, plane1);
 };
 
+/// Ensure that all the fields of ExternalTexture are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(ExternalTexture);
+
 }  // namespace binding
 
 // Maps the WGSL binding point to the SPIR-V group,binding for uniforms
@@ -107,9 +117,12 @@
     ExternalTextureBindings external_texture{};
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(uniform, storage, texture, storage_texture, sampler, external_texture);
+    TINT_REFLECT(Bindings, uniform, storage, texture, storage_texture, sampler, external_texture);
 };
 
+/// Ensure that all the fields of Bindings are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Bindings);
+
 /// Configuration options used for generating SPIR-V.
 struct Options {
     /// Set to `true` to disable software robustness that prevents out-of-bounds accesses.
@@ -153,7 +166,8 @@
     Bindings bindings;
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(disable_robustness,
+    TINT_REFLECT(Options,
+                 disable_robustness,
                  disable_image_robustness,
                  disable_runtime_sized_array_index_clamping,
                  disable_workgroup_init,
@@ -167,6 +181,9 @@
                  bindings);
 };
 
+/// Ensure that all the fields of Options are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Options);
+
 }  // namespace tint::spirv::writer
 
 #endif  // SRC_TINT_LANG_SPIRV_WRITER_COMMON_OPTIONS_H_
diff --git a/src/tint/lang/spirv/writer/printer/printer.cc b/src/tint/lang/spirv/writer/printer/printer.cc
index 9f243f4..ef41faf 100644
--- a/src/tint/lang/spirv/writer/printer/printer.cc
+++ b/src/tint/lang/spirv/writer/printer/printer.cc
@@ -225,18 +225,14 @@
         uint32_t return_type_id;
         Vector<uint32_t, 4> param_type_ids;
 
-        /// Hasher provides a hash function for the FunctionType.
-        struct Hasher {
-            /// @param ft the FunctionType to create a hash for
-            /// @return the hash value
-            inline std::size_t operator()(const FunctionType& ft) const {
-                size_t hash = Hash(ft.return_type_id);
-                for (auto& p : ft.param_type_ids) {
-                    hash = HashCombine(hash, p);
-                }
-                return hash;
+        /// @returns the hash code of the FunctionType
+        tint::HashCode HashCode() const {
+            auto hash = Hash(return_type_id);
+            for (auto& p : param_type_ids) {
+                hash = HashCombine(hash, p);
             }
-        };
+            return hash;
+        }
 
         /// Equality operator for FunctionType.
         bool operator==(const FunctionType& other) const {
@@ -249,7 +245,7 @@
     Hashmap<const core::type::Type*, uint32_t, 8> types_;
 
     /// The map of function types to their result IDs.
-    Hashmap<FunctionType, uint32_t, 8, FunctionType::Hasher> function_types_;
+    Hashmap<FunctionType, uint32_t, 8> function_types_;
 
     /// The map of constants to their result IDs.
     Hashmap<const core::constant::Value*, uint32_t, 16> constants_;
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 19037f7..cd41b6e 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
@@ -65,12 +65,8 @@
     // The list of constant indices to get from the base to the source object.
     Vector<core::ir::Value*, 4> indices;
 
-    // A specialization of Hasher for PartialAccess.
-    struct Hasher {
-        inline std::size_t operator()(const PartialAccess& src) const {
-            return Hash(src.base, src.indices);
-        }
-    };
+    /// @returns the hash code of the PartialAccess
+    tint::HashCode HashCode() const { return Hash(base, indices); }
 
     // An equality helper for PartialAccess.
     bool operator==(const PartialAccess& other) const {
@@ -139,7 +135,7 @@
 
     // Replace each access instruction that we recorded.
     Hashmap<core::ir::Value*, core::ir::Value*, 4> object_to_local;
-    Hashmap<PartialAccess, core::ir::Value*, 4, PartialAccess::Hasher> source_object_to_value;
+    Hashmap<PartialAccess, core::ir::Value*, 4> source_object_to_value;
     for (const auto& to_replace : worklist) {
         auto* access = to_replace.access;
         auto* source_object = access->Object();
diff --git a/src/tint/lang/spirv/writer/writer_bench.cc b/src/tint/lang/spirv/writer/writer_bench.cc
index 84beb72..fca650a 100644
--- a/src/tint/lang/spirv/writer/writer_bench.cc
+++ b/src/tint/lang/spirv/writer/writer_bench.cc
@@ -40,13 +40,13 @@
 void GenerateSPIRV(benchmark::State& state, std::string input_name) {
     auto res = bench::LoadProgram(input_name);
     if (res != Success) {
-        state.SkipWithError(res.Failure().reason.str());
+        state.SkipWithError(res.Failure().reason.Str());
         return;
     }
     for (auto _ : state) {
         auto gen_res = Generate(res->program, {});
         if (gen_res != Success) {
-            state.SkipWithError(gen_res.Failure().reason.str());
+            state.SkipWithError(gen_res.Failure().reason.Str());
         }
     }
 }
@@ -55,20 +55,20 @@
 #if TINT_BUILD_WGSL_READER
     auto res = bench::LoadProgram(input_name);
     if (res != Success) {
-        state.SkipWithError(res.Failure().reason.str());
+        state.SkipWithError(res.Failure().reason.Str());
         return;
     }
     for (auto _ : state) {
         // Convert the AST program to an IR module.
         auto ir = tint::wgsl::reader::ProgramToLoweredIR(res->program);
         if (ir != Success) {
-            state.SkipWithError(ir.Failure().reason.str());
+            state.SkipWithError(ir.Failure().reason.Str());
             return;
         }
 
         auto gen_res = Generate(ir.Get(), {});
         if (gen_res != Success) {
-            state.SkipWithError(gen_res.Failure().reason.str());
+            state.SkipWithError(gen_res.Failure().reason.Str());
         }
     }
 #else
diff --git a/src/tint/lang/wgsl/ast/builder.cc b/src/tint/lang/wgsl/ast/builder.cc
index 9482ecc..f1640f1 100644
--- a/src/tint/lang/wgsl/ast/builder.cc
+++ b/src/tint/lang/wgsl/ast/builder.cc
@@ -66,7 +66,7 @@
 }
 
 bool Builder::IsValid() const {
-    return !diagnostics_.contains_errors();
+    return !diagnostics_.ContainsErrors();
 }
 
 void Builder::MarkAsMoved() {
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 27b354c..fa6bc9e 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
@@ -82,7 +82,7 @@
     ApplyResult Run() {
         auto* cfg = inputs.Get<Config>();
         if (cfg == nullptr) {
-            b.Diagnostics().add_error(
+            b.Diagnostics().AddError(
                 diag::System::Transform,
                 "missing transform data for " +
                     std::string(tint::TypeInfo::Of<ArrayLengthFromUniform>().name));
diff --git a/src/tint/lang/wgsl/ast/transform/binding_remapper.cc b/src/tint/lang/wgsl/ast/transform/binding_remapper.cc
index 842e9ce..c3c8cbe 100644
--- a/src/tint/lang/wgsl/ast/transform/binding_remapper.cc
+++ b/src/tint/lang/wgsl/ast/transform/binding_remapper.cc
@@ -66,8 +66,8 @@
 
     auto* remappings = inputs.Get<Remappings>();
     if (!remappings) {
-        b.Diagnostics().add_error(diag::System::Transform,
-                                  "missing transform data for " + std::string(TypeInfo().name));
+        b.Diagnostics().AddError(diag::System::Transform,
+                                 "missing transform data for " + std::string(TypeInfo().name));
         return resolver::Resolve(b);
     }
 
@@ -112,15 +112,15 @@
             if (ac_it != remappings->access_controls.end()) {
                 core::Access access = ac_it->second;
                 if (access == core::Access::kUndefined) {
-                    b.Diagnostics().add_error(diag::System::Transform,
-                                              "invalid access mode (" +
-                                                  std::to_string(static_cast<uint32_t>(access)) +
-                                                  ")");
+                    b.Diagnostics().AddError(diag::System::Transform,
+                                             "invalid access mode (" +
+                                                 std::to_string(static_cast<uint32_t>(access)) +
+                                                 ")");
                     return resolver::Resolve(b);
                 }
                 auto* sem = src.Sem().Get(var);
                 if (sem->AddressSpace() != core::AddressSpace::kStorage) {
-                    b.Diagnostics().add_error(
+                    b.Diagnostics().AddError(
                         diag::System::Transform,
                         "cannot apply access control to variable with address space " +
                             std::string(tint::ToString(sem->AddressSpace())));
diff --git a/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc b/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc
index dcea861..842e41b 100644
--- a/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc
+++ b/src/tint/lang/wgsl/ast/transform/canonicalize_entry_point_io.cc
@@ -950,8 +950,8 @@
 
     auto* cfg = inputs.Get<Config>();
     if (cfg == nullptr) {
-        b.Diagnostics().add_error(diag::System::Transform,
-                                  "missing transform data for " + std::string(TypeInfo().name));
+        b.Diagnostics().AddError(diag::System::Transform,
+                                 "missing transform data for " + std::string(TypeInfo().name));
         return resolver::Resolve(b);
     }
 
diff --git a/src/tint/lang/wgsl/ast/transform/direct_variable_access.cc b/src/tint/lang/wgsl/ast/transform/direct_variable_access.cc
index 7cdee65..d92bfb0 100644
--- a/src/tint/lang/wgsl/ast/transform/direct_variable_access.cc
+++ b/src/tint/lang/wgsl/ast/transform/direct_variable_access.cc
@@ -73,7 +73,7 @@
     tint::core::AddressSpace address_space = tint::core::AddressSpace::kUndefined;
 
     /// @return a hash code for this object
-    size_t HashCode() const { return Hash(type, variable); }
+    tint::HashCode HashCode() const { return Hash(type, variable); }
 };
 
 /// Inequality operator for AccessRoot
@@ -85,7 +85,7 @@
 /// vector index.
 struct DynamicIndex {
     /// @return a hash code for this object
-    size_t HashCode() const { return 42 /* empty struct: any number will do */; }
+    tint::HashCode HashCode() const { return 42 /* empty struct: any number will do */; }
 };
 
 /// Inequality operator for DynamicIndex
@@ -160,7 +160,7 @@
     }
 
     /// @return a hash code for this object
-    size_t HashCode() const { return Hash(root, ops); }
+    tint::HashCode HashCode() const { return Hash(root, ops); }
 };
 
 /// Equality operator for AccessShape
diff --git a/src/tint/lang/wgsl/ast/transform/helper_test.h b/src/tint/lang/wgsl/ast/transform/helper_test.h
index 495f822..15a1ef5 100644
--- a/src/tint/lang/wgsl/ast/transform/helper_test.h
+++ b/src/tint/lang/wgsl/ast/transform/helper_test.h
@@ -46,13 +46,13 @@
 /// program is not valid.
 inline std::string str(const Program& program) {
     if (!program.IsValid()) {
-        return program.Diagnostics().str();
+        return program.Diagnostics().Str();
     }
 
     wgsl::writer::Options options;
     auto result = wgsl::writer::Generate(program, options);
     if (result != Success) {
-        return result.Failure().reason.str();
+        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 d32b3b7..815a3ed 100644
--- a/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
+++ b/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
@@ -135,7 +135,7 @@
 
             BindingsMap::const_iterator it = new_binding_points->bindings_map.find(bp);
             if (it == new_binding_points->bindings_map.end()) {
-                b.Diagnostics().add_error(
+                b.Diagnostics().AddError(
                     diag::System::Transform,
                     "missing new binding points for texture_external at binding {" +
                         std::to_string(bp.group) + "," + std::to_string(bp.binding) + "}");
@@ -552,8 +552,8 @@
     ProgramBuilder b;
     program::CloneContext ctx{&b, &src, /* auto_clone_symbols */ true};
     if (!new_binding_points) {
-        b.Diagnostics().add_error(diag::System::Transform, "missing new binding point data for " +
-                                                               std::string(TypeInfo().name));
+        b.Diagnostics().AddError(diag::System::Transform, "missing new binding point data for " +
+                                                              std::string(TypeInfo().name));
         return resolver::Resolve(b);
     }
 
diff --git a/src/tint/lang/wgsl/ast/transform/offset_first_index.cc b/src/tint/lang/wgsl/ast/transform/offset_first_index.cc
index eb64f60..04bdd9a 100644
--- a/src/tint/lang/wgsl/ast/transform/offset_first_index.cc
+++ b/src/tint/lang/wgsl/ast/transform/offset_first_index.cc
@@ -136,23 +136,29 @@
         return SkipTransform;
     }
 
-    // Abort on any use of push constants in the module.
+    Vector<const ast::StructMember*, 8> members;
+
+    const ast::Variable* push_constants_var = nullptr;
+
+    // Find first push_constant.
     for (auto* global : src.AST().GlobalVariables()) {
         if (auto* var = global->As<ast::Var>()) {
             auto* v = src.Sem().Get(var);
-            if (TINT_UNLIKELY(v->AddressSpace() == core::AddressSpace::kPushConstant)) {
-                TINT_ICE()
-                    << "OffsetFirstIndex doesn't know how to handle module that already use push "
-                       "constants (yet)";
-                return resolver::Resolve(b);
+            if (v->AddressSpace() == core::AddressSpace::kPushConstant) {
+                push_constants_var = var;
+                auto* str = v->Type()->UnwrapRef()->As<sem::Struct>();
+                if (!str) {
+                    TINT_ICE() << "expected var<push_constant> type to be struct. Was "
+                                  "AddBlockAttribute run?";
+                }
+                for (auto* member : str->Members()) {
+                    members.Push(ctx.CloneWithoutTransform(member->Declaration()));
+                }
             }
         }
     }
 
-    b.Enable(wgsl::Extension::kChromiumExperimentalPushConstant);
-
     // Add push constant members and calculate byte offsets
-    tint::Vector<const StructMember*, 8> members;
     if (has_vertex_index) {
         members.Push(b.Member(kFirstVertexName, b.ty.u32(),
                               Vector{b.MemberOffset(AInt(*cfg->first_vertex_offset))}));
@@ -161,10 +167,37 @@
         members.Push(b.Member(kFirstInstanceName, b.ty.u32(),
                               Vector{b.MemberOffset(AInt(*cfg->first_instance_offset))}));
     }
-    auto struct_ = b.Structure(b.Symbols().New("PushConstants"), std::move(members));
-    // Create a global to hold the uniform buffer
-    Symbol buffer_name = b.Symbols().New("push_constants");
-    b.GlobalVar(buffer_name, b.ty.Of(struct_), core::AddressSpace::kPushConstant);
+
+    auto new_struct = b.Structure(b.Symbols().New("PushConstants"), std::move(members));
+
+    Symbol buffer_name;
+
+    // If this is the first use of push constants, create a global to hold them.
+    if (!push_constants_var) {
+        b.Enable(wgsl::Extension::kChromiumExperimentalPushConstant);
+
+        buffer_name = b.Symbols().New("push_constants");
+        b.GlobalVar(buffer_name, b.ty.Of(new_struct), core::AddressSpace::kPushConstant);
+    } else {
+        buffer_name = ctx.Clone(push_constants_var->name->symbol);
+    }
+
+    // Replace all variable users of the old struct with the new struct.
+    if (push_constants_var) {
+        ctx.ReplaceAll([&](const ast::Variable* var) -> const ast::Variable* {
+            if (var->type == push_constants_var->type) {
+                if (var->As<ast::Parameter>()) {
+                    return ctx.dst->Param(ctx.Clone(var->name->symbol), b.ty.Of(new_struct),
+                                          ctx.Clone(var->attributes));
+                } else {
+                    return ctx.dst->Var(ctx.Clone(var->name->symbol), b.ty.Of(new_struct),
+                                        ctx.Clone(var->attributes),
+                                        core::AddressSpace::kPushConstant);
+                }
+            }
+            return nullptr;
+        });
+    }
 
     // Fix up all references to the builtins with the offsets
     ctx.ReplaceAll([&](const Expression* expr) -> const Expression* {
@@ -172,14 +205,14 @@
             if (auto* user = sem->UnwrapLoad()->As<sem::VariableUser>()) {
                 auto it = builtin_vars.find(user->Variable());
                 if (it != builtin_vars.end()) {
-                    return ctx.dst->Add(ctx.CloneWithoutTransform(expr),
+                    return ctx.dst->Add(b.Bitcast(b.ty.u32(), ctx.CloneWithoutTransform(expr)),
                                         ctx.dst->MemberAccessor(buffer_name, it->second));
                 }
             }
             if (auto* access = sem->As<sem::StructMemberAccess>()) {
                 auto it = builtin_members.find(access->Member());
                 if (it != builtin_members.end()) {
-                    return ctx.dst->Add(ctx.CloneWithoutTransform(expr),
+                    return ctx.dst->Add(b.Bitcast(b.ty.u32(), ctx.CloneWithoutTransform(expr)),
                                         ctx.dst->MemberAccessor(buffer_name, it->second));
                 }
             }
diff --git a/src/tint/lang/wgsl/ast/transform/offset_first_index.h b/src/tint/lang/wgsl/ast/transform/offset_first_index.h
index aa37559..72d2e96 100644
--- a/src/tint/lang/wgsl/ast/transform/offset_first_index.h
+++ b/src/tint/lang/wgsl/ast/transform/offset_first_index.h
@@ -35,7 +35,7 @@
 /// Adds firstVertex/Instance (injected via push constants) to
 /// vertex/instance index builtins.
 ///
-/// This transform assumes that Name transform has been run before.
+/// This transform assumes that the Name and AddBlockAttribute transforms have been run before.
 ///
 /// Some shading languages start vertex and instance numbering at 0,
 /// regardless of the firstVertex/firstInstance value specified. This transform
diff --git a/src/tint/lang/wgsl/ast/transform/offset_first_index_test.cc b/src/tint/lang/wgsl/ast/transform/offset_first_index_test.cc
index 37a79a9..7d026ed 100644
--- a/src/tint/lang/wgsl/ast/transform/offset_first_index_test.cc
+++ b/src/tint/lang/wgsl/ast/transform/offset_first_index_test.cc
@@ -154,7 +154,7 @@
 
 @vertex
 fn entry(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
-  test((vert_idx + push_constants.first_vertex));
+  test((bitcast<u32>(vert_idx) + push_constants.first_vertex));
   return vec4<f32>();
 }
 )";
@@ -191,7 +191,7 @@
 
 @vertex
 fn entry(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
-  test((vert_idx + push_constants.first_vertex));
+  test((bitcast<u32>(vert_idx) + push_constants.first_vertex));
   return vec4<f32>();
 }
 
@@ -238,7 +238,7 @@
 
 @vertex
 fn entry(@builtin(instance_index) inst_idx : u32) -> @builtin(position) vec4<f32> {
-  test((inst_idx + push_constants.first_instance));
+  test((bitcast<u32>(inst_idx) + push_constants.first_instance));
   return vec4<f32>();
 }
 )";
@@ -277,7 +277,7 @@
 
 @vertex
 fn entry(@builtin(instance_index) inst_idx : u32) -> @builtin(position) vec4<f32> {
-  test((inst_idx + push_constants.first_instance));
+  test((bitcast<u32>(inst_idx) + push_constants.first_instance));
   return vec4<f32>();
 }
 
@@ -336,7 +336,7 @@
 
 @vertex
 fn entry(inputs : Inputs) -> @builtin(position) vec4<f32> {
-  test((inputs.instance_idx + push_constants.first_instance), (inputs.vert_idx + push_constants.first_vertex));
+  test((bitcast<u32>(inputs.instance_idx) + push_constants.first_instance), (bitcast<u32>(inputs.vert_idx) + push_constants.first_vertex));
   return vec4<f32>();
 }
 )";
@@ -380,7 +380,7 @@
 
 @vertex
 fn entry(inputs : Inputs) -> @builtin(position) vec4<f32> {
-  test((inputs.instance_idx + push_constants.first_instance), (inputs.vert_idx + push_constants.first_vertex));
+  test((bitcast<u32>(inputs.instance_idx) + push_constants.first_instance), (bitcast<u32>(inputs.vert_idx) + push_constants.first_vertex));
   return vec4<f32>();
 }
 
@@ -444,7 +444,7 @@
 
 @vertex
 fn entry(inputs : Inputs) -> @builtin(position) vec4<f32> {
-  test((inputs.instance_idx + push_constants.first_instance), inputs.vert_idx);
+  test((bitcast<u32>(inputs.instance_idx) + push_constants.first_instance), inputs.vert_idx);
   return vec4<f32>();
 }
 )";
@@ -497,7 +497,7 @@
 
 @vertex
 fn entry(inputs : Inputs) -> @builtin(position) vec4<f32> {
-  test(inputs.instance_idx, (inputs.vert_idx + push_constants.first_vertex));
+  test(inputs.instance_idx, (bitcast<u32>(inputs.vert_idx) + push_constants.first_vertex));
   return vec4<f32>();
 }
 )";
@@ -572,7 +572,7 @@
 
 @vertex
 fn entry(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
-  return vec4<f32>((f32((vert_idx + push_constants.first_vertex)) + p.f));
+  return vec4<f32>((f32((bitcast<u32>(vert_idx) + push_constants.first_vertex)) + p.f));
 }
 )";
 
@@ -609,7 +609,7 @@
 
 @vertex
 fn entry(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
-  return vec4<f32>(f32((vert_idx + push_constants_1.first_vertex)));
+  return vec4<f32>(f32((bitcast<u32>(vert_idx) + push_constants_1.first_vertex)));
 }
 )";
 
@@ -657,7 +657,7 @@
 
 @vertex
 fn entry(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
-  func2((vert_idx + push_constants.first_vertex));
+  func2((bitcast<u32>(vert_idx) + push_constants.first_vertex));
   return vec4<f32>();
 }
 )";
@@ -698,7 +698,7 @@
 
 @vertex
 fn entry(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
-  func2((vert_idx + push_constants.first_vertex));
+  func2((bitcast<u32>(vert_idx) + push_constants.first_vertex));
   return vec4<f32>();
 }
 
@@ -761,19 +761,19 @@
 
 @vertex
 fn entry_a(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
-  func((vert_idx + push_constants.first_vertex));
+  func((bitcast<u32>(vert_idx) + push_constants.first_vertex));
   return vec4<f32>();
 }
 
 @vertex
 fn entry_b(@builtin(vertex_index) vert_idx : u32, @builtin(instance_index) inst_idx : u32) -> @builtin(position) vec4<f32> {
-  func(((vert_idx + push_constants.first_vertex) + (inst_idx + push_constants.first_instance)));
+  func(((bitcast<u32>(vert_idx) + push_constants.first_vertex) + (bitcast<u32>(inst_idx) + push_constants.first_instance)));
   return vec4<f32>();
 }
 
 @vertex
 fn entry_c(@builtin(instance_index) inst_idx : u32) -> @builtin(position) vec4<f32> {
-  func((inst_idx + push_constants.first_instance));
+  func((bitcast<u32>(inst_idx) + push_constants.first_instance));
   return vec4<f32>();
 }
 )";
@@ -824,19 +824,19 @@
 
 @vertex
 fn entry_a(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
-  func((vert_idx + push_constants.first_vertex));
+  func((bitcast<u32>(vert_idx) + push_constants.first_vertex));
   return vec4<f32>();
 }
 
 @vertex
 fn entry_b(@builtin(vertex_index) vert_idx : u32, @builtin(instance_index) inst_idx : u32) -> @builtin(position) vec4<f32> {
-  func(((vert_idx + push_constants.first_vertex) + (inst_idx + push_constants.first_instance)));
+  func(((bitcast<u32>(vert_idx) + push_constants.first_vertex) + (bitcast<u32>(inst_idx) + push_constants.first_instance)));
   return vec4<f32>();
 }
 
 @vertex
 fn entry_c(@builtin(instance_index) inst_idx : u32) -> @builtin(position) vec4<f32> {
-  func((inst_idx + push_constants.first_instance));
+  func((bitcast<u32>(inst_idx) + push_constants.first_instance));
   return vec4<f32>();
 }
 
diff --git a/src/tint/lang/wgsl/ast/transform/robustness.cc b/src/tint/lang/wgsl/ast/transform/robustness.cc
index 676a544..c3f9c57 100644
--- a/src/tint/lang/wgsl/ast/transform/robustness.cc
+++ b/src/tint/lang/wgsl/ast/transform/robustness.cc
@@ -272,8 +272,8 @@
                 }
                 // Note: Don't be tempted to use the array override variable as an expression here,
                 // the name might be shadowed!
-                b.Diagnostics().add_error(diag::System::Transform,
-                                          core::type::Array::kErrExpectedConstantCount);
+                b.Diagnostics().AddError(diag::System::Transform,
+                                         core::type::Array::kErrExpectedConstantCount);
                 return nullptr;
             },  //
             TINT_ICE_ON_NO_MATCH);
diff --git a/src/tint/lang/wgsl/ast/transform/single_entry_point.cc b/src/tint/lang/wgsl/ast/transform/single_entry_point.cc
index 53b00d0..78843cc 100644
--- a/src/tint/lang/wgsl/ast/transform/single_entry_point.cc
+++ b/src/tint/lang/wgsl/ast/transform/single_entry_point.cc
@@ -55,8 +55,8 @@
 
     auto* cfg = inputs.Get<Config>();
     if (cfg == nullptr) {
-        b.Diagnostics().add_error(diag::System::Transform,
-                                  "missing transform data for " + std::string(TypeInfo().name));
+        b.Diagnostics().AddError(diag::System::Transform,
+                                 "missing transform data for " + std::string(TypeInfo().name));
         return resolver::Resolve(b);
     }
 
@@ -72,8 +72,8 @@
         }
     }
     if (entry_point == nullptr) {
-        b.Diagnostics().add_error(diag::System::Transform,
-                                  "entry point '" + cfg->entry_point_name + "' not found");
+        b.Diagnostics().AddError(diag::System::Transform,
+                                 "entry point '" + cfg->entry_point_name + "' not found");
         return resolver::Resolve(b);
     }
 
diff --git a/src/tint/lang/wgsl/ast/transform/std140.cc b/src/tint/lang/wgsl/ast/transform/std140.cc
index 037d716..9dc49b5 100644
--- a/src/tint/lang/wgsl/ast/transform/std140.cc
+++ b/src/tint/lang/wgsl/ast/transform/std140.cc
@@ -57,7 +57,7 @@
 /// UniformVariable is used by Std140::State::AccessIndex to indicate the root uniform variable
 struct UniformVariable {
     /// @returns a hash code for this object
-    size_t HashCode() const { return 0; }
+    tint::HashCode HashCode() const { return 0; }
 };
 
 /// Inequality operator for UniformVariable
@@ -70,7 +70,7 @@
     size_t slot;  // The index of the expression in Std140::State::AccessChain::dynamic_indices
 
     /// @returns a hash code for this object
-    size_t HashCode() const { return Hash(slot); }
+    tint::HashCode HashCode() const { return Hash(slot); }
 };
 
 /// Inequality operator for DynamicIndex
@@ -193,12 +193,8 @@
         /// The chain of accesses indices.
         AccessIndices indices;
 
-        /// Hash function for LoadFnKey.
-        struct Hasher {
-            /// @param fn the LoadFnKey to hash
-            /// @return the hash for the given LoadFnKey
-            size_t operator()(const LoadFnKey& fn) const { return Hash(fn.var, fn.indices); }
-        };
+        /// @returns the hash code for the LoadFnKey
+        tint::HashCode HashCode() const { return Hash(var, indices); }
 
         /// Equality operator
         bool operator==(const LoadFnKey& other) const {
@@ -218,7 +214,7 @@
     const SymbolTable& sym = src.Symbols();
 
     /// Map of load function signature, to the generated function
-    Hashmap<LoadFnKey, Symbol, 8, LoadFnKey::Hasher> load_fns;
+    Hashmap<LoadFnKey, Symbol, 8> load_fns;
 
     /// Map of std140-forked type to converter function name
     Hashmap<const core::type::Type*, Symbol, 8> conv_fns;
diff --git a/src/tint/lang/wgsl/ast/transform/substitute_override.cc b/src/tint/lang/wgsl/ast/transform/substitute_override.cc
index a36bc65..74d8b7b 100644
--- a/src/tint/lang/wgsl/ast/transform/substitute_override.cc
+++ b/src/tint/lang/wgsl/ast/transform/substitute_override.cc
@@ -71,7 +71,7 @@
 
     const auto* data = config.Get<Config>();
     if (!data) {
-        b.Diagnostics().add_error(diag::System::Transform, "Missing override substitution data");
+        b.Diagnostics().AddError(diag::System::Transform, "Missing override substitution data");
         return resolver::Resolve(b);
     }
 
@@ -90,7 +90,7 @@
         auto iter = data->map.find(sem->Attributes().override_id.value());
         if (iter == data->map.end()) {
             if (!w->initializer) {
-                b.Diagnostics().add_error(
+                b.Diagnostics().AddError(
                     diag::System::Transform,
                     "Initializer not provided for override, and override not overridden.");
                 return nullptr;
@@ -108,8 +108,8 @@
             [&](const core::type::F16*) { return b.Expr(f16(value)); });
 
         if (!ctor) {
-            b.Diagnostics().add_error(diag::System::Transform,
-                                      "Failed to create override-expression");
+            b.Diagnostics().AddError(diag::System::Transform,
+                                     "Failed to create override-expression");
             return nullptr;
         }
 
diff --git a/src/tint/lang/wgsl/ast/transform/substitute_override.h b/src/tint/lang/wgsl/ast/transform/substitute_override.h
index 2e18b11..c95426d 100644
--- a/src/tint/lang/wgsl/ast/transform/substitute_override.h
+++ b/src/tint/lang/wgsl/ast/transform/substitute_override.h
@@ -79,9 +79,12 @@
         std::unordered_map<OverrideId, double> map;
 
         /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-        TINT_REFLECT(map);
+        TINT_REFLECT(Config, map);
     };
 
+    /// Ensure that all the fields of Config are reflected.
+    TINT_ASSERT_ALL_FIELDS_REFLECTED(Config);
+
     /// Constructor
     SubstituteOverride();
 
diff --git a/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc b/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc
index 81ec237..623bab0 100644
--- a/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc
+++ b/src/tint/lang/wgsl/ast/transform/vertex_pulling.cc
@@ -261,7 +261,7 @@
         for (auto* fn : src.AST().Functions()) {
             if (fn->PipelineStage() == PipelineStage::kVertex) {
                 if (func != nullptr) {
-                    b.Diagnostics().add_error(
+                    b.Diagnostics().AddError(
                         diag::System::Transform,
                         "VertexPulling found more than one vertex entry point");
                     return resolver::Resolve(b);
@@ -270,8 +270,7 @@
             }
         }
         if (func == nullptr) {
-            b.Diagnostics().add_error(diag::System::Transform,
-                                      "Vertex stage entry point not found");
+            b.Diagnostics().AddError(diag::System::Transform, "Vertex stage entry point not found");
             return resolver::Resolve(b);
         }
 
@@ -359,7 +358,7 @@
             const VertexBufferLayoutDescriptor& buffer_layout = cfg.vertex_state[buffer_idx];
 
             if ((buffer_layout.array_stride & 3) != 0) {
-                b.Diagnostics().add_error(
+                b.Diagnostics().AddError(
                     diag::System::Transform,
                     "WebGPU requires that vertex stride must be a multiple of 4 bytes, "
                     "but VertexPulling array stride for buffer " +
@@ -404,7 +403,7 @@
                         << std::to_string(attribute_desc.shader_location) << " has format "
                         << attribute_desc.format << " but shader expects "
                         << var.type->FriendlyName();
-                    b.Diagnostics().add_error(diag::System::Transform, err.str());
+                    b.Diagnostics().AddError(diag::System::Transform, err.str());
                     return nullptr;
                 }
 
diff --git a/src/tint/lang/wgsl/ast/transform/vertex_pulling.h b/src/tint/lang/wgsl/ast/transform/vertex_pulling.h
index 62ec75f..f238c0d 100644
--- a/src/tint/lang/wgsl/ast/transform/vertex_pulling.h
+++ b/src/tint/lang/wgsl/ast/transform/vertex_pulling.h
@@ -89,9 +89,12 @@
     uint32_t shader_location;
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(format, offset, shader_location);
+    TINT_REFLECT(VertexAttributeDescriptor, format, offset, shader_location);
 };
 
+/// Ensure that all the fields of VertexAttributeDescriptor are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(VertexAttributeDescriptor);
+
 /// Describes a buffer containing multiple vertex attributes
 struct VertexBufferLayoutDescriptor {
     /// Constructor
@@ -122,9 +125,12 @@
     std::vector<VertexAttributeDescriptor> attributes;
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(array_stride, step_mode, attributes);
+    TINT_REFLECT(VertexBufferLayoutDescriptor, array_stride, step_mode, attributes);
 };
 
+/// Ensure that all the fields of VertexBufferLayoutDescriptor are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(VertexBufferLayoutDescriptor);
+
 /// Describes vertex state, which consists of many buffers containing vertex
 /// attributes
 using VertexStateDescriptor = std::vector<VertexBufferLayoutDescriptor>;
@@ -176,9 +182,12 @@
         uint32_t pulling_group = 4u;
 
         /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-        TINT_REFLECT(vertex_state, pulling_group);
+        TINT_REFLECT(Config, vertex_state, pulling_group);
     };
 
+    /// Ensure that all the fields of Config are reflected.
+    TINT_ASSERT_ALL_FIELDS_REFLECTED(Config);
+
     /// Constructor
     VertexPulling();
 
diff --git a/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory.cc b/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory.cc
index 235693e..e394520 100644
--- a/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory.cc
+++ b/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory.cc
@@ -76,6 +76,9 @@
     /// An alias to *ctx.dst
     ast::Builder& b = *ctx.dst;
 
+    /// The semantic info for the source program.
+    const sem::Info& sem = ctx.src->Sem();
+
     /// The constant size of the workgroup. If 0, then #workgroup_size_expr should
     /// be used instead.
     uint32_t workgroup_size_const = 0;
@@ -91,23 +94,19 @@
         /// The RHS of the division part of the expression
         uint32_t division = 1;
 
+        /// @returns the hash code of the ArrayIndex
+        tint::HashCode HashCode() const { return Hash(modulo, division); }
+
         /// Equality operator
         /// @param i the ArrayIndex to compare to this ArrayIndex
         /// @returns true if `i` and this ArrayIndex are equal
         bool operator==(const ArrayIndex& i) const {
             return modulo == i.modulo && division == i.division;
         }
-
-        /// Hash function for the ArrayIndex type
-        struct Hasher {
-            /// @param i the ArrayIndex to calculate a hash for
-            /// @returns the hash value for the ArrayIndex `i`
-            size_t operator()(const ArrayIndex& i) const { return Hash(i.modulo, i.division); }
-        };
     };
 
     /// A list of unique ArrayIndex
-    using ArrayIndices = UniqueVector<ArrayIndex, 4, ArrayIndex::Hasher>;
+    using ArrayIndices = UniqueVector<ArrayIndex, 4>;
 
     /// Expression holds information about an expression that is being built for a
     /// statement will zero workgroup values.
@@ -139,7 +138,7 @@
 
     /// A map of ArrayIndex to the name reserved for the `let` declaration of that
     /// index.
-    std::unordered_map<ArrayIndex, Symbol, ArrayIndex::Hasher> array_index_names;
+    Hashmap<ArrayIndex, Symbol, 4> array_index_names;
 
     /// Constructor
     /// @param c the program::CloneContext used for the transform
@@ -149,12 +148,29 @@
     /// the given function
     /// @param fn a compute shader entry point function
     void Run(const Function* fn) {
-        auto& sem = ctx.src->Sem();
-
         CalculateWorkgroupSize(GetAttribute<WorkgroupAttribute>(fn->attributes));
 
-        // Generate a list of statements to zero initialize each of the
-        // workgroup storage variables used by `fn`. This will populate #statements.
+        // Generate the workgroup zeroing function
+        auto zeroing_fn_name = BuildZeroingFn(fn);
+        if (!zeroing_fn_name) {
+            return;  // Nothing to do.
+        }
+
+        // Get or create the local invocation index parameter on the entry point
+        auto local_invocation_index = GetOrCreateLocalInvocationIndex(fn);
+
+        // Prefix the entry point body with a call to the workgroup zeroing function
+        ctx.InsertFront(fn->body->statements,
+                        b.CallStmt(b.Call(zeroing_fn_name, local_invocation_index)));
+    }
+
+    /// Builds a function that zeros all the variables in the workgroup address space transitively
+    /// used by @p fn. The built function takes a single `local_invocation_id : u32` parameter
+    /// @param fn the entry point function.
+    /// @return the name of the workgroup memory zeroing function.
+    Symbol BuildZeroingFn(const Function* fn) {
+        // Generate a list of statements to zero initialize each of the workgroup storage variables
+        // used by `fn`. This will populate #statements.
         auto* func = sem.Get(fn);
         for (auto* var : func->TransitivelyReferencedGlobals()) {
             if (var->AddressSpace() == core::AddressSpace::kWorkgroup) {
@@ -163,47 +179,13 @@
                     return Expression{b.Expr(var_name), num_values, ArrayIndices{}};
                 };
                 if (!BuildZeroingStatements(var->Type()->UnwrapRef(), get_expr)) {
-                    return;
+                    return Symbol{};
                 }
             }
         }
 
         if (statements.empty()) {
-            return;  // No workgroup variables to initialize.
-        }
-
-        // Scan the entry point for an existing local_invocation_index builtin
-        // parameter
-        std::function<const ast::Expression*()> local_index;
-        for (auto* param : fn->params) {
-            if (auto* builtin_attr = GetAttribute<BuiltinAttribute>(param->attributes)) {
-                auto builtin = sem.Get(builtin_attr)->Value();
-                if (builtin == core::BuiltinValue::kLocalInvocationIndex) {
-                    local_index = [=] { return b.Expr(ctx.Clone(param->name->symbol)); };
-                    break;
-                }
-            }
-
-            if (auto* str = sem.Get(param)->Type()->As<core::type::Struct>()) {
-                for (auto* member : str->Members()) {
-                    if (member->Attributes().builtin == core::BuiltinValue::kLocalInvocationIndex) {
-                        local_index = [=] {
-                            auto* param_expr = b.Expr(ctx.Clone(param->name->symbol));
-                            auto member_name = ctx.Clone(member->Name());
-                            return b.MemberAccessor(param_expr, member_name);
-                        };
-                        break;
-                    }
-                }
-            }
-        }
-        if (!local_index) {
-            // No existing local index parameter. Append one to the entry point.
-            auto param_name = b.Symbols().New("local_invocation_index");
-            auto* local_invocation_index = b.Builtin(core::BuiltinValue::kLocalInvocationIndex);
-            auto* param = b.Param(param_name, b.ty.u32(), tint::Vector{local_invocation_index});
-            ctx.InsertBack(fn->params, param);
-            local_index = [=] { return b.Expr(param->name->symbol); };
+            return Symbol{};  // No workgroup variables to initialize.
         }
 
         // Take the zeroing statements and bin them by the number of iterations
@@ -220,7 +202,10 @@
         }
         std::sort(num_sorted_iterations.begin(), num_sorted_iterations.end());
 
+        auto local_idx = b.Symbols().New("local_idx");
+
         // Loop over the statements, grouped by num_iterations.
+        Vector<const ast::Statement*, 8> init_body;
         for (auto num_iterations : num_sorted_iterations) {
             auto& stmts = stmts_by_num_iterations[num_iterations];
 
@@ -245,9 +230,8 @@
                 //    ...
                 //  }
                 auto idx = b.Symbols().New("idx");
-                auto* init = b.Decl(b.Var(idx, b.ty.u32(), local_index()));
-                auto* cond = b.create<BinaryExpression>(core::BinaryOp::kLessThan, b.Expr(idx),
-                                                        b.Expr(u32(num_iterations)));
+                auto* init = b.Decl(b.Var(idx, b.ty.u32(), b.Expr(local_idx)));
+                auto* cond = b.LessThan(idx, u32(num_iterations));
                 auto* cont = b.Assign(
                     idx, b.Add(idx, workgroup_size_const ? b.Expr(u32(workgroup_size_const))
                                                          : workgroup_size_expr()));
@@ -258,7 +242,7 @@
                     block.Push(s.stmt);
                 }
                 auto* for_loop = b.For(init, cond, cont, b.Block(block));
-                ctx.InsertFront(fn->body->statements, for_loop);
+                init_body.Push(for_loop);
             } else if (num_iterations < workgroup_size_const) {
                 // Workgroup size is a known constant, but is greater than
                 // num_iterations. Emit an if statement:
@@ -266,15 +250,15 @@
                 //  if (local_index < num_iterations) {
                 //    ...
                 //  }
-                auto* cond = b.create<BinaryExpression>(core::BinaryOp::kLessThan, local_index(),
-                                                        b.Expr(u32(num_iterations)));
+
+                auto* cond = b.LessThan(local_idx, u32(num_iterations));
                 auto block = DeclareArrayIndices(num_iterations, array_indices,
-                                                 [&] { return b.Expr(local_index()); });
+                                                 [&] { return b.Expr(local_idx); });
                 for (auto& s : stmts) {
                     block.Push(s.stmt);
                 }
                 auto* if_stmt = b.If(cond, b.Block(block));
-                ctx.InsertFront(fn->body->statements, if_stmt);
+                init_body.Push(if_stmt);
             } else {
                 // Workgroup size exactly equals num_iterations.
                 // No need for any conditionals. Just emit a basic block:
@@ -283,16 +267,56 @@
                 //    ...
                 // }
                 auto block = DeclareArrayIndices(num_iterations, array_indices,
-                                                 [&] { return b.Expr(local_index()); });
+                                                 [&] { return b.Expr(local_idx); });
                 for (auto& s : stmts) {
                     block.Push(s.stmt);
                 }
-                ctx.InsertFront(fn->body->statements, b.Block(block));
+                init_body.Push(b.Block(std::move(block)));
             }
         }
 
         // Append a single workgroup barrier after the zero initialization.
-        ctx.InsertFront(fn->body->statements, b.CallStmt(b.Call("workgroupBarrier")));
+        init_body.Push(b.CallStmt(b.Call("workgroupBarrier")));
+
+        // Generate the zero-init function.
+        auto name = b.Symbols().New("tint_zero_workgroup_memory");
+        b.Func(name, Vector{b.Param(local_idx, b.ty.u32())}, b.ty.void_(),
+               b.Block(std::move(init_body)));
+        return name;
+    }
+
+    /// Looks for an existing `local_invocation_index` parameter on the entry point function @p fn,
+    /// or adds a new parameter to the function if it doesn't exist.
+    /// @param fn the entry point function.
+    /// @return an expression to the `local_invocation_index` parameter.
+    const ast::Expression* GetOrCreateLocalInvocationIndex(const Function* fn) {
+        // Scan the entry point for an existing local_invocation_index builtin parameter
+        std::function<const ast::Expression*()> local_index;
+        for (auto* param : fn->params) {
+            if (auto* builtin_attr = GetAttribute<BuiltinAttribute>(param->attributes)) {
+                auto builtin = sem.Get(builtin_attr)->Value();
+                if (builtin == core::BuiltinValue::kLocalInvocationIndex) {
+                    return b.Expr(ctx.Clone(param->name->symbol));
+                }
+            }
+
+            if (auto* str = sem.Get(param)->Type()->As<core::type::Struct>()) {
+                for (auto* member : str->Members()) {
+                    if (member->Attributes().builtin == core::BuiltinValue::kLocalInvocationIndex) {
+                        auto* param_expr = b.Expr(ctx.Clone(param->name->symbol));
+                        auto member_name = ctx.Clone(member->Name());
+                        return b.MemberAccessor(param_expr, member_name);
+                    }
+                }
+            }
+        }
+
+        // No existing local index parameter. Append one to the entry point.
+        auto param_name = b.Symbols().New("local_invocation_index");
+        auto* local_invocation_index = b.Builtin(core::BuiltinValue::kLocalInvocationIndex);
+        auto* param = b.Param(param_name, b.ty.u32(), tint::Vector{local_invocation_index});
+        ctx.InsertBack(fn->params, param);
+        return b.Expr(param->name->symbol);
     }
 
     /// BuildZeroingExpr is a function that builds a sub-expression used to zero
@@ -357,8 +381,8 @@
                 //      `(idx % modulo) / division`
                 auto count = arr->ConstantCount();
                 if (!count) {
-                    ctx.dst->Diagnostics().add_error(diag::System::Transform,
-                                                     core::type::Array::kErrExpectedConstantCount);
+                    ctx.dst->Diagnostics().AddError(diag::System::Transform,
+                                                    core::type::Array::kErrExpectedConstantCount);
                     return Expression{};  // error
                 }
                 auto modulo = num_values * count.value();
@@ -369,8 +393,8 @@
                 }
                 auto array_indices = a.array_indices;
                 array_indices.Add(ArrayIndex{modulo, division});
-                auto index = tint::GetOrAdd(array_index_names, ArrayIndex{modulo, division},
-                                            [&] { return b.Symbols().New("i"); });
+                auto index = array_index_names.GetOrAdd(ArrayIndex{modulo, division},
+                                                        [&] { return b.Symbols().New("i"); });
                 return Expression{b.IndexAccessor(a.expr, index), a.num_iterations, array_indices};
             };
             return BuildZeroingStatements(arr->ElemType(), get_el);
@@ -394,13 +418,13 @@
         StatementList stmts;
         std::map<Symbol, ArrayIndex> indices_by_name;
         for (auto index : array_indices) {
-            auto name = array_index_names.at(index);
+            auto name = array_index_names.Get(index);
             auto* mod = (num_iterations > index.modulo)
                             ? b.create<BinaryExpression>(core::BinaryOp::kModulo, iteration(),
                                                          b.Expr(u32(index.modulo)))
                             : iteration();
             auto* div = (index.division != 1u) ? b.Div(mod, u32(index.division)) : mod;
-            auto* decl = b.Decl(b.Let(name, b.ty.u32(), div));
+            auto* decl = b.Decl(b.Let(*name, b.ty.u32(), div));
             stmts.Push(decl);
         }
         return stmts;
@@ -417,8 +441,7 @@
             if (!expr) {
                 continue;
             }
-            auto* sem = ctx.src->Sem().GetVal(expr);
-            if (auto* c = sem->ConstantValue()) {
+            if (auto* c = sem.GetVal(expr)->ConstantValue()) {
                 workgroup_size_const *= c->ValueAs<AInt>();
                 continue;
             }
diff --git a/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory_test.cc b/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory_test.cc
index 63e9330..440e2a4 100644
--- a/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory_test.cc
+++ b/src/tint/lang/wgsl/ast/transform/zero_init_workgroup_memory_test.cc
@@ -138,14 +138,18 @@
 }
 )";
     auto* expect = R"(
-var<workgroup> v : i32;
-
-@compute @workgroup_size(1)
-fn f(@builtin(local_invocation_index) local_idx : u32) {
+fn tint_zero_workgroup_memory(local_idx_1 : u32) {
   {
     v = i32();
   }
   workgroupBarrier();
+}
+
+var<workgroup> v : i32;
+
+@compute @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_idx : u32) {
+  tint_zero_workgroup_memory(local_idx);
   _ = v;
 }
 )";
@@ -165,12 +169,16 @@
 var<workgroup> v : i32;
 )";
     auto* expect = R"(
-@compute @workgroup_size(1)
-fn f(@builtin(local_invocation_index) local_idx : u32) {
+fn tint_zero_workgroup_memory(local_idx_1 : u32) {
   {
     v = i32();
   }
   workgroupBarrier();
+}
+
+@compute @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_idx : u32) {
+  tint_zero_workgroup_memory(local_idx);
   _ = v;
 }
 
@@ -196,6 +204,13 @@
 }
 )";
     auto* expect = R"(
+fn tint_zero_workgroup_memory(local_idx_1 : u32) {
+  {
+    v = i32();
+  }
+  workgroupBarrier();
+}
+
 var<workgroup> v : i32;
 
 struct Params {
@@ -205,10 +220,7 @@
 
 @compute @workgroup_size(1)
 fn f(params : Params) {
-  {
-    v = i32();
-  }
-  workgroupBarrier();
+  tint_zero_workgroup_memory(params.local_idx);
   _ = v;
 }
 )";
@@ -232,12 +244,16 @@
 var<workgroup> v : i32;
 )";
     auto* expect = R"(
-@compute @workgroup_size(1)
-fn f(params : Params) {
+fn tint_zero_workgroup_memory(local_idx_1 : u32) {
   {
     v = i32();
   }
   workgroupBarrier();
+}
+
+@compute @workgroup_size(1)
+fn f(params : Params) {
+  tint_zero_workgroup_memory(params.local_idx);
   _ = v;
 }
 
@@ -264,14 +280,18 @@
 }
 )";
     auto* expect = R"(
-var<workgroup> v : i32;
-
-@compute @workgroup_size(1)
-fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+fn tint_zero_workgroup_memory(local_idx : u32) {
   {
     v = i32();
   }
   workgroupBarrier();
+}
+
+var<workgroup> v : i32;
+
+@compute @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+  tint_zero_workgroup_memory(local_invocation_index);
   _ = v;
 }
 )";
@@ -291,12 +311,16 @@
 var<workgroup> v : i32;
 )";
     auto* expect = R"(
-@compute @workgroup_size(1)
-fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+fn tint_zero_workgroup_memory(local_idx : u32) {
   {
     v = i32();
   }
   workgroupBarrier();
+}
+
+@compute @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+  tint_zero_workgroup_memory(local_invocation_index);
   _ = v;
 }
 
@@ -329,6 +353,27 @@
 }
 )";
     auto* expect = R"(
+fn tint_zero_workgroup_memory(local_idx_1 : u32) {
+  {
+    a = i32();
+    b.x = i32();
+  }
+  for(var idx : u32 = local_idx_1; (idx < 8u); idx = (idx + 1u)) {
+    let i : u32 = idx;
+    b.y[i] = i32();
+  }
+  for(var idx_1 : u32 = local_idx_1; (idx_1 < 32u); idx_1 = (idx_1 + 1u)) {
+    let i_1 : u32 = idx_1;
+    c[i_1].x = i32();
+  }
+  for(var idx_2 : u32 = local_idx_1; (idx_2 < 256u); idx_2 = (idx_2 + 1u)) {
+    let i_2 : u32 = (idx_2 / 8u);
+    let i : u32 = (idx_2 % 8u);
+    c[i_2].y[i] = i32();
+  }
+  workgroupBarrier();
+}
+
 struct S {
   x : i32,
   y : array<i32, 8>,
@@ -342,24 +387,7 @@
 
 @compute @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_idx : u32) {
-  {
-    a = i32();
-    b.x = i32();
-  }
-  for(var idx : u32 = local_idx; (idx < 8u); idx = (idx + 1u)) {
-    let i : u32 = idx;
-    b.y[i] = i32();
-  }
-  for(var idx_1 : u32 = local_idx; (idx_1 < 32u); idx_1 = (idx_1 + 1u)) {
-    let i_1 : u32 = idx_1;
-    c[i_1].x = i32();
-  }
-  for(var idx_2 : u32 = local_idx; (idx_2 < 256u); idx_2 = (idx_2 + 1u)) {
-    let i_2 : u32 = (idx_2 / 8u);
-    let i : u32 = (idx_2 % 8u);
-    c[i_2].y[i] = i32();
-  }
-  workgroupBarrier();
+  tint_zero_workgroup_memory(local_idx);
   _ = a;
   _ = b;
   _ = c;
@@ -392,26 +420,30 @@
 };
 )";
     auto* expect = R"(
-@compute @workgroup_size(1)
-fn f(@builtin(local_invocation_index) local_idx : u32) {
+fn tint_zero_workgroup_memory(local_idx_1 : u32) {
   {
     a = i32();
     b.x = i32();
   }
-  for(var idx : u32 = local_idx; (idx < 8u); idx = (idx + 1u)) {
+  for(var idx : u32 = local_idx_1; (idx < 8u); idx = (idx + 1u)) {
     let i : u32 = idx;
     b.y[i] = i32();
   }
-  for(var idx_1 : u32 = local_idx; (idx_1 < 32u); idx_1 = (idx_1 + 1u)) {
+  for(var idx_1 : u32 = local_idx_1; (idx_1 < 32u); idx_1 = (idx_1 + 1u)) {
     let i_1 : u32 = idx_1;
     c[i_1].x = i32();
   }
-  for(var idx_2 : u32 = local_idx; (idx_2 < 256u); idx_2 = (idx_2 + 1u)) {
+  for(var idx_2 : u32 = local_idx_1; (idx_2 < 256u); idx_2 = (idx_2 + 1u)) {
     let i_2 : u32 = (idx_2 / 8u);
     let i : u32 = (idx_2 % 8u);
     c[i_2].y[i] = i32();
   }
   workgroupBarrier();
+}
+
+@compute @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_idx : u32) {
+  tint_zero_workgroup_memory(local_idx);
   _ = a;
   _ = b;
   _ = c;
@@ -455,6 +487,27 @@
 }
 )";
     auto* expect = R"(
+fn tint_zero_workgroup_memory(local_idx_1 : u32) {
+  if ((local_idx_1 < 1u)) {
+    a = i32();
+    b.x = i32();
+  }
+  for(var idx : u32 = local_idx_1; (idx < 8u); idx = (idx + 6u)) {
+    let i : u32 = idx;
+    b.y[i] = i32();
+  }
+  for(var idx_1 : u32 = local_idx_1; (idx_1 < 32u); idx_1 = (idx_1 + 6u)) {
+    let i_1 : u32 = idx_1;
+    c[i_1].x = i32();
+  }
+  for(var idx_2 : u32 = local_idx_1; (idx_2 < 256u); idx_2 = (idx_2 + 6u)) {
+    let i_2 : u32 = (idx_2 / 8u);
+    let i : u32 = (idx_2 % 8u);
+    c[i_2].y[i] = i32();
+  }
+  workgroupBarrier();
+}
+
 struct S {
   x : i32,
   y : array<i32, 8>,
@@ -468,24 +521,7 @@
 
 @compute @workgroup_size(2, 3)
 fn f(@builtin(local_invocation_index) local_idx : u32) {
-  if ((local_idx < 1u)) {
-    a = i32();
-    b.x = i32();
-  }
-  for(var idx : u32 = local_idx; (idx < 8u); idx = (idx + 6u)) {
-    let i : u32 = idx;
-    b.y[i] = i32();
-  }
-  for(var idx_1 : u32 = local_idx; (idx_1 < 32u); idx_1 = (idx_1 + 6u)) {
-    let i_1 : u32 = idx_1;
-    c[i_1].x = i32();
-  }
-  for(var idx_2 : u32 = local_idx; (idx_2 < 256u); idx_2 = (idx_2 + 6u)) {
-    let i_2 : u32 = (idx_2 / 8u);
-    let i : u32 = (idx_2 % 8u);
-    c[i_2].y[i] = i32();
-  }
-  workgroupBarrier();
+  tint_zero_workgroup_memory(local_idx);
   _ = a;
   _ = b;
   _ = c;
@@ -521,6 +557,27 @@
 )";
     auto* expect =
         R"(
+fn tint_zero_workgroup_memory(local_idx_1 : u32) {
+  for(var idx : u32 = local_idx_1; (idx < 1u); idx = (idx + (u32(X) * 6u))) {
+    a = i32();
+    b.x = i32();
+  }
+  for(var idx_1 : u32 = local_idx_1; (idx_1 < 8u); idx_1 = (idx_1 + (u32(X) * 6u))) {
+    let i : u32 = idx_1;
+    b.y[i] = i32();
+  }
+  for(var idx_2 : u32 = local_idx_1; (idx_2 < 32u); idx_2 = (idx_2 + (u32(X) * 6u))) {
+    let i_1 : u32 = idx_2;
+    c[i_1].x = i32();
+  }
+  for(var idx_3 : u32 = local_idx_1; (idx_3 < 256u); idx_3 = (idx_3 + (u32(X) * 6u))) {
+    let i_2 : u32 = (idx_3 / 8u);
+    let i : u32 = (idx_3 % 8u);
+    c[i_2].y[i] = i32();
+  }
+  workgroupBarrier();
+}
+
 struct S {
   x : i32,
   y : array<i32, 8>,
@@ -536,24 +593,7 @@
 
 @compute @workgroup_size(2, 3, X)
 fn f(@builtin(local_invocation_index) local_idx : u32) {
-  for(var idx : u32 = local_idx; (idx < 1u); idx = (idx + (u32(X) * 6u))) {
-    a = i32();
-    b.x = i32();
-  }
-  for(var idx_1 : u32 = local_idx; (idx_1 < 8u); idx_1 = (idx_1 + (u32(X) * 6u))) {
-    let i : u32 = idx_1;
-    b.y[i] = i32();
-  }
-  for(var idx_2 : u32 = local_idx; (idx_2 < 32u); idx_2 = (idx_2 + (u32(X) * 6u))) {
-    let i_1 : u32 = idx_2;
-    c[i_1].x = i32();
-  }
-  for(var idx_3 : u32 = local_idx; (idx_3 < 256u); idx_3 = (idx_3 + (u32(X) * 6u))) {
-    let i_2 : u32 = (idx_3 / 8u);
-    let i : u32 = (idx_3 % 8u);
-    c[i_2].y[i] = i32();
-  }
-  workgroupBarrier();
+  tint_zero_workgroup_memory(local_idx);
   _ = a;
   _ = b;
   _ = c;
@@ -590,6 +630,46 @@
 )";
     auto* expect =
         R"(
+fn tint_zero_workgroup_memory(local_idx_1 : u32) {
+  for(var idx : u32 = local_idx_1; (idx < 1u); idx = (idx + (X * 50u))) {
+    a = i32();
+  }
+  for(var idx_1 : u32 = local_idx_1; (idx_1 < 8u); idx_1 = (idx_1 + (X * 50u))) {
+    let i_1 : u32 = idx_1;
+    b.y[i_1] = i32();
+  }
+  for(var idx_2 : u32 = local_idx_1; (idx_2 < 80u); idx_2 = (idx_2 + (X * 50u))) {
+    let i : u32 = (idx_2 / 8u);
+    let i_1 : u32 = (idx_2 % 8u);
+    b.x[i][i_1] = i32();
+  }
+  for(var idx_3 : u32 = local_idx_1; (idx_3 < 256u); idx_3 = (idx_3 + (X * 50u))) {
+    let i_4 : u32 = (idx_3 / 8u);
+    let i_1 : u32 = (idx_3 % 8u);
+    c[i_4].y[i_1] = i32();
+  }
+  for(var idx_4 : u32 = local_idx_1; (idx_4 < 1600u); idx_4 = (idx_4 + (X * 50u))) {
+    let i_2 : u32 = (idx_4 / 80u);
+    let i : u32 = ((idx_4 % 80u) / 8u);
+    let i_1 : u32 = (idx_4 % 8u);
+    b.z[i_2][i][i_1] = i32();
+  }
+  for(var idx_5 : u32 = local_idx_1; (idx_5 < 2560u); idx_5 = (idx_5 + (X * 50u))) {
+    let i_3 : u32 = (idx_5 / 80u);
+    let i : u32 = ((idx_5 % 80u) / 8u);
+    let i_1 : u32 = (idx_5 % 8u);
+    c[i_3].x[i][i_1] = i32();
+  }
+  for(var idx_6 : u32 = local_idx_1; (idx_6 < 51200u); idx_6 = (idx_6 + (X * 50u))) {
+    let i_5 : u32 = (idx_6 / 1600u);
+    let i_2 : u32 = ((idx_6 % 1600u) / 80u);
+    let i : u32 = ((idx_6 % 80u) / 8u);
+    let i_1 : u32 = (idx_6 % 8u);
+    c[i_5].z[i_2][i][i_1] = i32();
+  }
+  workgroupBarrier();
+}
+
 struct S {
   x : array<array<i32, 8>, 10>,
   y : array<i32, 8>,
@@ -606,43 +686,7 @@
 
 @compute @workgroup_size(5u, X, 10u)
 fn f(@builtin(local_invocation_index) local_idx : u32) {
-  for(var idx : u32 = local_idx; (idx < 1u); idx = (idx + (X * 50u))) {
-    a = i32();
-  }
-  for(var idx_1 : u32 = local_idx; (idx_1 < 8u); idx_1 = (idx_1 + (X * 50u))) {
-    let i_1 : u32 = idx_1;
-    b.y[i_1] = i32();
-  }
-  for(var idx_2 : u32 = local_idx; (idx_2 < 80u); idx_2 = (idx_2 + (X * 50u))) {
-    let i : u32 = (idx_2 / 8u);
-    let i_1 : u32 = (idx_2 % 8u);
-    b.x[i][i_1] = i32();
-  }
-  for(var idx_3 : u32 = local_idx; (idx_3 < 256u); idx_3 = (idx_3 + (X * 50u))) {
-    let i_4 : u32 = (idx_3 / 8u);
-    let i_1 : u32 = (idx_3 % 8u);
-    c[i_4].y[i_1] = i32();
-  }
-  for(var idx_4 : u32 = local_idx; (idx_4 < 1600u); idx_4 = (idx_4 + (X * 50u))) {
-    let i_2 : u32 = (idx_4 / 80u);
-    let i : u32 = ((idx_4 % 80u) / 8u);
-    let i_1 : u32 = (idx_4 % 8u);
-    b.z[i_2][i][i_1] = i32();
-  }
-  for(var idx_5 : u32 = local_idx; (idx_5 < 2560u); idx_5 = (idx_5 + (X * 50u))) {
-    let i_3 : u32 = (idx_5 / 80u);
-    let i : u32 = ((idx_5 % 80u) / 8u);
-    let i_1 : u32 = (idx_5 % 8u);
-    c[i_3].x[i][i_1] = i32();
-  }
-  for(var idx_6 : u32 = local_idx; (idx_6 < 51200u); idx_6 = (idx_6 + (X * 50u))) {
-    let i_5 : u32 = (idx_6 / 1600u);
-    let i_2 : u32 = ((idx_6 % 1600u) / 80u);
-    let i : u32 = ((idx_6 % 80u) / 8u);
-    let i_1 : u32 = (idx_6 % 8u);
-    c[i_5].z[i_2][i][i_1] = i32();
-  }
-  workgroupBarrier();
+  tint_zero_workgroup_memory(local_idx);
   _ = a;
   _ = b;
   _ = c;
@@ -675,6 +719,27 @@
 }
 )";
     auto* expect = R"(
+fn tint_zero_workgroup_memory(local_idx : u32) {
+  {
+    a = i32();
+    b.x = i32();
+  }
+  for(var idx : u32 = local_idx; (idx < 8u); idx = (idx + 1u)) {
+    let i : u32 = idx;
+    b.y[i] = i32();
+  }
+  for(var idx_1 : u32 = local_idx; (idx_1 < 32u); idx_1 = (idx_1 + 1u)) {
+    let i_1 : u32 = idx_1;
+    c[i_1].x = i32();
+  }
+  for(var idx_2 : u32 = local_idx; (idx_2 < 256u); idx_2 = (idx_2 + 1u)) {
+    let i_2 : u32 = (idx_2 / 8u);
+    let i : u32 = (idx_2 % 8u);
+    c[i_2].y[i] = i32();
+  }
+  workgroupBarrier();
+}
+
 struct S {
   x : i32,
   y : array<i32, 8>,
@@ -688,24 +753,7 @@
 
 @compute @workgroup_size(1)
 fn f(@builtin(local_invocation_id) local_invocation_id : vec3<u32>, @builtin(local_invocation_index) local_invocation_index : u32) {
-  {
-    a = i32();
-    b.x = i32();
-  }
-  for(var idx : u32 = local_invocation_index; (idx < 8u); idx = (idx + 1u)) {
-    let i : u32 = idx;
-    b.y[i] = i32();
-  }
-  for(var idx_1 : u32 = local_invocation_index; (idx_1 < 32u); idx_1 = (idx_1 + 1u)) {
-    let i_1 : u32 = idx_1;
-    c[i_1].x = i32();
-  }
-  for(var idx_2 : u32 = local_invocation_index; (idx_2 < 256u); idx_2 = (idx_2 + 1u)) {
-    let i_2 : u32 = (idx_2 / 8u);
-    let i : u32 = (idx_2 % 8u);
-    c[i_2].y[i] = i32();
-  }
-  workgroupBarrier();
+  tint_zero_workgroup_memory(local_invocation_index);
   _ = a;
   _ = b;
   _ = c;
@@ -738,26 +786,30 @@
 };
 )";
     auto* expect = R"(
-@compute @workgroup_size(1)
-fn f(@builtin(local_invocation_id) local_invocation_id : vec3<u32>, @builtin(local_invocation_index) local_invocation_index : u32) {
+fn tint_zero_workgroup_memory(local_idx : u32) {
   {
     a = i32();
     b.x = i32();
   }
-  for(var idx : u32 = local_invocation_index; (idx < 8u); idx = (idx + 1u)) {
+  for(var idx : u32 = local_idx; (idx < 8u); idx = (idx + 1u)) {
     let i : u32 = idx;
     b.y[i] = i32();
   }
-  for(var idx_1 : u32 = local_invocation_index; (idx_1 < 32u); idx_1 = (idx_1 + 1u)) {
+  for(var idx_1 : u32 = local_idx; (idx_1 < 32u); idx_1 = (idx_1 + 1u)) {
     let i_1 : u32 = idx_1;
     c[i_1].x = i32();
   }
-  for(var idx_2 : u32 = local_invocation_index; (idx_2 < 256u); idx_2 = (idx_2 + 1u)) {
+  for(var idx_2 : u32 = local_idx; (idx_2 < 256u); idx_2 = (idx_2 + 1u)) {
     let i_2 : u32 = (idx_2 / 8u);
     let i : u32 = (idx_2 % 8u);
     c[i_2].y[i] = i32();
   }
   workgroupBarrier();
+}
+
+@compute @workgroup_size(1)
+fn f(@builtin(local_invocation_id) local_invocation_id : vec3<u32>, @builtin(local_invocation_index) local_invocation_index : u32) {
+  tint_zero_workgroup_memory(local_invocation_index);
   _ = a;
   _ = b;
   _ = c;
@@ -811,6 +863,49 @@
 }
 )";
     auto* expect = R"(
+fn tint_zero_workgroup_memory(local_idx : u32) {
+  {
+    a = i32();
+  }
+  for(var idx : u32 = local_idx; (idx < 32u); idx = (idx + 1u)) {
+    let i : u32 = idx;
+    c[i].x = i32();
+  }
+  for(var idx_1 : u32 = local_idx; (idx_1 < 256u); idx_1 = (idx_1 + 1u)) {
+    let i_1 : u32 = (idx_1 / 8u);
+    let i_2 : u32 = (idx_1 % 8u);
+    c[i_1].y[i_2] = i32();
+  }
+  workgroupBarrier();
+}
+
+fn tint_zero_workgroup_memory_1(local_idx_1 : u32) {
+  if ((local_idx_1 < 1u)) {
+    b.x = i32();
+  }
+  for(var idx_2 : u32 = local_idx_1; (idx_2 < 8u); idx_2 = (idx_2 + 6u)) {
+    let i_3 : u32 = idx_2;
+    b.y[i_3] = i32();
+  }
+  workgroupBarrier();
+}
+
+fn tint_zero_workgroup_memory_2(local_idx_2 : u32) {
+  if ((local_idx_2 < 1u)) {
+    a = i32();
+  }
+  if ((local_idx_2 < 32u)) {
+    let i_4 : u32 = local_idx_2;
+    c[i_4].x = i32();
+  }
+  for(var idx_3 : u32 = local_idx_2; (idx_3 < 256u); idx_3 = (idx_3 + 120u)) {
+    let i_5 : u32 = (idx_3 / 8u);
+    let i_6 : u32 = (idx_3 % 8u);
+    c[i_5].y[i_6] = i32();
+  }
+  workgroupBarrier();
+}
+
 struct S {
   x : i32,
   y : array<i32, 8>,
@@ -824,51 +919,20 @@
 
 @compute @workgroup_size(1)
 fn f1(@builtin(local_invocation_index) local_invocation_index : u32) {
-  {
-    a = i32();
-  }
-  for(var idx : u32 = local_invocation_index; (idx < 32u); idx = (idx + 1u)) {
-    let i : u32 = idx;
-    c[i].x = i32();
-  }
-  for(var idx_1 : u32 = local_invocation_index; (idx_1 < 256u); idx_1 = (idx_1 + 1u)) {
-    let i_1 : u32 = (idx_1 / 8u);
-    let i_2 : u32 = (idx_1 % 8u);
-    c[i_1].y[i_2] = i32();
-  }
-  workgroupBarrier();
+  tint_zero_workgroup_memory(local_invocation_index);
   _ = a;
   _ = c;
 }
 
 @compute @workgroup_size(1, 2, 3)
 fn f2(@builtin(local_invocation_id) local_invocation_id : vec3<u32>, @builtin(local_invocation_index) local_invocation_index_1 : u32) {
-  if ((local_invocation_index_1 < 1u)) {
-    b.x = i32();
-  }
-  for(var idx_2 : u32 = local_invocation_index_1; (idx_2 < 8u); idx_2 = (idx_2 + 6u)) {
-    let i_3 : u32 = idx_2;
-    b.y[i_3] = i32();
-  }
-  workgroupBarrier();
+  tint_zero_workgroup_memory_1(local_invocation_index_1);
   _ = b;
 }
 
 @compute @workgroup_size(4, 5, 6)
 fn f3(@builtin(local_invocation_index) local_invocation_index_2 : u32) {
-  if ((local_invocation_index_2 < 1u)) {
-    a = i32();
-  }
-  if ((local_invocation_index_2 < 32u)) {
-    let i_4 : u32 = local_invocation_index_2;
-    c[i_4].x = i32();
-  }
-  for(var idx_3 : u32 = local_invocation_index_2; (idx_3 < 256u); idx_3 = (idx_3 + 120u)) {
-    let i_5 : u32 = (idx_3 / 8u);
-    let i_6 : u32 = (idx_3 % 8u);
-    c[i_5].y[i_6] = i32();
-  }
-  workgroupBarrier();
+  tint_zero_workgroup_memory_2(local_invocation_index_2);
   _ = c;
   _ = a;
 }
@@ -910,53 +974,65 @@
 };
 )";
     auto* expect = R"(
-@compute @workgroup_size(1)
-fn f1(@builtin(local_invocation_index) local_invocation_index : u32) {
+fn tint_zero_workgroup_memory(local_idx : u32) {
   {
     a = i32();
   }
-  for(var idx : u32 = local_invocation_index; (idx < 32u); idx = (idx + 1u)) {
+  for(var idx : u32 = local_idx; (idx < 32u); idx = (idx + 1u)) {
     let i : u32 = idx;
     c[i].x = i32();
   }
-  for(var idx_1 : u32 = local_invocation_index; (idx_1 < 256u); idx_1 = (idx_1 + 1u)) {
+  for(var idx_1 : u32 = local_idx; (idx_1 < 256u); idx_1 = (idx_1 + 1u)) {
     let i_1 : u32 = (idx_1 / 8u);
     let i_2 : u32 = (idx_1 % 8u);
     c[i_1].y[i_2] = i32();
   }
   workgroupBarrier();
+}
+
+fn tint_zero_workgroup_memory_1(local_idx_1 : u32) {
+  if ((local_idx_1 < 1u)) {
+    b.x = i32();
+  }
+  for(var idx_2 : u32 = local_idx_1; (idx_2 < 8u); idx_2 = (idx_2 + 6u)) {
+    let i_3 : u32 = idx_2;
+    b.y[i_3] = i32();
+  }
+  workgroupBarrier();
+}
+
+fn tint_zero_workgroup_memory_2(local_idx_2 : u32) {
+  if ((local_idx_2 < 1u)) {
+    a = i32();
+  }
+  if ((local_idx_2 < 32u)) {
+    let i_4 : u32 = local_idx_2;
+    c[i_4].x = i32();
+  }
+  for(var idx_3 : u32 = local_idx_2; (idx_3 < 256u); idx_3 = (idx_3 + 120u)) {
+    let i_5 : u32 = (idx_3 / 8u);
+    let i_6 : u32 = (idx_3 % 8u);
+    c[i_5].y[i_6] = i32();
+  }
+  workgroupBarrier();
+}
+
+@compute @workgroup_size(1)
+fn f1(@builtin(local_invocation_index) local_invocation_index : u32) {
+  tint_zero_workgroup_memory(local_invocation_index);
   _ = a;
   _ = c;
 }
 
 @compute @workgroup_size(1, 2, 3)
 fn f2(@builtin(local_invocation_id) local_invocation_id : vec3<u32>, @builtin(local_invocation_index) local_invocation_index_1 : u32) {
-  if ((local_invocation_index_1 < 1u)) {
-    b.x = i32();
-  }
-  for(var idx_2 : u32 = local_invocation_index_1; (idx_2 < 8u); idx_2 = (idx_2 + 6u)) {
-    let i_3 : u32 = idx_2;
-    b.y[i_3] = i32();
-  }
-  workgroupBarrier();
+  tint_zero_workgroup_memory_1(local_invocation_index_1);
   _ = b;
 }
 
 @compute @workgroup_size(4, 5, 6)
 fn f3(@builtin(local_invocation_index) local_invocation_index_2 : u32) {
-  if ((local_invocation_index_2 < 1u)) {
-    a = i32();
-  }
-  if ((local_invocation_index_2 < 32u)) {
-    let i_4 : u32 = local_invocation_index_2;
-    c[i_4].x = i32();
-  }
-  for(var idx_3 : u32 = local_invocation_index_2; (idx_3 < 256u); idx_3 = (idx_3 + 120u)) {
-    let i_5 : u32 = (idx_3 / 8u);
-    let i_6 : u32 = (idx_3 % 8u);
-    c[i_5].y[i_6] = i32();
-  }
-  workgroupBarrier();
+  tint_zero_workgroup_memory_2(local_invocation_index_2);
   _ = c;
   _ = a;
 }
@@ -996,6 +1072,13 @@
 }
 )";
     auto* expect = R"(
+fn tint_zero_workgroup_memory(local_idx_1 : u32) {
+  {
+    v = i32();
+  }
+  workgroupBarrier();
+}
+
 var<workgroup> v : i32;
 
 fn use_v() {
@@ -1008,10 +1091,7 @@
 
 @compute @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_idx : u32) {
-  {
-    v = i32();
-  }
-  workgroupBarrier();
+  tint_zero_workgroup_memory(local_idx);
   call_use_v();
 }
 )";
@@ -1039,12 +1119,16 @@
 var<workgroup> v : i32;
 )";
     auto* expect = R"(
-@compute @workgroup_size(1)
-fn f(@builtin(local_invocation_index) local_idx : u32) {
+fn tint_zero_workgroup_memory(local_idx_1 : u32) {
   {
     v = i32();
   }
   workgroupBarrier();
+}
+
+@compute @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_idx : u32) {
+  tint_zero_workgroup_memory(local_idx);
   call_use_v();
 }
 
@@ -1076,17 +1160,21 @@
 }
 )";
     auto* expect = R"(
+fn tint_zero_workgroup_memory(local_idx : u32) {
+  {
+    atomicStore(&(i), i32());
+    atomicStore(&(u), u32());
+  }
+  workgroupBarrier();
+}
+
 var<workgroup> i : atomic<i32>;
 
 var<workgroup> u : atomic<u32>;
 
 @compute @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
-  {
-    atomicStore(&(i), i32());
-    atomicStore(&(u), u32());
-  }
-  workgroupBarrier();
+  tint_zero_workgroup_memory(local_invocation_index);
   atomicLoad(&(i));
   atomicLoad(&(u));
 }
@@ -1109,13 +1197,17 @@
 var<workgroup> u : atomic<u32>;
 )";
     auto* expect = R"(
-@compute @workgroup_size(1)
-fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+fn tint_zero_workgroup_memory(local_idx : u32) {
   {
     atomicStore(&(i), i32());
     atomicStore(&(u), u32());
   }
   workgroupBarrier();
+}
+
+@compute @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+  tint_zero_workgroup_memory(local_invocation_index);
   atomicLoad(&(i));
   atomicLoad(&(u));
 }
@@ -1148,6 +1240,17 @@
 }
 )";
     auto* expect = R"(
+fn tint_zero_workgroup_memory(local_idx : u32) {
+  {
+    w.a = i32();
+    atomicStore(&(w.i), i32());
+    w.b = f32();
+    atomicStore(&(w.u), u32());
+    w.c = u32();
+  }
+  workgroupBarrier();
+}
+
 struct S {
   a : i32,
   i : atomic<i32>,
@@ -1160,14 +1263,7 @@
 
 @compute @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
-  {
-    w.a = i32();
-    atomicStore(&(w.i), i32());
-    w.b = f32();
-    atomicStore(&(w.u), u32());
-    w.c = u32();
-  }
-  workgroupBarrier();
+  tint_zero_workgroup_memory(local_invocation_index);
   _ = w.a;
 }
 )";
@@ -1195,8 +1291,7 @@
 };
 )";
     auto* expect = R"(
-@compute @workgroup_size(1)
-fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+fn tint_zero_workgroup_memory(local_idx : u32) {
   {
     w.a = i32();
     atomicStore(&(w.i), i32());
@@ -1205,6 +1300,11 @@
     w.c = u32();
   }
   workgroupBarrier();
+}
+
+@compute @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+  tint_zero_workgroup_memory(local_invocation_index);
   _ = w.a;
 }
 
@@ -1234,15 +1334,19 @@
 }
 )";
     auto* expect = R"(
-var<workgroup> w : array<atomic<u32>, 4>;
-
-@compute @workgroup_size(1)
-fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
-  for(var idx : u32 = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+fn tint_zero_workgroup_memory(local_idx : u32) {
+  for(var idx : u32 = local_idx; (idx < 4u); idx = (idx + 1u)) {
     let i : u32 = idx;
     atomicStore(&(w[i]), u32());
   }
   workgroupBarrier();
+}
+
+var<workgroup> w : array<atomic<u32>, 4>;
+
+@compute @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+  tint_zero_workgroup_memory(local_invocation_index);
   atomicLoad(&(w[0]));
 }
 )";
@@ -1262,13 +1366,17 @@
 var<workgroup> w : array<atomic<u32>, 4>;
 )";
     auto* expect = R"(
-@compute @workgroup_size(1)
-fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
-  for(var idx : u32 = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+fn tint_zero_workgroup_memory(local_idx : u32) {
+  for(var idx : u32 = local_idx; (idx < 4u); idx = (idx + 1u)) {
     let i : u32 = idx;
     atomicStore(&(w[i]), u32());
   }
   workgroupBarrier();
+}
+
+@compute @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+  tint_zero_workgroup_memory(local_invocation_index);
   atomicLoad(&(w[0]));
 }
 
@@ -1298,6 +1406,18 @@
 }
 )";
     auto* expect = R"(
+fn tint_zero_workgroup_memory(local_idx : u32) {
+  for(var idx : u32 = local_idx; (idx < 4u); idx = (idx + 1u)) {
+    let i_1 : u32 = idx;
+    w[i_1].a = i32();
+    atomicStore(&(w[i_1].i), i32());
+    w[i_1].b = f32();
+    atomicStore(&(w[i_1].u), u32());
+    w[i_1].c = u32();
+  }
+  workgroupBarrier();
+}
+
 struct S {
   a : i32,
   i : atomic<i32>,
@@ -1310,15 +1430,7 @@
 
 @compute @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
-  for(var idx : u32 = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
-    let i_1 : u32 = idx;
-    w[i_1].a = i32();
-    atomicStore(&(w[i_1].i), i32());
-    w[i_1].b = f32();
-    atomicStore(&(w[i_1].u), u32());
-    w[i_1].c = u32();
-  }
-  workgroupBarrier();
+  tint_zero_workgroup_memory(local_invocation_index);
   _ = w[0].a;
 }
 )";
@@ -1346,9 +1458,8 @@
 };
 )";
     auto* expect = R"(
-@compute @workgroup_size(1)
-fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
-  for(var idx : u32 = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
+fn tint_zero_workgroup_memory(local_idx : u32) {
+  for(var idx : u32 = local_idx; (idx < 4u); idx = (idx + 1u)) {
     let i_1 : u32 = idx;
     w[i_1].a = i32();
     atomicStore(&(w[i_1].i), i32());
@@ -1357,6 +1468,11 @@
     w[i_1].c = u32();
   }
   workgroupBarrier();
+}
+
+@compute @workgroup_size(1)
+fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
+  tint_zero_workgroup_memory(local_invocation_index);
   _ = w[0].a;
 }
 
@@ -1399,5 +1515,38 @@
     EXPECT_EQ(expect, str(got));
 }
 
+TEST_F(ZeroInitWorkgroupMemoryTest, AliasTypeWithParamName) {
+    auto* src =
+        R"(
+var<workgroup> W : mat2x2<f32>;
+
+@compute @workgroup_size(1) fn F(@builtin(local_invocation_index) mat2x2 : u32) {
+  W[0]+=0;
+}
+)";
+
+    auto* expect =
+        R"(
+fn tint_zero_workgroup_memory(local_idx : u32) {
+  {
+    W = mat2x2<f32>();
+  }
+  workgroupBarrier();
+}
+
+var<workgroup> W : mat2x2<f32>;
+
+@compute @workgroup_size(1)
+fn F(@builtin(local_invocation_index) mat2x2 : u32) {
+  tint_zero_workgroup_memory(mat2x2);
+  W[0] += 0;
+}
+)";
+
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
 }  // namespace
 }  // namespace tint::ast::transform
diff --git a/src/tint/lang/wgsl/common/allowed_features.h b/src/tint/lang/wgsl/common/allowed_features.h
index 7549fc7..9673103 100644
--- a/src/tint/lang/wgsl/common/allowed_features.h
+++ b/src/tint/lang/wgsl/common/allowed_features.h
@@ -63,9 +63,12 @@
     }
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField().
-    TINT_REFLECT(extensions, features);
+    TINT_REFLECT(AllowedFeatures, extensions, features);
 };
 
+/// Ensure that all the fields of AllowedFeatures are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(AllowedFeatures);
+
 }  // namespace tint::wgsl
 
 #endif  // SRC_TINT_LANG_WGSL_COMMON_ALLOWED_FEATURES_H_
diff --git a/src/tint/lang/wgsl/features/status.cc b/src/tint/lang/wgsl/features/status.cc
index 2f592a1..22fd78e 100644
--- a/src/tint/lang/wgsl/features/status.cc
+++ b/src/tint/lang/wgsl/features/status.cc
@@ -36,7 +36,6 @@
             ////////////////////////////////////////////////////////////////////
             // Experimental features
             ///////////////////////////////////////////////////////////////////
-        case LanguageFeature::kPointerCompositeAccess:
         case LanguageFeature::kReadonlyAndReadwriteStorageTextures:
             return FeatureStatus::kExperimental;
 
@@ -44,6 +43,7 @@
             // Enabled features
             ////////////////////////////////////////////////////////////////////
         case LanguageFeature::kPacked4X8IntegerDotProduct:
+        case LanguageFeature::kPointerCompositeAccess:
         case LanguageFeature::kUnrestrictedPointerParameters:
             return FeatureStatus::kShippedWithKillswitch;
 
diff --git a/src/tint/lang/wgsl/helpers/check_supported_extensions.cc b/src/tint/lang/wgsl/helpers/check_supported_extensions.cc
index 4ab0f84..bb35e15 100644
--- a/src/tint/lang/wgsl/helpers/check_supported_extensions.cc
+++ b/src/tint/lang/wgsl/helpers/check_supported_extensions.cc
@@ -48,10 +48,10 @@
     for (auto* enable : module.Enables()) {
         for (auto* ext : enable->extensions) {
             if (!set.Contains(ext->name)) {
-                diags.add_error(diag::System::Writer,
-                                std::string(writer_name) + " backend does not support extension '" +
-                                    tint::ToString(ext->name) + "'",
-                                ext->source);
+                diags.AddError(diag::System::Writer,
+                               std::string(writer_name) + " backend does not support extension '" +
+                                   tint::ToString(ext->name) + "'",
+                               ext->source);
                 return false;
             }
         }
diff --git a/src/tint/lang/wgsl/helpers/check_supported_extensions_test.cc b/src/tint/lang/wgsl/helpers/check_supported_extensions_test.cc
index 415f32c..6d8252d 100644
--- a/src/tint/lang/wgsl/helpers/check_supported_extensions_test.cc
+++ b/src/tint/lang/wgsl/helpers/check_supported_extensions_test.cc
@@ -53,7 +53,7 @@
                                           Vector{
                                               wgsl::Extension::kChromiumExperimentalSubgroups,
                                           }));
-    EXPECT_EQ(Diagnostics().str(), "12:34 error: writer backend does not support extension 'f16'");
+    EXPECT_EQ(Diagnostics().Str(), "12:34 error: writer backend does not support extension 'f16'");
 }
 
 }  // namespace
diff --git a/src/tint/lang/wgsl/inspector/entry_point.h b/src/tint/lang/wgsl/inspector/entry_point.h
index 24164d0..3709ade 100644
--- a/src/tint/lang/wgsl/inspector/entry_point.h
+++ b/src/tint/lang/wgsl/inspector/entry_point.h
@@ -165,6 +165,8 @@
     std::optional<WorkgroupSize> workgroup_size;
     /// The total size in bytes of all Workgroup storage-class storage accessed via the entry point.
     uint32_t workgroup_storage_size = 0;
+    /// The total size in bytes of all push_constant variables accessed by the entry point.
+    uint32_t push_constant_size = 0;
     /// List of the input variable accessed via this entry point.
     std::vector<StageVariable> input_variables;
     /// List of the output variable accessed via this entry point.
diff --git a/src/tint/lang/wgsl/inspector/inspector.cc b/src/tint/lang/wgsl/inspector/inspector.cc
index e6c2b44..8efa350 100644
--- a/src/tint/lang/wgsl/inspector/inspector.cc
+++ b/src/tint/lang/wgsl/inspector/inspector.cc
@@ -174,6 +174,8 @@
         }
     }
 
+    entry_point.push_constant_size = ComputePushConstantSize(func);
+
     for (auto* param : sem->Parameters()) {
         AddEntryPointInOutVariables(param->Declaration()->name->symbol.Name(),
                                     param->Declaration()->name->symbol.Name(), param->Type(),
@@ -569,12 +571,12 @@
 const ast::Function* Inspector::FindEntryPointByName(const std::string& name) {
     auto* func = program_.AST().Functions().Find(program_.Symbols().Get(name));
     if (!func) {
-        diagnostics_.add_error(diag::System::Inspector, name + " was not found!");
+        diagnostics_.AddError(diag::System::Inspector, name + " was not found!");
         return nullptr;
     }
 
     if (!func->IsEntryPoint()) {
-        diagnostics_.add_error(diag::System::Inspector, name + " is not an entry point!");
+        diagnostics_.AddError(diag::System::Inspector, name + " is not an entry point!");
         return nullptr;
     }
 
@@ -927,6 +929,18 @@
     return total_size;
 }
 
+uint32_t Inspector::ComputePushConstantSize(const ast::Function* func) const {
+    uint32_t size = 0;
+    auto* func_sem = program_.Sem().Get(func);
+    for (const sem::Variable* var : func_sem->TransitivelyReferencedGlobals()) {
+        if (var->AddressSpace() == core::AddressSpace::kPushConstant) {
+            size += var->Type()->UnwrapRef()->Size();
+        }
+    }
+
+    return size;
+}
+
 std::vector<PixelLocalMemberType> Inspector::ComputePixelLocalMemberTypes(
     const ast::Function* func) const {
     auto* func_sem = program_.Sem().Get(func);
diff --git a/src/tint/lang/wgsl/inspector/inspector.h b/src/tint/lang/wgsl/inspector/inspector.h
index 6604832..736b2da 100644
--- a/src/tint/lang/wgsl/inspector/inspector.h
+++ b/src/tint/lang/wgsl/inspector/inspector.h
@@ -62,9 +62,9 @@
     ~Inspector();
 
     /// @returns error messages from the Inspector
-    std::string error() { return diagnostics_.str(); }
+    std::string error() { return diagnostics_.Str(); }
     /// @returns true if an error was encountered
-    bool has_error() const { return diagnostics_.contains_errors(); }
+    bool has_error() const { return diagnostics_.ContainsErrors(); }
 
     /// @returns vector of entry point information
     std::vector<EntryPoint> GetEntryPoints();
@@ -264,6 +264,10 @@
     /// @returns the total size in bytes of all Workgroup storage-class storage accessed via func.
     uint32_t ComputeWorkgroupStorageSize(const ast::Function* func) const;
 
+    /// @param func the root function of the callgraph to consider for the computation.
+    /// @returns the total size in bytes of all push_constant variables accessed via func.
+    uint32_t ComputePushConstantSize(const ast::Function* func) const;
+
     /// @param func the root function of the callgraph to consider for the computation
     /// @returns the list of member types for the `pixel_local` variable accessed via func, if any.
     std::vector<PixelLocalMemberType> ComputePixelLocalMemberTypes(const ast::Function* func) const;
diff --git a/src/tint/lang/wgsl/inspector/inspector_test.cc b/src/tint/lang/wgsl/inspector/inspector_test.cc
index e3d97bb..8d1a4b3 100644
--- a/src/tint/lang/wgsl/inspector/inspector_test.cc
+++ b/src/tint/lang/wgsl/inspector/inspector_test.cc
@@ -258,6 +258,85 @@
     EXPECT_EQ(1u, workgroup_size->z);
 }
 
+// Test that push_constant_size is zero if there are no push constants.
+TEST_F(InspectorGetEntryPointTest, PushConstantSizeNone) {
+    MakeEmptyBodyFunction("foo", Vector{
+                                     Stage(ast::PipelineStage::kFragment),
+                                 });
+
+    Inspector& inspector = Build();
+
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(0u, result[0].push_constant_size);
+}
+
+// Test that push_constant_size is 4 (bytes) if there is a single F32 push constant.
+TEST_F(InspectorGetEntryPointTest, PushConstantSizeOneWord) {
+    Enable(wgsl::Extension::kChromiumExperimentalPushConstant);
+    GlobalVar("pc", core::AddressSpace::kPushConstant, ty.f32());
+    MakePlainGlobalReferenceBodyFunction("foo", "pc", ty.f32(),
+                                         Vector{
+                                             Stage(ast::PipelineStage::kFragment),
+                                         });
+
+    Inspector& inspector = Build();
+
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(4u, result[0].push_constant_size);
+}
+
+// Test that push_constant_size is 12 (bytes) if there is a struct containing one
+// each of i32, f32 and u32.
+TEST_F(InspectorGetEntryPointTest, PushConstantSizeThreeWords) {
+    Enable(wgsl::Extension::kChromiumExperimentalPushConstant);
+    auto* pc_struct_type =
+        MakeStructType("PushConstantStruct", Vector{ty.i32(), ty.f32(), ty.u32()});
+    GlobalVar("pc", core::AddressSpace::kPushConstant, ty.Of(pc_struct_type));
+    MakePlainGlobalReferenceBodyFunction("foo", "pc", ty.Of(pc_struct_type),
+                                         Vector{
+                                             Stage(ast::PipelineStage::kFragment),
+                                         });
+
+    Inspector& inspector = Build();
+
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(12u, result[0].push_constant_size);
+}
+
+// Test that push_constant_size is 4 (bytes) if there are two push constants,
+// one used by the entry point containing an f32, and one unused by the entry
+// point containing a struct of size 12 bytes.
+TEST_F(InspectorGetEntryPointTest, PushConstantSizeTwoConstants) {
+    Enable(wgsl::Extension::kChromiumExperimentalPushConstant);
+    auto* unused_struct_type =
+        MakeStructType("PushConstantStruct", Vector{ty.i32(), ty.f32(), ty.u32()});
+    GlobalVar("unused", core::AddressSpace::kPushConstant, ty.Of(unused_struct_type));
+    GlobalVar("pc", core::AddressSpace::kPushConstant, ty.f32());
+    MakePlainGlobalReferenceBodyFunction("foo", "pc", ty.f32(),
+                                         Vector{
+                                             Stage(ast::PipelineStage::kFragment),
+                                         });
+
+    Inspector& inspector = Build();
+
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+
+    ASSERT_EQ(1u, result.size());
+
+    // Check that the result only includes the single f32 push constant.
+    EXPECT_EQ(4u, result[0].push_constant_size);
+}
+
 TEST_F(InspectorGetEntryPointTest, NonDefaultWorkgroupSize) {
     MakeEmptyBodyFunction("foo", Vector{
                                      Stage(ast::PipelineStage::kCompute),
diff --git a/src/tint/lang/wgsl/intrinsic/data.cc b/src/tint/lang/wgsl/intrinsic/data.cc
index 8266687..5114e2d 100644
--- a/src/tint/lang/wgsl/intrinsic/data.cc
+++ b/src/tint/lang/wgsl/intrinsic/data.cc
@@ -4168,39 +4168,39 @@
   },
   {
     /* [350] */
+    /* usage */ core::ParameterUsage::kValue,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
+    /* [351] */
+    /* usage */ core::ParameterUsage::kSourceLaneIndex,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+  },
+  {
+    /* [352] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [351] */
+    /* [353] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
   },
   {
-    /* [352] */
+    /* [354] */
     /* 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 */),
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
   },
   {
     /* [356] */
@@ -4211,335 +4211,347 @@
   {
     /* [357] */
     /* usage */ core::ParameterUsage::kNone,
-    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
-    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
     /* [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),
   },
   {
+    /* [359] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
+  },
+  {
     /* [360] */
     /* usage */ core::ParameterUsage::kNone,
-    /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
-    /* number_matcher_indices */ NumberMatcherIndicesIndex(22),
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(3),
   },
   {
     /* [361] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
-    /* number_matcher_indices */ NumberMatcherIndicesIndex(3),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
   },
   {
     /* [362] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(22),
+  },
+  {
+    /* [363] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* number_matcher_indices */ NumberMatcherIndicesIndex(3),
+  },
+  {
+    /* [364] */
     /* usage */ core::ParameterUsage::kXy,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(74),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [363] */
+    /* [365] */
     /* usage */ core::ParameterUsage::kZw,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(74),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [364] */
+    /* [366] */
     /* usage */ core::ParameterUsage::kXyz,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [365] */
+    /* [367] */
     /* usage */ core::ParameterUsage::kW,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [366] */
+    /* [368] */
     /* usage */ core::ParameterUsage::kX,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(2),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [367] */
+    /* [369] */
     /* usage */ core::ParameterUsage::kZyw,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(10),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [368] */
+    /* [370] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(0),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(0),
   },
   {
-    /* [369] */
+    /* [371] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(12),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
   },
   {
-    /* [370] */
+    /* [372] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(15),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [371] */
+    /* [373] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(14),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(1),
   },
   {
-    /* [372] */
+    /* [374] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(26),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [373] */
+    /* [375] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(28),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [374] */
+    /* [376] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(30),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [375] */
+    /* [377] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(32),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [376] */
+    /* [378] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(34),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(6),
   },
   {
-    /* [377] */
+    /* [379] */
     /* usage */ core::ParameterUsage::kTexture,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(165),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
   },
   {
-    /* [378] */
+    /* [380] */
     /* usage */ core::ParameterUsage::kTexture,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(166),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
   },
   {
-    /* [379] */
+    /* [381] */
     /* usage */ core::ParameterUsage::kTexture,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(167),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
   },
   {
-    /* [380] */
+    /* [382] */
     /* usage */ core::ParameterUsage::kTexture,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(168),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(2),
   },
   {
-    /* [381] */
+    /* [383] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(31),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [382] */
+    /* [384] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(87),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [383] */
+    /* [385] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(76),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [384] */
+    /* [386] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(78),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [385] */
+    /* [387] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(98),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [386] */
+    /* [388] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(104),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [387] */
+    /* [389] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(108),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [388] */
+    /* [390] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(106),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [389] */
+    /* [391] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(110),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [390] */
+    /* [392] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(114),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [391] */
+    /* [393] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(112),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [392] */
+    /* [394] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(116),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [393] */
+    /* [395] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(120),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [394] */
+    /* [396] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(118),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [395] */
+    /* [397] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(122),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [396] */
+    /* [398] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(126),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [397] */
+    /* [399] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(124),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [398] */
+    /* [400] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(128),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [399] */
+    /* [401] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(132),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [400] */
+    /* [402] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(130),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [401] */
+    /* [403] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(134),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [402] */
+    /* [404] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(138),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [403] */
+    /* [405] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(136),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [404] */
+    /* [406] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(140),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [405] */
+    /* [407] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(144),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [406] */
+    /* [408] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(142),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [407] */
+    /* [409] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(146),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [408] */
+    /* [410] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(150),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [409] */
+    /* [411] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(148),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [410] */
+    /* [412] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(152),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [411] */
+    /* [413] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(156),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
   },
   {
-    /* [412] */
+    /* [414] */
     /* usage */ core::ParameterUsage::kNone,
     /* type_matcher_indices */ TypeMatcherIndicesIndex(154),
     /* number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
@@ -5210,7 +5222,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(6),
-    /* parameters */ ParameterIndex(377),
+    /* parameters */ ParameterIndex(379),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -5223,7 +5235,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(6),
-    /* parameters */ ParameterIndex(378),
+    /* parameters */ ParameterIndex(380),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(38),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -5236,7 +5248,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(6),
-    /* parameters */ ParameterIndex(379),
+    /* parameters */ ParameterIndex(381),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(38),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -5249,7 +5261,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(6),
-    /* parameters */ ParameterIndex(380),
+    /* parameters */ ParameterIndex(382),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(44),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -5652,7 +5664,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(27),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(362),
+    /* parameters */ ParameterIndex(364),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(54),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(110),
@@ -5665,7 +5677,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(27),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(364),
+    /* parameters */ ParameterIndex(366),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(54),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(110),
@@ -5678,7 +5690,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(27),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(366),
+    /* parameters */ ParameterIndex(368),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(54),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(110),
@@ -5691,7 +5703,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(385),
+    /* parameters */ ParameterIndex(387),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(28),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -5704,7 +5716,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(385),
+    /* parameters */ ParameterIndex(387),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(100),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -5717,7 +5729,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(18),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(385),
+    /* parameters */ ParameterIndex(387),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(30),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -5730,7 +5742,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(20),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(385),
+    /* parameters */ ParameterIndex(387),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(32),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -5743,7 +5755,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(22),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(385),
+    /* parameters */ ParameterIndex(387),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(102),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -6536,7 +6548,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(384),
+    /* parameters */ ParameterIndex(386),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(58),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -6549,7 +6561,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(384),
+    /* parameters */ ParameterIndex(386),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(92),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -6562,7 +6574,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(18),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(384),
+    /* parameters */ ParameterIndex(386),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(68),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -6575,7 +6587,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(20),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(384),
+    /* parameters */ ParameterIndex(386),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(44),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -6588,7 +6600,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(22),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(384),
+    /* parameters */ ParameterIndex(386),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(94),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -6796,7 +6808,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(383),
+    /* parameters */ ParameterIndex(385),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(26),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -6809,7 +6821,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(383),
+    /* parameters */ ParameterIndex(385),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(86),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -6822,7 +6834,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(18),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(383),
+    /* parameters */ ParameterIndex(385),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(56),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -6835,7 +6847,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(20),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(383),
+    /* parameters */ ParameterIndex(385),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(38),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -6848,7 +6860,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(22),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(383),
+    /* parameters */ ParameterIndex(385),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(88),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -6900,7 +6912,7 @@
     /* num_template_numbers */ 1,
     /* template_types */ TemplateTypeIndex(24),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(350),
+    /* parameters */ ParameterIndex(352),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(87),
@@ -6913,7 +6925,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(10),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(355),
+    /* parameters */ ParameterIndex(357),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(2),
     /* const_eval_fn */ ConstEvalFunctionIndex(87),
@@ -6926,7 +6938,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(10),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(354),
+    /* parameters */ ParameterIndex(356),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(2),
     /* const_eval_fn */ ConstEvalFunctionIndex(87),
@@ -6939,7 +6951,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(10),
     /* template_numbers */ TemplateNumberIndex(1),
-    /* parameters */ ParameterIndex(356),
+    /* parameters */ ParameterIndex(358),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(3),
     /* const_eval_fn */ ConstEvalFunctionIndex(88),
@@ -6952,7 +6964,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(10),
     /* template_numbers */ TemplateNumberIndex(1),
-    /* parameters */ ParameterIndex(358),
+    /* parameters */ ParameterIndex(360),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(89),
@@ -6965,7 +6977,7 @@
     /* num_template_numbers */ 3,
     /* template_types */ TemplateTypeIndex(10),
     /* template_numbers */ TemplateNumberIndex(0),
-    /* parameters */ ParameterIndex(360),
+    /* parameters */ ParameterIndex(362),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(20),
     /* const_eval_fn */ ConstEvalFunctionIndex(90),
@@ -7433,7 +7445,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(386),
+    /* parameters */ ParameterIndex(388),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(104),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(81),
@@ -7472,7 +7484,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(387),
+    /* parameters */ ParameterIndex(389),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(106),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -7485,7 +7497,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(388),
+    /* parameters */ ParameterIndex(390),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(108),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -7511,7 +7523,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(389),
+    /* parameters */ ParameterIndex(391),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(110),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(81),
@@ -7550,7 +7562,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(390),
+    /* parameters */ ParameterIndex(392),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(112),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -7563,7 +7575,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(391),
+    /* parameters */ ParameterIndex(393),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(114),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -7589,7 +7601,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(392),
+    /* parameters */ ParameterIndex(394),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(116),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(81),
@@ -7628,7 +7640,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(393),
+    /* parameters */ ParameterIndex(395),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(118),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -7641,7 +7653,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(394),
+    /* parameters */ ParameterIndex(396),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(120),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -7667,7 +7679,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(395),
+    /* parameters */ ParameterIndex(397),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(122),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(81),
@@ -7706,7 +7718,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(396),
+    /* parameters */ ParameterIndex(398),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(124),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -7719,7 +7731,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(397),
+    /* parameters */ ParameterIndex(399),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(126),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -7745,7 +7757,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(398),
+    /* parameters */ ParameterIndex(400),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(128),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(81),
@@ -7784,7 +7796,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(399),
+    /* parameters */ ParameterIndex(401),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(130),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -7797,7 +7809,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(400),
+    /* parameters */ ParameterIndex(402),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(132),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -7823,7 +7835,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(401),
+    /* parameters */ ParameterIndex(403),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(134),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(81),
@@ -7862,7 +7874,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(402),
+    /* parameters */ ParameterIndex(404),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(136),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -7875,7 +7887,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(403),
+    /* parameters */ ParameterIndex(405),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(138),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -7901,7 +7913,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(404),
+    /* parameters */ ParameterIndex(406),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(140),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(81),
@@ -7940,7 +7952,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(405),
+    /* parameters */ ParameterIndex(407),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(142),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -7953,7 +7965,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(406),
+    /* parameters */ ParameterIndex(408),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(144),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -7979,7 +7991,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(407),
+    /* parameters */ ParameterIndex(409),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(146),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(81),
@@ -8018,7 +8030,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(408),
+    /* parameters */ ParameterIndex(410),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(148),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -8031,7 +8043,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(409),
+    /* parameters */ ParameterIndex(411),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(150),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -8057,7 +8069,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(37),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(410),
+    /* parameters */ ParameterIndex(412),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(152),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(81),
@@ -8096,7 +8108,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(16),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(411),
+    /* parameters */ ParameterIndex(413),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(154),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -8109,7 +8121,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(14),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(412),
+    /* parameters */ ParameterIndex(414),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(156),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(107),
@@ -8174,7 +8186,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(6),
-    /* parameters */ ParameterIndex(379),
+    /* parameters */ ParameterIndex(381),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -8226,7 +8238,7 @@
     /* num_template_numbers */ 1,
     /* template_types */ TemplateTypeIndex(24),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(350),
+    /* parameters */ ParameterIndex(352),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(85),
@@ -8239,7 +8251,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(10),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(353),
+    /* parameters */ ParameterIndex(355),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(2),
     /* const_eval_fn */ ConstEvalFunctionIndex(85),
@@ -8291,7 +8303,7 @@
     /* num_template_numbers */ 1,
     /* template_types */ TemplateTypeIndex(24),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(350),
+    /* parameters */ ParameterIndex(352),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(86),
@@ -8304,7 +8316,7 @@
     /* num_template_numbers */ 2,
     /* template_types */ TemplateTypeIndex(10),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(353),
+    /* parameters */ ParameterIndex(355),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(2),
     /* const_eval_fn */ ConstEvalFunctionIndex(86),
@@ -8356,7 +8368,7 @@
     /* num_template_numbers */ 1,
     /* template_types */ TemplateTypeIndex(24),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(350),
+    /* parameters */ ParameterIndex(352),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(91),
@@ -8408,7 +8420,7 @@
     /* num_template_numbers */ 1,
     /* template_types */ TemplateTypeIndex(24),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(350),
+    /* parameters */ ParameterIndex(352),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(92),
@@ -8616,7 +8628,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(381),
+    /* parameters */ ParameterIndex(383),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(31),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(81),
@@ -8694,7 +8706,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(370),
+    /* parameters */ ParameterIndex(372),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(81),
@@ -8733,7 +8745,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(382),
+    /* parameters */ ParameterIndex(384),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(87),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(81),
@@ -9292,7 +9304,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(370),
+    /* parameters */ ParameterIndex(372),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -9305,7 +9317,7 @@
     /* num_template_numbers */ 1,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(371),
+    /* parameters */ ParameterIndex(373),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(14),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
@@ -9812,7 +9824,7 @@
     /* num_template_numbers */ 0,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(370),
+    /* parameters */ ParameterIndex(372),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(15),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
     /* const_eval_fn */ ConstEvalFunctionIndex(55),
@@ -9825,7 +9837,7 @@
     /* num_template_numbers */ 1,
     /* template_types */ TemplateTypeIndex(/* invalid */),
     /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(371),
+    /* parameters */ ParameterIndex(373),
     /* return_type_matcher_indices */ TypeMatcherIndicesIndex(14),
     /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
     /* const_eval_fn */ ConstEvalFunctionIndex(55),
@@ -10222,760 +10234,6 @@
   },
   {
     /* [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(82),
-  },
-  {
-    /* [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(82),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(1),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(83),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(149),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
-    /* const_eval_fn */ ConstEvalFunctionIndex(83),
-  },
-  {
-    /* [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(84),
-  },
-  {
-    /* [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(84),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(1),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(93),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(149),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
-    /* const_eval_fn */ ConstEvalFunctionIndex(93),
-  },
-  {
-    /* [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(98),
-  },
-  {
-    /* [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(98),
-  },
-  {
-    /* [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(99),
-  },
-  {
-    /* [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(99),
-  },
-  {
-    /* [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(100),
-  },
-  {
-    /* [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(100),
-  },
-  {
-    /* [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(101),
-  },
-  {
-    /* [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(101),
-  },
-  {
-    /* [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(102),
-  },
-  {
-    /* [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(102),
-  },
-  {
-    /* [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(103),
-  },
-  {
-    /* [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(103),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(16),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(104),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(351),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
-    /* const_eval_fn */ ConstEvalFunctionIndex(104),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(/* invalid */),
-    /* parameters */ ParameterIndex(16),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(105),
-  },
-  {
-    /* [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(30),
-    /* template_numbers */ TemplateNumberIndex(4),
-    /* parameters */ ParameterIndex(351),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
-    /* const_eval_fn */ ConstEvalFunctionIndex(105),
-  },
-  {
-    /* [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(33),
-    /* 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(31),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(22),
-  },
-  {
-    /* [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(33),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(23),
-  },
-  {
-    /* [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(27),
-  },
-  {
-    /* [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(44),
-  },
-  {
-    /* [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(33),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(45),
-  },
-  {
-    /* [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(33),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(46),
-  },
-  {
-    /* [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(33),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(47),
-  },
-  {
-    /* [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(33),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(48),
-  },
-  {
-    /* [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(33),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(49),
-  },
-  {
-    /* [445] */
-    /* 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(374),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(50),
-  },
-  {
-    /* [446] */
-    /* 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(375),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(51),
-  },
-  {
-    /* [447] */
-    /* 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(374),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(52),
-  },
-  {
-    /* [448] */
-    /* 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(375),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(53),
-  },
-  {
-    /* [449] */
-    /* 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(57),
-  },
-  {
-    /* [450] */
-    /* 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(58),
-  },
-  {
-    /* [451] */
-    /* 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 */),
-  },
-  {
-    /* [452] */
-    /* 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(72),
-  },
-  {
-    /* [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(26),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(74),
-  },
-  {
-    /* [454] */
-    /* 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(75),
-  },
-  {
-    /* [455] */
-    /* 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(76),
-  },
-  {
-    /* [456] */
-    /* 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(77),
-  },
-  {
-    /* [457] */
-    /* 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(78),
-  },
-  {
-    /* [458] */
-    /* 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(30),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(79),
-  },
-  {
-    /* [459] */
-    /* 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(32),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(80),
-  },
-  {
-    /* [460] */
-    /* 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(376),
-    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
-  },
-  {
-    /* [461] */
-    /* 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 */),
-  },
-  {
-    /* [462] */
-    /* 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 */),
-  },
-  {
-    /* [463] */
-    /* 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 */),
-  },
-  {
-    /* [464] */
-    /* 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 */),
-  },
-  {
-    /* [465] */
-    /* 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(32),
-    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
-    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
-  },
-  {
-    /* [466] */
     /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* num_parameters */ 2,
     /* num_template_types */ 1,
@@ -10988,7 +10246,774 @@
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
+    /* [409] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, 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(350),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [410] */
+    /* 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(82),
+  },
+  {
+    /* [411] */
+    /* 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(82),
+  },
+  {
+    /* [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(30),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(83),
+  },
+  {
+    /* [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(30),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(83),
+  },
+  {
+    /* [414] */
+    /* 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(84),
+  },
+  {
+    /* [415] */
+    /* 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(84),
+  },
+  {
+    /* [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(30),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(93),
+  },
+  {
+    /* [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(30),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(93),
+  },
+  {
+    /* [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(98),
+  },
+  {
+    /* [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(98),
+  },
+  {
+    /* [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(27),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [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(27),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(8),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(99),
+  },
+  {
+    /* [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(100),
+  },
+  {
+    /* [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(100),
+  },
+  {
+    /* [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(101),
+  },
+  {
+    /* [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(101),
+  },
+  {
+    /* [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(102),
+  },
+  {
+    /* [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(102),
+  },
+  {
+    /* [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(24),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(1),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(9),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(103),
+  },
+  {
+    /* [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(24),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(149),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(8),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(103),
+  },
+  {
+    /* [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(30),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(16),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(104),
+  },
+  {
+    /* [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(30),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(353),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(104),
+  },
+  {
+    /* [432] */
+    /* 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(30),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(16),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(105),
+  },
+  {
+    /* [433] */
+    /* 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(30),
+    /* template_numbers */ TemplateNumberIndex(4),
+    /* parameters */ ParameterIndex(353),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(6),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(1),
+    /* const_eval_fn */ ConstEvalFunctionIndex(105),
+  },
+  {
+    /* [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(25),
+    /* template_numbers */ TemplateNumberIndex(7),
+    /* parameters */ ParameterIndex(370),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [435] */
+    /* 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),
+  },
+  {
+    /* [436] */
+    /* 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(371),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(19),
+  },
+  {
+    /* [437] */
+    /* 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),
+  },
+  {
+    /* [438] */
+    /* 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(31),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(22),
+  },
+  {
+    /* [439] */
+    /* 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(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(23),
+  },
+  {
+    /* [440] */
+    /* 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(27),
+  },
+  {
+    /* [441] */
+    /* 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(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(374),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* 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(374),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* 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(374),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* 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 */ 1,
+    /* num_template_types */ 0,
+    /* num_template_numbers */ 0,
+    /* template_types */ TemplateTypeIndex(/* invalid */),
+    /* template_numbers */ TemplateNumberIndex(/* invalid */),
+    /* parameters */ ParameterIndex(375),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(48),
+  },
+  {
+    /* [446] */
+    /* 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(375),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(49),
+  },
+  {
+    /* [447] */
+    /* 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(376),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(50),
+  },
+  {
+    /* [448] */
+    /* 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(377),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(51),
+  },
+  {
+    /* [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(376),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(52),
+  },
+  {
+    /* [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(377),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(33),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(53),
+  },
+  {
+    /* [451] */
+    /* 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(57),
+  },
+  {
+    /* [452] */
+    /* 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(58),
+  },
+  {
+    /* [453] */
+    /* 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 */),
+  },
+  {
+    /* [454] */
+    /* 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(355),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(12),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(3),
+    /* const_eval_fn */ ConstEvalFunctionIndex(72),
+  },
+  {
+    /* [455] */
+    /* 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(74),
+  },
+  {
+    /* [456] */
+    /* 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(75),
+  },
+  {
+    /* [457] */
+    /* 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(76),
+  },
+  {
+    /* [458] */
+    /* 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(77),
+  },
+  {
+    /* [459] */
+    /* 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(78),
+  },
+  {
+    /* [460] */
+    /* 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(30),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(79),
+  },
+  {
+    /* [461] */
+    /* 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(32),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(80),
+  },
+  {
+    /* [462] */
+    /* 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(378),
+    /* return_type_matcher_indices */ TypeMatcherIndicesIndex(2),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [463] */
+    /* 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 */),
+  },
+  {
+    /* [464] */
+    /* 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 */),
+  },
+  {
+    /* [465] */
+    /* 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 */),
+  },
+  {
+    /* [466] */
+    /* 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 */),
+  },
+  {
     /* [467] */
+    /* 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(32),
+    /* return_number_matcher_indices */ NumberMatcherIndicesIndex(/* invalid */),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [468] */
     /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
     /* num_parameters */ 1,
     /* num_template_types */ 1,
@@ -11001,7 +11026,7 @@
     /* const_eval_fn */ ConstEvalFunctionIndex(81),
   },
   {
-    /* [468] */
+    /* [469] */
     /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* num_parameters */ 2,
     /* num_template_types */ 0,
@@ -11014,7 +11039,7 @@
     /* const_eval_fn */ ConstEvalFunctionIndex(96),
   },
   {
-    /* [469] */
+    /* [470] */
     /* flags */ OverloadFlags(OverloadFlag::kIsOperator, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* num_parameters */ 2,
     /* num_template_types */ 0,
@@ -11027,7 +11052,7 @@
     /* const_eval_fn */ ConstEvalFunctionIndex(97),
   },
   {
-    /* [470] */
+    /* [471] */
     /* flags */ OverloadFlags(OverloadFlag::kIsConverter, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMustUse),
     /* num_parameters */ 1,
     /* num_template_types */ 1,
@@ -11084,7 +11109,7 @@
     /* [5] */
     /* fn arrayLength<T, A : access>(ptr<storage, array<T>, A>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(432),
+    /* overloads */ OverloadIndex(434),
   },
   {
     /* [6] */
@@ -11174,7 +11199,7 @@
     /* [18] */
     /* fn cross<T : fa_f32_f16>(vec3<T>, vec3<T>) -> vec3<T> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(433),
+    /* overloads */ OverloadIndex(435),
   },
   {
     /* [19] */
@@ -11187,7 +11212,7 @@
     /* [20] */
     /* fn determinant<N : num, T : fa_f32_f16>(mat<N, N, T>) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(434),
+    /* overloads */ OverloadIndex(436),
   },
   {
     /* [21] */
@@ -11200,19 +11225,19 @@
     /* [22] */
     /* fn dot<N : num, T : fia_fiu32_f16>(vec<N, T>, vec<N, T>) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(435),
+    /* overloads */ OverloadIndex(437),
   },
   {
     /* [23] */
     /* fn dot4I8Packed(u32, u32) -> i32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(436),
+    /* overloads */ OverloadIndex(438),
   },
   {
     /* [24] */
     /* fn dot4U8Packed(u32, u32) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(437),
+    /* overloads */ OverloadIndex(439),
   },
   {
     /* [25] */
@@ -11281,7 +11306,7 @@
     /* [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),
+    /* overloads */ OverloadIndex(440),
   },
   {
     /* [35] */
@@ -11421,61 +11446,61 @@
     /* [54] */
     /* fn normalize<N : num, T : fa_f32_f16>(vec<N, T>) -> vec<N, T> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(439),
+    /* overloads */ OverloadIndex(441),
   },
   {
     /* [55] */
     /* fn pack2x16float(vec2<f32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(440),
+    /* overloads */ OverloadIndex(442),
   },
   {
     /* [56] */
     /* fn pack2x16snorm(vec2<f32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(441),
+    /* overloads */ OverloadIndex(443),
   },
   {
     /* [57] */
     /* fn pack2x16unorm(vec2<f32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(442),
+    /* overloads */ OverloadIndex(444),
   },
   {
     /* [58] */
     /* fn pack4x8snorm(vec4<f32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(443),
+    /* overloads */ OverloadIndex(445),
   },
   {
     /* [59] */
     /* fn pack4x8unorm(vec4<f32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(444),
+    /* overloads */ OverloadIndex(446),
   },
   {
     /* [60] */
     /* fn pack4xI8(vec4<i32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(445),
+    /* overloads */ OverloadIndex(447),
   },
   {
     /* [61] */
     /* fn pack4xU8(vec4<u32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(446),
+    /* overloads */ OverloadIndex(448),
   },
   {
     /* [62] */
     /* fn pack4xI8Clamp(vec4<i32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(447),
+    /* overloads */ OverloadIndex(449),
   },
   {
     /* [63] */
     /* fn pack4xU8Clamp(vec4<u32>) -> u32 */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(448),
+    /* overloads */ OverloadIndex(450),
   },
   {
     /* [64] */
@@ -11502,13 +11527,13 @@
     /* [67] */
     /* fn reflect<N : num, T : fa_f32_f16>(vec<N, T>, vec<N, T>) -> vec<N, T> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(449),
+    /* overloads */ OverloadIndex(451),
   },
   {
     /* [68] */
     /* fn refract<N : num, T : fa_f32_f16>(vec<N, T>, vec<N, T>, T) -> vec<N, T> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(450),
+    /* overloads */ OverloadIndex(452),
   },
   {
     /* [69] */
@@ -11585,7 +11610,7 @@
     /* [79] */
     /* fn storageBarrier() */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(451),
+    /* overloads */ OverloadIndex(453),
   },
   {
     /* [80] */
@@ -11605,7 +11630,7 @@
     /* [82] */
     /* fn transpose<M : num, N : num, T : fa_f32_f16>(mat<M, N, T>) -> mat<N, M, T> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(452),
+    /* overloads */ OverloadIndex(454),
   },
   {
     /* [83] */
@@ -11618,61 +11643,61 @@
     /* [84] */
     /* fn unpack2x16float(u32) -> vec2<f32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(453),
+    /* overloads */ OverloadIndex(455),
   },
   {
     /* [85] */
     /* fn unpack2x16snorm(u32) -> vec2<f32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(454),
+    /* overloads */ OverloadIndex(456),
   },
   {
     /* [86] */
     /* fn unpack2x16unorm(u32) -> vec2<f32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(455),
+    /* overloads */ OverloadIndex(457),
   },
   {
     /* [87] */
     /* fn unpack4x8snorm(u32) -> vec4<f32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(456),
+    /* overloads */ OverloadIndex(458),
   },
   {
     /* [88] */
     /* fn unpack4x8unorm(u32) -> vec4<f32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(457),
+    /* overloads */ OverloadIndex(459),
   },
   {
     /* [89] */
     /* fn unpack4xI8(u32) -> vec4<i32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(458),
+    /* overloads */ OverloadIndex(460),
   },
   {
     /* [90] */
     /* fn unpack4xU8(u32) -> vec4<u32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(459),
+    /* overloads */ OverloadIndex(461),
   },
   {
     /* [91] */
     /* fn workgroupBarrier() */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(451),
+    /* overloads */ OverloadIndex(453),
   },
   {
     /* [92] */
     /* fn workgroupUniformLoad<T>(ptr<workgroup, T, read_write>) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(460),
+    /* overloads */ OverloadIndex(462),
   },
   {
     /* [93] */
     /* fn textureBarrier() */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(451),
+    /* overloads */ OverloadIndex(453),
   },
   {
     /* [94] */
@@ -11907,85 +11932,86 @@
     /* [109] */
     /* fn atomicLoad<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(461),
+    /* overloads */ OverloadIndex(463),
   },
   {
     /* [110] */
     /* fn atomicStore<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(462),
+    /* overloads */ OverloadIndex(464),
   },
   {
     /* [111] */
     /* fn atomicAdd<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(463),
+    /* overloads */ OverloadIndex(465),
   },
   {
     /* [112] */
     /* fn atomicSub<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(463),
+    /* overloads */ OverloadIndex(465),
   },
   {
     /* [113] */
     /* fn atomicMax<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(463),
+    /* overloads */ OverloadIndex(465),
   },
   {
     /* [114] */
     /* fn atomicMin<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(463),
+    /* overloads */ OverloadIndex(465),
   },
   {
     /* [115] */
     /* fn atomicAnd<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(463),
+    /* overloads */ OverloadIndex(465),
   },
   {
     /* [116] */
     /* fn atomicOr<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(463),
+    /* overloads */ OverloadIndex(465),
   },
   {
     /* [117] */
     /* fn atomicXor<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(463),
+    /* overloads */ OverloadIndex(465),
   },
   {
     /* [118] */
     /* fn atomicExchange<T : iu32, S : workgroup_or_storage>(ptr<S, atomic<T>, read_write>, T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(463),
+    /* overloads */ OverloadIndex(465),
   },
   {
     /* [119] */
     /* 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(464),
+    /* overloads */ OverloadIndex(466),
   },
   {
     /* [120] */
     /* fn subgroupBallot() -> vec4<u32> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(465),
+    /* overloads */ OverloadIndex(467),
   },
   {
     /* [121] */
     /* fn subgroupBroadcast<T : fiu32_f16>(value: T, @const sourceLaneIndex: u32) -> T */
-    /* num overloads */ 1,
-    /* overloads */ OverloadIndex(466),
+    /* fn subgroupBroadcast<N : num, T : fiu32_f16>(value: vec<N, T>, @const sourceLaneIndex: u32) -> vec<N, T> */
+    /* num overloads */ 2,
+    /* overloads */ OverloadIndex(408),
   },
   {
     /* [122] */
     /* fn _tint_materialize<T>(T) -> T */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(467),
+    /* overloads */ OverloadIndex(468),
   },
 };
 
@@ -11995,21 +12021,21 @@
     /* op !(bool) -> bool */
     /* op !<N : num>(vec<N, bool>) -> vec<N, bool> */
     /* num overloads */ 2,
-    /* overloads */ OverloadIndex(408),
+    /* overloads */ OverloadIndex(410),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(412),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(414),
   },
 };
 constexpr uint8_t kUnaryOperatorNot = 0;
@@ -12074,7 +12100,7 @@
     /* 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),
+    /* overloads */ OverloadIndex(416),
   },
   {
     /* [6] */
@@ -12098,69 +12124,69 @@
     /* [8] */
     /* op &&(bool, bool) -> bool */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(468),
+    /* overloads */ OverloadIndex(469),
   },
   {
     /* [9] */
     /* op ||(bool, bool) -> bool */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(469),
+    /* overloads */ OverloadIndex(470),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(418),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(420),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(422),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(424),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(426),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(428),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(430),
   },
   {
     /* [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),
+    /* overloads */ OverloadIndex(432),
   },
 };
 constexpr uint8_t kBinaryOperatorPlus = 0;
@@ -12379,7 +12405,7 @@
     /* [17] */
     /* conv packedVec3<T : concrete_scalar>(vec3<T>) -> packedVec3<T> */
     /* num overloads */ 1,
-    /* overloads */ OverloadIndex(470),
+    /* overloads */ OverloadIndex(471),
   },
 };
 
diff --git a/src/tint/lang/wgsl/ir_roundtrip_test.cc b/src/tint/lang/wgsl/ir_roundtrip_test.cc
index 9b7b522..5cb3f99 100644
--- a/src/tint/lang/wgsl/ir_roundtrip_test.cc
+++ b/src/tint/lang/wgsl/ir_roundtrip_test.cc
@@ -76,7 +76,7 @@
         result.ir_pre_raise = core::ir::Disassemble(ir_module.Get());
 
         if (auto res = tint::wgsl::writer::Raise(ir_module.Get()); res != Success) {
-            result.err = res.Failure().reason.str();
+            result.err = res.Failure().reason.Str();
             return result;
         }
 
@@ -86,7 +86,7 @@
         program_options.allowed_features = AllowedFeatures::Everything();
         auto output_program = wgsl::writer::IRToProgram(ir_module.Get(), program_options);
         if (!output_program.IsValid()) {
-            result.err = output_program.Diagnostics().str();
+            result.err = output_program.Diagnostics().Str();
             result.ast = Program::printer(output_program);
             return result;
         }
diff --git a/src/tint/lang/wgsl/program/program.cc b/src/tint/lang/wgsl/program/program.cc
index 3f7735e..bcd8e93 100644
--- a/src/tint/lang/wgsl/program/program.cc
+++ b/src/tint/lang/wgsl/program/program.cc
@@ -74,14 +74,14 @@
     ast_ = &builder.AST();  // ast::Module is actually a heap allocation.
     sem_ = std::move(builder.Sem());
     symbols_ = std::move(builder.Symbols());
-    diagnostics_.add(std::move(builder.Diagnostics()));
+    diagnostics_.Add(std::move(builder.Diagnostics()));
     builder.MarkAsMoved();
 
-    if (!is_valid_ && !diagnostics_.contains_errors()) {
+    if (!is_valid_ && !diagnostics_.ContainsErrors()) {
         // If the builder claims to be invalid, then we really should have an error
         // message generated. If we find a situation where the program is not valid
         // and there are no errors reported, add one here.
-        diagnostics_.add_error(diag::System::Program, "invalid program generated");
+        diagnostics_.AddError(diag::System::Program, "invalid program generated");
     }
 }
 
diff --git a/src/tint/lang/wgsl/program/program_test.cc b/src/tint/lang/wgsl/program/program_test.cc
index c8f2656..1a59adb 100644
--- a/src/tint/lang/wgsl/program/program_test.cc
+++ b/src/tint/lang/wgsl/program/program_test.cc
@@ -93,18 +93,18 @@
 }
 
 TEST_F(ProgramTest, DiagnosticsMove) {
-    Diagnostics().add_error(diag::System::Program, "an error message");
+    Diagnostics().AddError(diag::System::Program, "an error message");
 
     Program program_a(std::move(*this));
     EXPECT_FALSE(program_a.IsValid());
-    EXPECT_EQ(program_a.Diagnostics().count(), 1u);
-    EXPECT_EQ(program_a.Diagnostics().error_count(), 1u);
+    EXPECT_EQ(program_a.Diagnostics().Count(), 1u);
+    EXPECT_EQ(program_a.Diagnostics().NumErrors(), 1u);
     EXPECT_EQ(program_a.Diagnostics().begin()->message, "an error message");
 
     Program program_b(std::move(program_a));
     EXPECT_FALSE(program_b.IsValid());
-    EXPECT_EQ(program_b.Diagnostics().count(), 1u);
-    EXPECT_EQ(program_b.Diagnostics().error_count(), 1u);
+    EXPECT_EQ(program_b.Diagnostics().Count(), 1u);
+    EXPECT_EQ(program_b.Diagnostics().NumErrors(), 1u);
     EXPECT_EQ(program_b.Diagnostics().begin()->message, "an error message");
 }
 
diff --git a/src/tint/lang/wgsl/reader/options.h b/src/tint/lang/wgsl/reader/options.h
index 3ac0e03..eb3400f 100644
--- a/src/tint/lang/wgsl/reader/options.h
+++ b/src/tint/lang/wgsl/reader/options.h
@@ -39,9 +39,12 @@
     AllowedFeatures allowed_features{};
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField().
-    TINT_REFLECT(allowed_features);
+    TINT_REFLECT(Options, allowed_features);
 };
 
+/// Ensure that all the fields of Options are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Options);
+
 }  // namespace tint::wgsl::reader
 
 #endif  // SRC_TINT_LANG_WGSL_READER_OPTIONS_H_
diff --git a/src/tint/lang/wgsl/reader/parser/error_msg_test.cc b/src/tint/lang/wgsl/reader/parser/error_msg_test.cc
index a0ff445..394a6f3 100644
--- a/src/tint/lang/wgsl/reader/parser/error_msg_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/error_msg_test.cc
@@ -46,8 +46,8 @@
         p->set_max_errors(5);                                                      \
         EXPECT_EQ(false, p->Parse());                                              \
         auto diagnostics = p->builder().Diagnostics();                             \
-        EXPECT_EQ(true, diagnostics.contains_errors());                            \
-        EXPECT_EQ(expected, diag::Formatter(formatter_style).format(diagnostics)); \
+        EXPECT_EQ(true, diagnostics.ContainsErrors());                             \
+        EXPECT_EQ(expected, diag::Formatter(formatter_style).Format(diagnostics)); \
     } while (false)
 
 TEST_F(ParserImplErrorTest, AdditiveInvalidExpr) {
diff --git a/src/tint/lang/wgsl/reader/parser/error_resync_test.cc b/src/tint/lang/wgsl/reader/parser/error_resync_test.cc
index d818893..31a6dbc 100644
--- a/src/tint/lang/wgsl/reader/parser/error_resync_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/error_resync_test.cc
@@ -43,8 +43,8 @@
         auto p = parser(source);                                                   \
         EXPECT_EQ(false, p->Parse());                                              \
         auto diagnostics = p->builder().Diagnostics();                             \
-        EXPECT_EQ(true, diagnostics.contains_errors());                            \
-        EXPECT_EQ(expected, diag::Formatter(formatter_style).format(diagnostics)); \
+        EXPECT_EQ(true, diagnostics.ContainsErrors());                             \
+        EXPECT_EQ(expected, diag::Formatter(formatter_style).Format(diagnostics)); \
     } while (false)
 
 TEST_F(ParserImplErrorResyncTest, BadFunctionDecls) {
diff --git a/src/tint/lang/wgsl/reader/parser/expression_test.cc b/src/tint/lang/wgsl/reader/parser/expression_test.cc
index 74d78df..16d0ba0 100644
--- a/src/tint/lang/wgsl/reader/parser/expression_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/expression_test.cc
@@ -180,7 +180,7 @@
     EXPECT_TRUE(e.errored);
     EXPECT_EQ(e.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->builder().Diagnostics().str(),
+    EXPECT_EQ(p->builder().Diagnostics().Str(),
               R"(test.wgsl:1:3 error: mixing '&&' and '||' requires parenthesis
 a && true || b
   ^^^^^^^^^^
@@ -194,7 +194,7 @@
     EXPECT_TRUE(e.errored);
     EXPECT_EQ(e.value, nullptr);
     EXPECT_TRUE(p->has_error());
-    EXPECT_EQ(p->builder().Diagnostics().str(),
+    EXPECT_EQ(p->builder().Diagnostics().Str(),
               R"(test.wgsl:1:3 error: mixing '||' and '&&' requires parenthesis
 a || true && b
   ^^^^^^^^^^
diff --git a/src/tint/lang/wgsl/reader/parser/parser.cc b/src/tint/lang/wgsl/reader/parser/parser.cc
index b00c274..3a05f2d 100644
--- a/src/tint/lang/wgsl/reader/parser/parser.cc
+++ b/src/tint/lang/wgsl/reader/parser/parser.cc
@@ -222,43 +222,43 @@
 
 Parser::~Parser() = default;
 
-Parser::Failure::Errored Parser::add_error(const Source& source,
-                                           std::string_view err,
-                                           std::string_view use) {
+Parser::Failure::Errored Parser::AddError(const Source& source,
+                                          std::string_view err,
+                                          std::string_view use) {
     if (silence_diags_ == 0) {
         StringStream msg;
         msg << err;
         if (!use.empty()) {
             msg << " for " << use;
         }
-        add_error(source, msg.str());
+        AddError(source, msg.str());
     }
     return Failure::kErrored;
 }
 
-Parser::Failure::Errored Parser::add_error(const Token& t, std::string_view err) {
-    add_error(t.source(), err);
+Parser::Failure::Errored Parser::AddError(const Token& t, std::string_view err) {
+    AddError(t.source(), err);
     return Failure::kErrored;
 }
 
-Parser::Failure::Errored Parser::add_error(const Source& source, std::string_view err) {
+Parser::Failure::Errored Parser::AddError(const Source& source, std::string_view err) {
     if (silence_diags_ == 0) {
-        builder_.Diagnostics().add_error(diag::System::Reader, err, source);
+        builder_.Diagnostics().AddError(diag::System::Reader, err, source);
     }
     return Failure::kErrored;
 }
 
-void Parser::add_note(const Source& source, std::string_view err) {
+void Parser::AddNote(const Source& source, std::string_view err) {
     if (silence_diags_ == 0) {
-        builder_.Diagnostics().add_note(diag::System::Reader, err, source);
+        builder_.Diagnostics().AddNote(diag::System::Reader, err, source);
     }
 }
 
 void Parser::deprecated(const Source& source, std::string_view msg) {
     if (silence_diags_ == 0) {
-        builder_.Diagnostics().add_warning(
-            diag::System::Reader, "use of deprecated language feature: " + std::string(msg),
-            source);
+        builder_.Diagnostics().AddWarning(diag::System::Reader,
+                                          "use of deprecated language feature: " + std::string(msg),
+                                          source);
     }
 }
 
@@ -349,13 +349,13 @@
             }
 
             if (!gd.matched && !gd.errored) {
-                add_error(p, "unexpected token");
+                AddError(p, "unexpected token");
             }
         }
 
-        if (builder_.Diagnostics().error_count() >= max_errors_) {
-            add_error(Source{{}, p.source().file},
-                      "stopping after " + std::to_string(max_errors_) + " errors");
+        if (builder_.Diagnostics().NumErrors() >= max_errors_) {
+            AddError(Source{{}, p.source().file},
+                     "stopping after " + std::to_string(max_errors_) + " errors");
             break;
         }
     }
@@ -376,7 +376,7 @@
     }
 
     if (result.matched && have_parsed_decl) {
-        return add_error(p, "directives must come before all global declarations");
+        return AddError(p, "directives must come before all global declarations");
     }
     return result;
 }
@@ -423,7 +423,7 @@
         if (peek_is(Token::Type::kParenLeft)) {
             // A common error case is writing `enable(foo);` instead of `enable foo;`.
             synchronized_ = false;
-            return add_error(peek().source(), "enable directives don't take parenthesis");
+            return AddError(peek().source(), "enable directives don't take parenthesis");
         }
 
         Vector<const ast::Extension*, 4> extensions;
@@ -471,7 +471,7 @@
         if (t.Is(Token::Type::kParenLeft)) {
             // A common error case is writing `require(foo);` instead of `require foo;`.
             synchronized_ = false;
-            return add_error(t.source(), "requires directives don't take parenthesis");
+            return AddError(t.source(), "requires directives don't take parenthesis");
         }
 
         ast::Requires::LanguageFeatures features;
@@ -489,11 +489,11 @@
                     // Any identifier is a valid feature name, so we correctly handle new feature
                     // names getting added in the future, they just all get flagged as not
                     // supported.
-                    return add_error(t2.source(), "feature '" + t2.to_str() + "' is not supported");
+                    return AddError(t2.source(), "feature '" + t2.to_str() + "' is not supported");
                 }
                 features.Add(feature);
             } else {
-                return add_error(t2.source(), "invalid feature name for requires");
+                return AddError(t2.source(), "invalid feature name for requires");
             }
 
             if (!match(Token::Type::kComma)) {
@@ -629,7 +629,7 @@
 
     // We have attributes parsed, but nothing to consume them?
     if (attrs.value.Length() > 0) {
-        return add_error(next(), "expected declaration after attributes");
+        return AddError(next(), "expected declaration after attributes");
     }
 
     // We have a statement outside of a function?
@@ -639,7 +639,7 @@
         // Attempt to jump to the next '}' - the function might have just been
         // missing an opening line.
         sync_to(Token::Type::kBraceRight, true);
-        return add_error(t, "statement found outside of function body");
+        return AddError(t, "statement found outside of function body");
     }
     if (!stat.errored) {
         // No match, no error - the parser might not have progressed.
@@ -676,7 +676,7 @@
             return Failure::kErrored;
         }
         if (!expr.matched) {
-            return add_error(peek(), "missing initializer for 'var' declaration");
+            return AddError(peek(), "missing initializer for 'var' declaration");
         }
         initializer = expr.value;
     }
@@ -707,7 +707,7 @@
         use = "'override' declaration";
         is_overridable = true;
     } else if (match(Token::Type::kLet, &source)) {
-        return add_error(source, "module-scope 'let' is invalid, use 'const'");
+        return AddError(source, "module-scope 'let' is invalid, use 'const'");
     } else {
         return Failure::kNoMatch;
     }
@@ -734,7 +734,7 @@
             return Failure::kErrored;
         }
         if (!expr.matched) {
-            return add_error(peek(), "missing initializer for " + std::string(use));
+            return AddError(peek(), "missing initializer for " + std::string(use));
         }
         initializer = std::move(expr.value);
     }
@@ -804,7 +804,7 @@
         return Failure::kErrored;
     }
     if (!type.matched) {
-        return add_error(t.source(), "invalid type", use);
+        return AddError(t.source(), "invalid type", use);
     }
 
     return TypedIdentifier{type.value, ident.value};
@@ -877,7 +877,7 @@
         return Failure::kErrored;
     }
     if (!type.matched) {
-        return add_error(peek(), "invalid type alias");
+        return AddError(peek(), "invalid type alias");
     }
 
     return builder_.ty.alias(source(), name.value, type.value);
@@ -952,7 +952,7 @@
     }
 
     synchronized_ = false;
-    return add_error(t.source(), err.str());
+    return AddError(t.source(), err.str());
 }
 
 Expect<ast::Type> Parser::expect_type(std::string_view use) {
@@ -961,7 +961,7 @@
         return Failure::kErrored;
     }
     if (!type.matched) {
-        return add_error(peek().source(), "invalid type", use);
+        return AddError(peek().source(), "invalid type", use);
     }
     return type.value;
 }
@@ -1051,7 +1051,7 @@
         return Failure::kErrored;
     }
     if (!condition.matched) {
-        return add_error(peek(), "unable to parse condition expression");
+        return AddError(peek(), "unable to parse condition expression");
     }
 
     return create<ast::ConstAssert>(source(), condition.value);
@@ -1138,7 +1138,7 @@
         if (type.errored) {
             errored = true;
         } else if (!type.matched) {
-            return add_error(peek(), "unable to determine function return type");
+            return AddError(peek(), "unable to determine function return type");
         } else {
             return_type = type.value;
         }
@@ -1230,7 +1230,7 @@
             return Failure::kErrored;
         }
         if (!expr.matched) {
-            return add_error(peek(), "unable to parse expression");
+            return AddError(peek(), "unable to parse expression");
         }
 
         return expr.value;
@@ -1468,7 +1468,7 @@
             return Failure::kErrored;
         }
         if (!initializer.matched) {
-            return add_error(peek(), "missing initializer for 'const' declaration");
+            return AddError(peek(), "missing initializer for 'const' declaration");
         }
 
         auto* const_ = builder_.Const(typed_ident->name->source,  // source
@@ -1496,7 +1496,7 @@
             return Failure::kErrored;
         }
         if (!initializer.matched) {
-            return add_error(peek(), "missing initializer for 'let' declaration");
+            return AddError(peek(), "missing initializer for 'let' declaration");
         }
 
         auto* let = builder_.Let(typed_ident->name->source,  // source
@@ -1524,7 +1524,7 @@
             return Failure::kErrored;
         }
         if (!initializer_expr.matched) {
-            return add_error(peek(), "missing initializer for 'var' declaration");
+            return AddError(peek(), "missing initializer for 'var' declaration");
         }
 
         initializer = initializer_expr.value;
@@ -1572,7 +1572,7 @@
             return Failure::kErrored;
         }
         if (!condition.matched) {
-            return add_error(peek(), "unable to parse condition expression");
+            return AddError(peek(), "unable to parse condition expression");
         }
 
         auto body = expect_compound_statement("if statement");
@@ -1642,7 +1642,7 @@
         return Failure::kErrored;
     }
     if (!condition.matched) {
-        return add_error(peek(), "unable to parse selector expression");
+        return AddError(peek(), "unable to parse selector expression");
     }
 
     auto body_attrs = attribute_list();
@@ -1735,7 +1735,7 @@
     }
 
     if (selectors.IsEmpty()) {
-        return add_error(peek(), "expected case selector expression or `default`");
+        return AddError(peek(), "expected case selector expression or `default`");
     }
 
     return selectors;
@@ -1920,7 +1920,7 @@
         return Failure::kErrored;
     }
     if (!condition.matched) {
-        return add_error(peek(), "unable to parse while condition expression");
+        return AddError(peek(), "unable to parse while condition expression");
     }
 
     auto body = expect_compound_statement("while loop");
@@ -1993,7 +1993,7 @@
         return Failure::kErrored;
     }
     if (!expr.matched) {
-        return add_error(t1, "expected expression for `break-if`");
+        return AddError(t1, "expected expression for `break-if`");
     }
     if (!expect("`break-if` statement", Token::Type::kSemicolon)) {
         return Failure::kErrored;
@@ -2146,7 +2146,7 @@
                     return Failure::kErrored;
                 }
                 if (!param.matched) {
-                    return add_error(peek(), "unable to parse expression inside []");
+                    return AddError(peek(), "unable to parse expression inside []");
                 }
 
                 if (!expect("index accessor", Token::Type::kBracketRight)) {
@@ -2223,8 +2223,8 @@
             return Failure::kErrored;
         }
         if (!rhs.matched) {
-            return add_error(peek(), std::string("unable to parse right side of ") +
-                                         std::string(t.to_name()) + " expression");
+            return AddError(peek(), std::string("unable to parse right side of ") +
+                                        std::string(t.to_name()) + " expression");
         }
 
         lhs = create<ast::BinaryExpression>(source(), *op, lhs, rhs.value);
@@ -2276,8 +2276,8 @@
             return Failure::kErrored;
         }
         if (!rhs.matched) {
-            return add_error(peek(), std::string("unable to parse right side of ") +
-                                         std::string(t.to_name()) + " expression");
+            return AddError(peek(), std::string("unable to parse right side of ") +
+                                        std::string(t.to_name()) + " expression");
         }
 
         lhs = create<ast::BinaryExpression>(source(), op.value, lhs, rhs.value);
@@ -2334,8 +2334,8 @@
             return Failure::kErrored;
         }
         if (!unary.matched) {
-            return add_error(peek(), std::string("unable to parse right side of ") +
-                                         std::string(t.to_name()) + " expression");
+            return AddError(peek(), std::string("unable to parse right side of ") +
+                                        std::string(t.to_name()) + " expression");
         }
 
         // The multiplicative binds tighter, so pass the unary into that and build that expression
@@ -2412,8 +2412,8 @@
             return Failure::kErrored;
         }
         if (!rhs.matched) {
-            return add_error(rhs_start,
-                             std::string("unable to parse right side of ") + name + " expression");
+            return AddError(rhs_start,
+                            std::string("unable to parse right side of ") + name + " expression");
         }
         return create<ast::BinaryExpression>(source(), *op, lhs, rhs.value);
     }
@@ -2490,8 +2490,8 @@
         return Failure::kErrored;
     }
     if (!rhs.matched) {
-        return add_error(tok_rhs, std::string("unable to parse right side of ") +
-                                      std::string(tok_op.to_name()) + " expression");
+        return AddError(tok_rhs, std::string("unable to parse right side of ") +
+                                     std::string(tok_op.to_name()) + " expression");
     }
 
     return create<ast::BinaryExpression>(source(), *op, lhs, rhs.value);
@@ -2506,7 +2506,7 @@
     if (expr.matched) {
         return expr.value;
     }
-    return add_error(t, "expected expression for " + std::string(use));
+    return AddError(t, "expected expression for " + std::string(use));
 }
 
 Maybe<Parser::ExpressionList> Parser::expression_list(std::string_view use,
@@ -2616,8 +2616,8 @@
                     return Failure::kErrored;
                 }
                 if (!rhs.matched) {
-                    return add_error(peek(), std::string("unable to parse right side of ") +
-                                                 std::string(t.to_name()) + " expression");
+                    return AddError(peek(), std::string("unable to parse right side of ") +
+                                                std::string(t.to_name()) + " expression");
                 }
 
                 ret = create<ast::BinaryExpression>(source(), op, ret, rhs.value);
@@ -2632,9 +2632,9 @@
         // after this then it _must_ be a different one, and hence an error.
         if (auto* lhs = expr->As<ast::BinaryExpression>()) {
             if (auto& n = peek(); n.IsBinaryOperator()) {
-                add_error(Source::Combine(first_op, n.source()),
-                          std::string("mixing '") + ast::Operator(lhs->op) + "' and '" +
-                              std::string(n.to_name()) + "' requires parenthesis");
+                AddError(Source::Combine(first_op, n.source()),
+                         std::string("mixing '") + ast::Operator(lhs->op) + "' and '" +
+                             std::string(n.to_name()) + "' requires parenthesis");
                 return Failure::kErrored;
             }
         }
@@ -2672,9 +2672,9 @@
 
     auto& t = peek();
     if (match(Token::Type::kPlusPlus) || match(Token::Type::kMinusMinus)) {
-        add_error(source,
-                  "prefix increment and decrement operators are reserved for a "
-                  "future WGSL version");
+        AddError(source,
+                 "prefix increment and decrement operators are reserved for a "
+                 "future WGSL version");
         return Failure::kErrored;
     }
 
@@ -2697,7 +2697,7 @@
         // We've hit a maximum parser recursive depth.
         // We can't call into unary_expression() as we might stack overflow.
         // Instead, report an error
-        add_error(peek(), "maximum parser recursive depth reached");
+        AddError(peek(), "maximum parser recursive depth reached");
         return Failure::kErrored;
     }
 
@@ -2709,7 +2709,7 @@
         return Failure::kErrored;
     }
     if (!expr.matched) {
-        return add_error(
+        return AddError(
             peek(), "unable to parse right side of " + std::string(t.to_name()) + " expression");
     }
 
@@ -2775,7 +2775,7 @@
                 return Failure::kErrored;
             }
             if (!expr.matched) {
-                return add_error(t, "invalid expression");
+                return AddError(t, "invalid expression");
             }
             return expr.value;
         });
@@ -2832,7 +2832,7 @@
         return Failure::kErrored;
     }
     if (!expr.matched) {
-        return add_error(t, "missing expression");
+        return AddError(t, "missing expression");
     }
 
     const ast::Expression* ret = expr.value;
@@ -2858,7 +2858,7 @@
     // special casing will error as "missing = for assignment", which is less
     // helpful than this error message:
     if (peek_is(Token::Type::kIdentifier) && peek_is(Token::Type::kColon, 1)) {
-        return add_error(peek(0).source(), "expected 'var' for variable declaration");
+        return AddError(peek(0).source(), "expected 'var' for variable declaration");
     }
 
     Source source;
@@ -2912,7 +2912,7 @@
         return Failure::kErrored;
     }
     if (!rhs.matched) {
-        return add_error(peek(), "unable to parse right side of assignment");
+        return AddError(peek(), "unable to parse right side of assignment");
     }
 
     if (compound_op) {
@@ -3003,7 +3003,7 @@
     if (attr.matched) {
         return attr.value;
     }
-    return add_error(t, "expected attribute");
+    return AddError(t, "expected attribute");
 }
 
 // attribute
@@ -3014,7 +3014,7 @@
     auto& t = peek();
 
     if (match(Token::Type::kConst)) {
-        return add_error(t.source(), "const attribute may not appear in shaders");
+        return AddError(t.source(), "const attribute may not appear in shaders");
     }
     if (match(Token::Type::kDiagnostic)) {
         auto control = expect_diagnostic_control();
@@ -3056,7 +3056,7 @@
     if (min == 0) {
         auto& t2 = peek();
         if (match(Token::Type::kParenLeft)) {
-            return add_error(t2.source(), t.to_str() + " attribute doesn't take parenthesis");
+            return AddError(t2.source(), t.to_str() + " attribute doesn't take parenthesis");
         }
     } else {
         auto res = expect_paren_block(t.to_str() + " attribute", [&]() -> Expect<bool> {
@@ -3082,15 +3082,15 @@
         }
 
         if (args.IsEmpty() || args.Length() < min) {
-            return add_error(t.source(),
-                             t.to_str() + " expects" + (min != max ? " at least " : " ") +
-                                 std::to_string(min) + " argument" + (min != 1 ? "s" : ""));
+            return AddError(t.source(),
+                            t.to_str() + " expects" + (min != max ? " at least " : " ") +
+                                std::to_string(min) + " argument" + (min != 1 ? "s" : ""));
         }
         if (args.Length() > max) {
-            return add_error(t.source(),
-                             t.to_str() + " expects" + (min != max ? " at most " : " ") +
-                                 std::to_string(max) + " argument" + (max != 1 ? "s" : "") +
-                                 ", got " + std::to_string(args.Length()));
+            return AddError(t.source(), t.to_str() + " expects" + (min != max ? " at most " : " ") +
+                                            std::to_string(max) + " argument" +
+                                            (max != 1 ? "s" : "") + ", got " +
+                                            std::to_string(args.Length()));
         }
     }
 
@@ -3139,7 +3139,7 @@
     if (in.IsEmpty()) {
         return kSuccess;
     }
-    add_error(in[0]->source, "unexpected attributes");
+    AddError(in[0]->source, "unexpected attributes");
     return Failure::kErrored;
 }
 
@@ -3157,13 +3157,13 @@
     }
     Source template_source = lhs_source;
     template_source.range.end = end.range.end;
-    add_error(template_source, "parsed as template list");
+    AddError(template_source, "parsed as template list");
 
     if (auto rhs = expression(); rhs.matched) {
         Source lt_source = lhs_source;
         lt_source.range.end = rhs->source.range.end;
-        add_note(lt_source,
-                 "if this is intended to be a less-than expression then wrap in parentheses");
+        AddNote(lt_source,
+                "if this is intended to be a less-than expression then wrap in parentheses");
     }
     return Failure::kErrored;
 }
@@ -3178,13 +3178,13 @@
         return kSuccess;
     }
 
-    add_error(ident->source, "parsed as template list");
+    AddError(ident->source, "parsed as template list");
 
     if (auto rhs = expression(); rhs.matched) {
         Source gt_source = ident->arguments.Back()->source;
         gt_source.range.end = rhs->source.range.end;
-        add_note(gt_source,
-                 "if this is intended to be a greater-than expression then wrap in parentheses");
+        AddNote(gt_source,
+                "if this is intended to be a greater-than expression then wrap in parentheses");
     }
     return Failure::kErrored;
 }
@@ -3300,7 +3300,7 @@
     if (!use.empty()) {
         err << " for " << use;
     }
-    add_error(t, err.str());
+    AddError(t, err.str());
     return false;
 }
 
@@ -3310,14 +3310,14 @@
         *source = t.source();
     }
     if (!t.Is(Token::Type::kIntLiteral) && !t.Is(Token::Type::kIntLiteral_I)) {
-        return add_error(t.source(), "expected signed integer literal", use);
+        return AddError(t.source(), "expected signed integer literal", use);
     }
 
     int64_t val = t.to_i64();
     if ((val > std::numeric_limits<int32_t>::max()) ||
         (val < std::numeric_limits<int32_t>::min())) {
         // TODO(crbug.com/tint/1504): Test this when abstract int is implemented
-        return add_error(t.source(), "value overflows i32", use);
+        return AddError(t.source(), "value overflows i32", use);
     }
 
     next();
@@ -3332,7 +3332,7 @@
     }
 
     if (sint.value < 0) {
-        return add_error(source, std::string(use) + " must be positive");
+        return AddError(source, std::string(use) + " must be positive");
     }
 
     return static_cast<uint32_t>(sint.value);
@@ -3346,7 +3346,7 @@
     }
 
     if (sint.value <= 0) {
-        return add_error(source, std::string(use) + " must be greater than 0");
+        return AddError(source, std::string(use) + " must be greater than 0");
     }
 
     return static_cast<uint32_t>(sint.value);
@@ -3360,7 +3360,7 @@
         next();
 
         if (is_reserved(t)) {
-            return add_error(t.source(), "'" + t.to_str() + "' is a reserved keyword");
+            return AddError(t.source(), "'" + t.to_str() + "' is a reserved keyword");
         }
 
         return builder_.Ident(t.source(), t.to_str());
@@ -3369,7 +3369,7 @@
         return Failure::kErrored;
     }
     synchronized_ = false;
-    return add_error(t.source(), "expected " + std::string(kind), use);
+    return AddError(t.source(), "expected " + std::string(kind), use);
 }
 
 template <typename F, typename T>
@@ -3423,7 +3423,7 @@
         // We've hit a maximum parser recursive depth.
         // We can't call into body() as we might stack overflow.
         // Instead, report an error...
-        add_error(peek(), "maximum parser recursive depth reached");
+        AddError(peek(), "maximum parser recursive depth reached");
         // ...and try to resynchronize. If we cannot resynchronize to `tok` then
         // synchronized_ is set to false, and the parser knows that forward progress
         // is not being made.
@@ -3499,7 +3499,7 @@
     // The token might itself be an error.
     if (t.IsError()) {
         synchronized_ = false;
-        add_error(t.source(), t.to_str());
+        AddError(t.source(), t.to_str());
         return true;
     }
     return false;
diff --git a/src/tint/lang/wgsl/reader/parser/parser.h b/src/tint/lang/wgsl/reader/parser/parser.h
index 58f231e..9124e89 100644
--- a/src/tint/lang/wgsl/reader/parser/parser.h
+++ b/src/tint/lang/wgsl/reader/parser/parser.h
@@ -103,7 +103,7 @@
     /// Expect is the return type of the parser methods that are expected to
     /// return a parsed value of type T, unless there was an parse error.
     /// In the case of a parse error the called method will have called
-    /// add_error() and #errored will be set to true.
+    /// AddError() and #errored will be set to true.
     template <typename T>
     struct Expect {
         /// An alias to the templated type T.
@@ -154,7 +154,7 @@
     /// In the case of a successful grammar match, the Maybe will have #matched
     /// set to true.
     /// In the case of a parse error the called method will have called
-    /// add_error() and the Maybe will have #errored set to true.
+    /// AddError() and the Maybe will have #errored set to true.
     template <typename T>
     struct Maybe {
         inline Maybe(std::nullptr_t) = delete;  // NOLINT
@@ -323,12 +323,12 @@
     size_t get_max_errors() const { return max_errors_; }
 
     /// @returns true if an error was encountered.
-    bool has_error() const { return builder_.Diagnostics().contains_errors(); }
+    bool has_error() const { return builder_.Diagnostics().ContainsErrors(); }
 
     /// @returns the parser error string
     std::string error() const {
         diag::Formatter formatter{{false, false, false, false}};
-        return formatter.format(builder_.Diagnostics());
+        return formatter.Format(builder_.Diagnostics());
     }
 
     /// @returns the Program. The program builder in the parser will be reset
@@ -355,28 +355,28 @@
     /// Appends an error at `t` with the message `msg`
     /// @param t the token to associate the error with
     /// @param msg the error message
-    /// @return `Failure::Errored::kError` so that you can combine an add_error()
+    /// @return `Failure::Errored::kError` so that you can combine an AddError()
     /// call and return on the same line.
-    Failure::Errored add_error(const Token& t, std::string_view msg);
+    Failure::Errored AddError(const Token& t, std::string_view msg);
     /// Appends an error raised when parsing `use` at `t` with the message
     /// `msg`
     /// @param source the source to associate the error with
     /// @param msg the error message
     /// @param use a description of what was being parsed when the error was
     /// raised.
-    /// @return `Failure::Errored::kError` so that you can combine an add_error()
+    /// @return `Failure::Errored::kError` so that you can combine an AddError()
     /// call and return on the same line.
-    Failure::Errored add_error(const Source& source, std::string_view msg, std::string_view use);
+    Failure::Errored AddError(const Source& source, std::string_view msg, std::string_view use);
     /// Appends an error at `source` with the message `msg`
     /// @param source the source to associate the error with
     /// @param msg the error message
-    /// @return `Failure::Errored::kError` so that you can combine an add_error()
+    /// @return `Failure::Errored::kError` so that you can combine an AddError()
     /// call and return on the same line.
-    Failure::Errored add_error(const Source& source, std::string_view msg);
+    Failure::Errored AddError(const Source& source, std::string_view msg);
     /// Appends a note at `source` with the message `msg`
     /// @param source the source to associate the error with
     /// @param msg the note message
-    void add_note(const Source& source, std::string_view msg);
+    void AddNote(const Source& source, std::string_view msg);
     /// Appends a deprecated-language-feature warning at `source` with the message
     /// `msg`
     /// @param source the source to associate the error with
@@ -838,7 +838,7 @@
     /// @returns true if #synchronized_ is true and the number of reported errors
     /// is less than #max_errors_.
     bool continue_parsing() {
-        return synchronized_ && builder_.Diagnostics().error_count() < max_errors_;
+        return synchronized_ && builder_.Diagnostics().NumErrors() < max_errors_;
     }
 
     /// without_diag() calls the function `func` muting any diagnostics found while executing the
diff --git a/src/tint/lang/wgsl/reader/parser/struct_member_attribute_test.cc b/src/tint/lang/wgsl/reader/parser/struct_member_attribute_test.cc
index 2c93c6e..d0db0e5 100644
--- a/src/tint/lang/wgsl/reader/parser/struct_member_attribute_test.cc
+++ b/src/tint/lang/wgsl/reader/parser/struct_member_attribute_test.cc
@@ -233,7 +233,7 @@
     EXPECT_EQ(attr.value, nullptr);
     EXPECT_TRUE(p->has_error());
 
-    EXPECT_EQ(p->builder().Diagnostics().str(),
+    EXPECT_EQ(p->builder().Diagnostics().Str(),
               R"(test.wgsl:1:9 error: mixing '+' and '<<' requires parenthesis
 align(4 + 5 << 6)
         ^^^^^^
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 cc5a137..05505d1 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
@@ -201,8 +201,8 @@
         ~ControlStackScope() { impl_->control_stack_.Pop(); }
     };
 
-    void add_error(const Source& s, const std::string& err) {
-        diagnostics_.add_error(tint::diag::System::IR, err, s);
+    void AddError(const Source& s, const std::string& err) {
+        diagnostics_.AddError(tint::diag::System::IR, err, s);
     }
 
     bool NeedTerminator() { return current_block_ && !current_block_->Terminator(); }
@@ -266,7 +266,7 @@
                 TINT_ICE_ON_NO_MATCH);
         }
 
-        if (diagnostics_.contains_errors()) {
+        if (diagnostics_.ContainsErrors()) {
             return Failure{std::move(diagnostics_)};
         }
 
@@ -1005,8 +1005,8 @@
                     if (mat->ConstantValue()) {
                         auto* cv = mat->ConstantValue()->Clone(impl.clone_ctx_);
                         if (!cv) {
-                            impl.add_error(expr->source, "failed to get constant value for call " +
-                                                             std::string(expr->TypeInfo().name));
+                            impl.AddError(expr->source, "failed to get constant value for call " +
+                                                            std::string(expr->TypeInfo().name));
                             return;
                         }
                         Bind(expr, impl.builder_.Constant(cv));
@@ -1019,15 +1019,15 @@
                 for (const auto* arg : expr->args) {
                     auto value = GetValue(arg);
                     if (!value) {
-                        impl.add_error(arg->source, "failed to convert arguments");
+                        impl.AddError(arg->source, "failed to convert arguments");
                         return;
                     }
                     args.Push(value);
                 }
                 auto* sem = impl.program_.Sem().Get<sem::Call>(expr);
                 if (!sem) {
-                    impl.add_error(expr->source, "failed to get semantic information for call " +
-                                                     std::string(expr->TypeInfo().name));
+                    impl.AddError(expr->source, "failed to get semantic information for call " +
+                                                    std::string(expr->TypeInfo().name));
                     return;
                 }
                 auto* ty = sem->Target()->ReturnType()->Clone(impl.clone_ctx_.type_ctx);
@@ -1061,8 +1061,8 @@
             void EmitIdentifier(const ast::IdentifierExpression* i) {
                 auto* v = impl.scopes_.Get(i->identifier->symbol);
                 if (TINT_UNLIKELY(!v)) {
-                    impl.add_error(i->source,
-                                   "unable to find identifier " + i->identifier->symbol.Name());
+                    impl.AddError(i->source,
+                                  "unable to find identifier " + i->identifier->symbol.Name());
                     return;
                 }
                 Bind(i, v);
@@ -1071,14 +1071,14 @@
             void EmitLiteral(const ast::LiteralExpression* lit) {
                 auto* sem = impl.program_.Sem().Get(lit);
                 if (!sem) {
-                    impl.add_error(lit->source, "failed to get semantic information for node " +
-                                                    std::string(lit->TypeInfo().name));
+                    impl.AddError(lit->source, "failed to get semantic information for node " +
+                                                   std::string(lit->TypeInfo().name));
                     return;
                 }
                 auto* cv = sem->ConstantValue()->Clone(impl.clone_ctx_);
                 if (!cv) {
-                    impl.add_error(lit->source, "failed to get constant value for node " +
-                                                    std::string(lit->TypeInfo().name));
+                    impl.AddError(lit->source, "failed to get constant value for node " +
+                                                   std::string(lit->TypeInfo().name));
                     return;
                 }
                 auto* val = impl.builder_.Constant(cv);
@@ -1272,9 +1272,9 @@
                 scopes_.Set(l->name->symbol, let->Result(0));
             },
             [&](const ast::Override*) {
-                add_error(var->source,
-                          "found an `Override` variable. The SubstituteOverrides "
-                          "transform must be run before converting to IR");
+                AddError(var->source,
+                         "found an `Override` variable. The SubstituteOverrides "
+                         "transform must be run before converting to IR");
             },
             [&](const ast::Const*) {
                 // Skip. This should be handled by const-eval already, so the const will be a
@@ -1346,7 +1346,7 @@
     auto r = b.Build();
     if (r != Success) {
         diag::List err = std::move(r.Failure().reason);
-        err.add_note(diag::System::IR, "AST:\n" + Program::printer(program), Source{});
+        err.AddNote(diag::System::IR, "AST:\n" + Program::printer(program), Source{});
         return Failure{err};
     }
 
diff --git a/src/tint/lang/wgsl/reader/reader.cc b/src/tint/lang/wgsl/reader/reader.cc
index 77289d1..40c4f79 100644
--- a/src/tint/lang/wgsl/reader/reader.cc
+++ b/src/tint/lang/wgsl/reader/reader.cc
@@ -41,8 +41,8 @@
     if (TINT_UNLIKELY(file->content.data.size() >
                       static_cast<size_t>(std::numeric_limits<uint32_t>::max()))) {
         ProgramBuilder b;
-        b.Diagnostics().add_error(tint::diag::System::Reader,
-                                  "WGSL source must be 0xffffffff bytes or fewer");
+        b.Diagnostics().AddError(tint::diag::System::Reader,
+                                 "WGSL source must be 0xffffffff bytes or fewer");
         return Program(std::move(b));
     }
     Parser parser(file);
diff --git a/src/tint/lang/wgsl/reader/reader.h b/src/tint/lang/wgsl/reader/reader.h
index 8594250..45edcd8 100644
--- a/src/tint/lang/wgsl/reader/reader.h
+++ b/src/tint/lang/wgsl/reader/reader.h
@@ -36,7 +36,7 @@
 
 /// Parses the WGSL source, returning the parsed program.
 /// If the source fails to parse then the returned
-/// `program.Diagnostics.contains_errors()` will be true, and the
+/// `program.Diagnostics.ContainsErrors()` will be true, and the
 /// `program.Diagnostics()` will describe the error.
 /// @param file the source file
 /// @param options the configuration options to use when parsing WGSL
diff --git a/src/tint/lang/wgsl/reader/reader_bench.cc b/src/tint/lang/wgsl/reader/reader_bench.cc
index bc24e0d..ba260af 100644
--- a/src/tint/lang/wgsl/reader/reader_bench.cc
+++ b/src/tint/lang/wgsl/reader/reader_bench.cc
@@ -36,13 +36,13 @@
 void ParseWGSL(benchmark::State& state, std::string input_name) {
     auto res = bench::LoadInputFile(input_name);
     if (res != Success) {
-        state.SkipWithError(res.Failure().reason.str());
+        state.SkipWithError(res.Failure().reason.Str());
         return;
     }
     for (auto _ : state) {
         auto program = Parse(&res.Get());
-        if (program.Diagnostics().contains_errors()) {
-            state.SkipWithError(program.Diagnostics().str());
+        if (program.Diagnostics().ContainsErrors()) {
+            state.SkipWithError(program.Diagnostics().Str());
         }
     }
 }
diff --git a/src/tint/lang/wgsl/resolver/array_accessor_test.cc b/src/tint/lang/wgsl/resolver/array_accessor_test.cc
index 937568d..b3e98ed 100644
--- a/src/tint/lang/wgsl/resolver/array_accessor_test.cc
+++ b/src/tint/lang/wgsl/resolver/array_accessor_test.cc
@@ -27,9 +27,8 @@
 
 #include "src/tint/lang/wgsl/resolver/resolver.h"
 
-#include "gmock/gmock.h"
+#include "gtest/gtest.h"
 #include "src/tint/lang/core/fluent_types.h"
-#include "src/tint/lang/core/type/reference.h"
 #include "src/tint/lang/wgsl/resolver/resolver_helper_test.h"
 #include "src/tint/lang/wgsl/sem/index_accessor_expression.h"
 
diff --git a/src/tint/lang/wgsl/resolver/dependency_graph.cc b/src/tint/lang/wgsl/resolver/dependency_graph.cc
index f8b5425..cb666d5 100644
--- a/src/tint/lang/wgsl/resolver/dependency_graph.cc
+++ b/src/tint/lang/wgsl/resolver/dependency_graph.cc
@@ -107,22 +107,16 @@
     const Global* from;
     /// The Global that is depended on by #from
     const Global* to;
-};
 
-/// DependencyEdgeCmp implements the contracts of std::equal_to<DependencyEdge>
-/// and std::hash<DependencyEdge>.
-struct DependencyEdgeCmp {
+    /// @returns the hash code of the DependencyEdge
+    tint::HashCode HashCode() const { return Hash(from, to); }
+
     /// Equality operator
-    bool operator()(const DependencyEdge& lhs, const DependencyEdge& rhs) const {
-        return lhs.from == rhs.from && lhs.to == rhs.to;
-    }
-    /// Hashing operator
-    inline std::size_t operator()(const DependencyEdge& d) const { return Hash(d.from, d.to); }
+    bool operator==(const DependencyEdge& rhs) const { return from == rhs.from && to == rhs.to; }
 };
 
 /// A map of DependencyEdge to DependencyInfo
-using DependencyEdges =
-    Hashmap<DependencyEdge, DependencyInfo, 64, DependencyEdgeCmp, DependencyEdgeCmp>;
+using DependencyEdges = Hashmap<DependencyEdge, DependencyInfo, 64>;
 
 /// Global describes a module-scope variable, type or function.
 struct Global {
@@ -139,12 +133,12 @@
 
 /// Raises an error diagnostic with the given message and source.
 void AddError(diag::List& diagnostics, const std::string& msg, const Source& source) {
-    diagnostics.add_error(diag::System::Resolver, msg, source);
+    diagnostics.AddError(diag::System::Resolver, msg, source);
 }
 
 /// Raises a note diagnostic with the given message and source.
 void AddNote(diag::List& diagnostics, const std::string& msg, const Source& source) {
-    diagnostics.add_note(diag::System::Resolver, msg, source);
+    diagnostics.AddNote(diag::System::Resolver, msg, source);
 }
 
 /// DependencyScanner is used to traverse a module to build the list of
@@ -600,7 +594,7 @@
 
         graph_.ordered_globals = sorted_.Release();
 
-        return !diagnostics_.contains_errors();
+        return !diagnostics_.ContainsErrors();
     }
 
   private:
@@ -714,7 +708,7 @@
     /// SortGlobals sorts the globals into dependency order, erroring if cyclic
     /// dependencies are found. The sorted dependencies are assigned to #sorted.
     void SortGlobals() {
-        if (diagnostics_.contains_errors()) {
+        if (diagnostics_.ContainsErrors()) {
             return;  // This code assumes there are no undeclared identifiers.
         }
 
diff --git a/src/tint/lang/wgsl/resolver/dependency_graph_test.cc b/src/tint/lang/wgsl/resolver/dependency_graph_test.cc
index 5e79a3e..e435301 100644
--- a/src/tint/lang/wgsl/resolver/dependency_graph_test.cc
+++ b/src/tint/lang/wgsl/resolver/dependency_graph_test.cc
@@ -53,7 +53,7 @@
             EXPECT_TRUE(result) << this->Diagnostics();
         } else {
             EXPECT_FALSE(result);
-            EXPECT_EQ(expected_error, this->Diagnostics().str());
+            EXPECT_EQ(expected_error, this->Diagnostics().Str());
         }
         return graph;
     }
diff --git a/src/tint/lang/wgsl/resolver/incomplete_type.cc b/src/tint/lang/wgsl/resolver/incomplete_type.cc
index 61b633b..7f81517 100644
--- a/src/tint/lang/wgsl/resolver/incomplete_type.cc
+++ b/src/tint/lang/wgsl/resolver/incomplete_type.cc
@@ -32,8 +32,7 @@
 namespace tint::resolver {
 
 IncompleteType::IncompleteType(core::BuiltinType b)
-    : Base(static_cast<size_t>(tint::TypeInfo::Of<IncompleteType>().full_hashcode),
-           core::type::Flags{}),
+    : Base(static_cast<size_t>(tint::TypeCode::Of<IncompleteType>().bits), core::type::Flags{}),
       builtin(b) {}
 
 IncompleteType::~IncompleteType() = default;
diff --git a/src/tint/lang/wgsl/resolver/resolver.cc b/src/tint/lang/wgsl/resolver/resolver.cc
index 3e717d4..76b9ff9 100644
--- a/src/tint/lang/wgsl/resolver/resolver.cc
+++ b/src/tint/lang/wgsl/resolver/resolver.cc
@@ -141,7 +141,7 @@
 Resolver::~Resolver() = default;
 
 bool Resolver::Resolve() {
-    if (diagnostics_.contains_errors()) {
+    if (diagnostics_.ContainsErrors()) {
         return false;
     }
 
@@ -156,7 +156,7 @@
 
     bool result = ResolveInternal();
 
-    if (TINT_UNLIKELY(!result && !diagnostics_.contains_errors())) {
+    if (TINT_UNLIKELY(!result && !diagnostics_.ContainsErrors())) {
         AddICE("resolving failed, but no error was raised", {});
         return false;
     }
@@ -3584,9 +3584,8 @@
         },
 
         [&](Default) {
-            AddError("invalid member accessor expression. Expected vector or struct, got '" +
-                         sem_.TypeNameOf(storage_ty) + "'",
-                     expr->member->source);
+            AddError("cannot index into expression of type '" + sem_.TypeNameOf(storage_ty) + "'",
+                     expr->object->source);
             return nullptr;
         });
 }
@@ -5063,19 +5062,19 @@
     err.system = diag::System::Resolver;
     err.source = source;
     err.message = msg;
-    diagnostics_.add(std::move(err));
+    diagnostics_.Add(std::move(err));
 }
 
 void Resolver::AddError(const std::string& msg, const Source& source) const {
-    diagnostics_.add_error(diag::System::Resolver, msg, source);
+    diagnostics_.AddError(diag::System::Resolver, msg, source);
 }
 
 void Resolver::AddWarning(const std::string& msg, const Source& source) const {
-    diagnostics_.add_warning(diag::System::Resolver, msg, source);
+    diagnostics_.AddWarning(diag::System::Resolver, msg, source);
 }
 
 void Resolver::AddNote(const std::string& msg, const Source& source) const {
-    diagnostics_.add_note(diag::System::Resolver, msg, source);
+    diagnostics_.AddNote(diag::System::Resolver, msg, source);
 }
 
 }  // namespace tint::resolver
diff --git a/src/tint/lang/wgsl/resolver/resolver.h b/src/tint/lang/wgsl/resolver/resolver.h
index d51923c..fe1e497 100644
--- a/src/tint/lang/wgsl/resolver/resolver.h
+++ b/src/tint/lang/wgsl/resolver/resolver.h
@@ -104,7 +104,7 @@
     ~Resolver();
 
     /// @returns error messages from the resolver
-    std::string error() const { return diagnostics_.str(); }
+    std::string error() const { return diagnostics_.Str(); }
 
     /// @returns the list of diagnostics raised by the generator.
     const diag::List& Diagnostics() const { return diagnostics_; }
diff --git a/src/tint/lang/wgsl/resolver/resolver_test.cc b/src/tint/lang/wgsl/resolver/resolver_test.cc
index fe4027e..ad94a6f 100644
--- a/src/tint/lang/wgsl/resolver/resolver_test.cc
+++ b/src/tint/lang/wgsl/resolver/resolver_test.cc
@@ -1242,6 +1242,15 @@
 12:34 note: are you missing '()'?)");
 }
 
+TEST_F(ResolverTest, Expr_MemberAccessor_NonCompoundType) {
+    GlobalConst("depth", ty.i32(), Expr(3_i));
+    auto* mem = MemberAccessor(Ident(Source{{12, 34}}, "depth"), "x");
+    WrapInFunction(mem);
+
+    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(), R"(12:34 error: cannot index into expression of type 'i32')");
+}
+
 TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
     auto* st =
         Structure("S", Vector{Member("first_member", ty.i32()), Member("second_member", ty.f32())});
diff --git a/src/tint/lang/wgsl/resolver/sem_helper.cc b/src/tint/lang/wgsl/resolver/sem_helper.cc
index d6e8b89..e364a91 100644
--- a/src/tint/lang/wgsl/resolver/sem_helper.cc
+++ b/src/tint/lang/wgsl/resolver/sem_helper.cc
@@ -214,14 +214,14 @@
 }
 
 void SemHelper::AddError(const std::string& msg, const Source& source) const {
-    builder_->Diagnostics().add_error(diag::System::Resolver, msg, source);
+    builder_->Diagnostics().AddError(diag::System::Resolver, msg, source);
 }
 
 void SemHelper::AddWarning(const std::string& msg, const Source& source) const {
-    builder_->Diagnostics().add_warning(diag::System::Resolver, msg, source);
+    builder_->Diagnostics().AddWarning(diag::System::Resolver, msg, source);
 }
 
 void SemHelper::AddNote(const std::string& msg, const Source& source) const {
-    builder_->Diagnostics().add_note(diag::System::Resolver, msg, source);
+    builder_->Diagnostics().AddNote(diag::System::Resolver, msg, source);
 }
 }  // namespace tint::resolver
diff --git a/src/tint/lang/wgsl/resolver/uniformity.cc b/src/tint/lang/wgsl/resolver/uniformity.cc
index cf03bc7..f3f2570 100644
--- a/src/tint/lang/wgsl/resolver/uniformity.cc
+++ b/src/tint/lang/wgsl/resolver/uniformity.cc
@@ -1831,9 +1831,9 @@
         auto* control_flow = TraceBackAlongPathUntil(
             non_uniform_source, [](Node* node) { return node->affects_control_flow; });
         if (control_flow) {
-            diagnostics_.add_note(diag::System::Resolver,
-                                  "control flow depends on possibly non-uniform value",
-                                  control_flow->ast->source);
+            diagnostics_.AddNote(diag::System::Resolver,
+                                 "control flow depends on possibly non-uniform value",
+                                 control_flow->ast->source);
             // TODO(jrprice): There are cases where the function with uniformity requirements is not
             // actually inside this control flow construct, for example:
             // - A conditional interrupt (e.g. break), with a barrier elsewhere in the loop
@@ -1887,20 +1887,20 @@
                     ss << "reading from " << var_type(var) << "'" << NameFor(ident)
                        << "' may result in a non-uniform value";
                 }
-                diagnostics_.add_note(diag::System::Resolver, ss.str(), ident->source);
+                diagnostics_.AddNote(diag::System::Resolver, ss.str(), ident->source);
             },
             [&](const ast::Variable* v) {
                 auto* var = sem_.Get(v);
                 StringStream ss;
                 ss << "reading from " << var_type(var) << "'" << NameFor(v)
                    << "' may result in a non-uniform value";
-                diagnostics_.add_note(diag::System::Resolver, ss.str(), v->source);
+                diagnostics_.AddNote(diag::System::Resolver, ss.str(), v->source);
             },
             [&](const ast::CallExpression* c) {
                 auto target_name = NameFor(c->target);
                 switch (non_uniform_source->type) {
                     case Node::kFunctionCallReturnValue: {
-                        diagnostics_.add_note(
+                        diagnostics_.AddNote(
                             diag::System::Resolver,
                             "return value of '" + target_name + "' may be non-uniform", c->source);
                         break;
@@ -1911,21 +1911,21 @@
                         StringStream ss;
                         ss << "reading from " << var_type(var) << "'" << NameFor(var)
                            << "' may result in a non-uniform value";
-                        diagnostics_.add_note(diag::System::Resolver, ss.str(),
-                                              var->Declaration()->source);
+                        diagnostics_.AddNote(diag::System::Resolver, ss.str(),
+                                             var->Declaration()->source);
                         break;
                     }
                     case Node::kFunctionCallArgumentValue: {
                         auto* arg = c->args[non_uniform_source->arg_index];
                         // TODO(jrprice): Which output? (return value vs another pointer argument).
-                        diagnostics_.add_note(diag::System::Resolver,
-                                              "passing non-uniform pointer to '" + target_name +
-                                                  "' may produce a non-uniform output",
-                                              arg->source);
+                        diagnostics_.AddNote(diag::System::Resolver,
+                                             "passing non-uniform pointer to '" + target_name +
+                                                 "' may produce a non-uniform output",
+                                             arg->source);
                         break;
                     }
                     case Node::kFunctionCallPointerArgumentResult: {
-                        diagnostics_.add_note(
+                        diagnostics_.AddNote(
                             diag::System::Resolver,
                             "contents of pointer may become non-uniform after calling '" +
                                 target_name + "'",
@@ -1939,8 +1939,8 @@
                 }
             },
             [&](const ast::Expression* e) {
-                diagnostics_.add_note(diag::System::Resolver,
-                                      "result of expression may be non-uniform", e->source);
+                diagnostics_.AddNote(diag::System::Resolver,
+                                     "result of expression may be non-uniform", e->source);
             },  //
             TINT_ICE_ON_NO_MATCH);
     }
@@ -1957,7 +1957,7 @@
             error.system = diag::System::Resolver;
             error.source = source;
             error.message = msg;
-            diagnostics_.add(std::move(error));
+            diagnostics_.Add(std::move(error));
         };
 
         // Traverse the graph to generate a path from RequiredToBeUniform to the source node.
diff --git a/src/tint/lang/wgsl/resolver/uniformity_test.cc b/src/tint/lang/wgsl/resolver/uniformity_test.cc
index 4674237..c4a5000 100644
--- a/src/tint/lang/wgsl/resolver/uniformity_test.cc
+++ b/src/tint/lang/wgsl/resolver/uniformity_test.cc
@@ -53,12 +53,12 @@
     /// @param program the program
     /// @param should_pass true if `builder` program should pass the analysis, otherwise false
     void RunTest(Program&& program, bool should_pass) {
-        error_ = program.Diagnostics().str();
+        error_ = program.Diagnostics().Str();
 
         bool valid = program.IsValid();
         if (should_pass) {
             EXPECT_TRUE(valid) << error_;
-            EXPECT_FALSE(program.Diagnostics().contains_errors());
+            EXPECT_FALSE(program.Diagnostics().ContainsErrors());
         } else {
             if (kUniformityFailuresAsError) {
                 EXPECT_FALSE(valid);
diff --git a/src/tint/lang/wgsl/resolver/validator.cc b/src/tint/lang/wgsl/resolver/validator.cc
index 6e0413c..8e54a74 100644
--- a/src/tint/lang/wgsl/resolver/validator.cc
+++ b/src/tint/lang/wgsl/resolver/validator.cc
@@ -182,15 +182,15 @@
 Validator::~Validator() = default;
 
 void Validator::AddError(const std::string& msg, const Source& source) const {
-    diagnostics_.add_error(diag::System::Resolver, msg, source);
+    diagnostics_.AddError(diag::System::Resolver, msg, source);
 }
 
 void Validator::AddWarning(const std::string& msg, const Source& source) const {
-    diagnostics_.add_warning(diag::System::Resolver, msg, source);
+    diagnostics_.AddWarning(diag::System::Resolver, msg, source);
 }
 
 void Validator::AddNote(const std::string& msg, const Source& source) const {
-    diagnostics_.add_note(diag::System::Resolver, msg, source);
+    diagnostics_.AddNote(diag::System::Resolver, msg, source);
 }
 
 bool Validator::AddDiagnostic(wgsl::DiagnosticRule rule,
@@ -203,7 +203,7 @@
         d.system = diag::System::Resolver;
         d.source = source;
         d.message = msg;
-        diagnostics_.add(std::move(d));
+        diagnostics_.Add(std::move(d));
         if (severity == wgsl::DiagnosticSeverity::kError) {
             return false;
         }
diff --git a/src/tint/lang/wgsl/resolver/validator.h b/src/tint/lang/wgsl/resolver/validator.h
index 4834073..92ccf7c 100644
--- a/src/tint/lang/wgsl/resolver/validator.h
+++ b/src/tint/lang/wgsl/resolver/validator.h
@@ -98,7 +98,7 @@
     }
 
     /// @returns the hash value of this object
-    std::size_t HashCode() const { return Hash(type, address_space); }
+    tint::HashCode HashCode() const { return Hash(type, address_space); }
 };
 
 /// DiagnosticFilterStack is a scoped stack of diagnostic filters.
diff --git a/src/tint/lang/wgsl/sem/array_count.cc b/src/tint/lang/wgsl/sem/array_count.cc
index 2914e52..3e6b5e0 100644
--- a/src/tint/lang/wgsl/sem/array_count.cc
+++ b/src/tint/lang/wgsl/sem/array_count.cc
@@ -35,7 +35,7 @@
 namespace tint::sem {
 
 NamedOverrideArrayCount::NamedOverrideArrayCount(const GlobalVariable* var)
-    : Base(static_cast<size_t>(tint::TypeInfo::Of<NamedOverrideArrayCount>().full_hashcode)),
+    : Base(static_cast<size_t>(tint::TypeCode::Of<NamedOverrideArrayCount>().bits)),
       variable(var) {}
 NamedOverrideArrayCount::~NamedOverrideArrayCount() = default;
 
@@ -56,8 +56,7 @@
 }
 
 UnnamedOverrideArrayCount::UnnamedOverrideArrayCount(const ValueExpression* e)
-    : Base(static_cast<size_t>(tint::TypeInfo::Of<UnnamedOverrideArrayCount>().full_hashcode)),
-      expr(e) {}
+    : Base(static_cast<size_t>(tint::TypeCode::Of<UnnamedOverrideArrayCount>().bits)), expr(e) {}
 UnnamedOverrideArrayCount::~UnnamedOverrideArrayCount() = default;
 
 bool UnnamedOverrideArrayCount::Equals(const UniqueNode& other) const {
diff --git a/src/tint/lang/wgsl/sem/builtin_fn.h b/src/tint/lang/wgsl/sem/builtin_fn.h
index 7c5d12c..bcac245 100644
--- a/src/tint/lang/wgsl/sem/builtin_fn.h
+++ b/src/tint/lang/wgsl/sem/builtin_fn.h
@@ -123,7 +123,7 @@
     wgsl::LanguageFeature RequiredLanguageFeature() const;
 
     /// @return the hash code for this object
-    std::size_t HashCode() const {
+    tint::HashCode HashCode() const {
         return Hash(Fn(), SupportedStages(), ReturnType(), Parameters(), IsDeprecated());
     }
 
diff --git a/src/tint/lang/wgsl/sem/call_target.cc b/src/tint/lang/wgsl/sem/call_target.cc
index 37098f5..1298301 100644
--- a/src/tint/lang/wgsl/sem/call_target.cc
+++ b/src/tint/lang/wgsl/sem/call_target.cc
@@ -71,6 +71,14 @@
     return -1;
 }
 
+tint::HashCode CallTargetSignature::HashCode() const {
+    auto hash = tint::Hash(parameters.Length());
+    for (auto* p : parameters) {
+        hash = HashCombine(hash, p->Type(), p->Usage());
+    }
+    return Hash(hash, return_type);
+}
+
 bool CallTargetSignature::operator==(const CallTargetSignature& other) const {
     if (return_type != other.return_type || parameters.Length() != other.parameters.Length()) {
         return false;
@@ -86,16 +94,3 @@
 }
 
 }  // namespace tint::sem
-
-namespace std {
-
-std::size_t hash<tint::sem::CallTargetSignature>::operator()(
-    const tint::sem::CallTargetSignature& sig) const {
-    size_t hash = tint::Hash(sig.parameters.Length());
-    for (auto* p : sig.parameters) {
-        hash = HashCombine(hash, p->Type(), p->Usage());
-    }
-    return Hash(hash, sig.return_type);
-}
-
-}  // namespace std
diff --git a/src/tint/lang/wgsl/sem/call_target.h b/src/tint/lang/wgsl/sem/call_target.h
index cdf7141..24ed2ae 100644
--- a/src/tint/lang/wgsl/sem/call_target.h
+++ b/src/tint/lang/wgsl/sem/call_target.h
@@ -54,10 +54,8 @@
     /// Destructor
     ~CallTargetSignature();
 
-    /// The type of the call target return value
-    const core::type::Type* return_type = nullptr;
-    /// The parameters of the call target
-    tint::Vector<const sem::Parameter*, 8> parameters;
+    /// @returns the hash code of the CallTargetSignature
+    tint::HashCode HashCode() const;
 
     /// Equality operator
     /// @param other the signature to compare this to
@@ -76,6 +74,12 @@
         auto idx = IndexOf(usage);
         return (idx >= 0) ? parameters[static_cast<size_t>(idx)] : nullptr;
     }
+
+    /// The type of the call target return value
+    const core::type::Type* return_type = nullptr;
+
+    /// The parameters of the call target
+    tint::Vector<const sem::Parameter*, 8> parameters;
 };
 
 /// CallTarget is the base for callable functions, builtins, value constructors and value
@@ -140,19 +144,4 @@
 
 }  // namespace tint::sem
 
-namespace std {
-
-/// Custom std::hash specialization for tint::sem::CallTargetSignature so
-/// CallTargetSignature can be used as keys for std::unordered_map and
-/// std::unordered_set.
-template <>
-class hash<tint::sem::CallTargetSignature> {
-  public:
-    /// @param sig the CallTargetSignature to hash
-    /// @return the hash value
-    std::size_t operator()(const tint::sem::CallTargetSignature& sig) const;
-};
-
-}  // namespace std
-
 #endif  // SRC_TINT_LANG_WGSL_SEM_CALL_TARGET_H_
diff --git a/src/tint/lang/wgsl/sem/sampler_texture_pair.h b/src/tint/lang/wgsl/sem/sampler_texture_pair.h
index f5896b6..6d3d6ae 100644
--- a/src/tint/lang/wgsl/sem/sampler_texture_pair.h
+++ b/src/tint/lang/wgsl/sem/sampler_texture_pair.h
@@ -68,9 +68,12 @@
     }
 
     /// Reflect the fields of this class so that it can be used by tint::ForeachField()
-    TINT_REFLECT(sampler_binding_point, texture_binding_point);
+    TINT_REFLECT(SamplerTexturePair, sampler_binding_point, texture_binding_point);
 };
 
+/// Ensure that all the fields of SamplerTexturePair are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(SamplerTexturePair);
+
 /// Prints the SamplerTexturePair @p stp to @p o
 /// @param o the stream to write to
 /// @param stp the SamplerTexturePair
diff --git a/src/tint/lang/wgsl/sem/value_expression_test.cc b/src/tint/lang/wgsl/sem/value_expression_test.cc
index c3ced06..de31e95 100644
--- a/src/tint/lang/wgsl/sem/value_expression_test.cc
+++ b/src/tint/lang/wgsl/sem/value_expression_test.cc
@@ -46,7 +46,7 @@
     size_t NumElements() const override { return 0; }
     bool AllZero() const override { return {}; }
     bool AnyZero() const override { return {}; }
-    size_t Hash() const override { return 0; }
+    HashCode Hash() const override { return 0; }
     MockConstant* Clone(core::constant::CloneContext&) const override { return nullptr; }
 
   protected:
diff --git a/src/tint/lang/wgsl/wgsl.def b/src/tint/lang/wgsl/wgsl.def
index 3e3282c..33f2038 100644
--- a/src/tint/lang/wgsl/wgsl.def
+++ b/src/tint/lang/wgsl/wgsl.def
@@ -737,6 +737,7 @@
 
 @must_use @stage("compute") fn subgroupBallot() -> vec4<u32>
 @must_use @stage("compute") fn subgroupBroadcast<T: fiu32_f16>(value: T, @const sourceLaneIndex: u32) -> T
+@must_use @stage("compute") fn subgroupBroadcast<N: num, T: fiu32_f16>(value: vec<N, T>, @const sourceLaneIndex: u32) -> vec<N, T>
 
 ////////////////////////////////////////////////////////////////////////////////
 // Value constructors                                                         //
diff --git a/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc
index 517ea6d..05cce63 100644
--- a/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/wgsl/writer/ast_printer/ast_printer.cc
@@ -133,7 +133,7 @@
         }
     }
 
-    return !diagnostics_.contains_errors();
+    return !diagnostics_.ContainsErrors();
 }
 
 void ASTPrinter::EmitDiagnosticControl(StringStream& out,
@@ -349,7 +349,7 @@
 void ASTPrinter::EmitImageFormat(StringStream& out, const core::TexelFormat fmt) {
     switch (fmt) {
         case core::TexelFormat::kUndefined:
-            diagnostics_.add_error(diag::System::Writer, "unknown image format");
+            diagnostics_.AddError(diag::System::Writer, "unknown image format");
             break;
         default:
             out << fmt;
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 b3119c7..c2fff06 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
@@ -53,7 +53,7 @@
     options.allowed_features = AllowedFeatures::Everything();
     auto output_program = IRToProgram(mod, options);
     if (!output_program.IsValid()) {
-        result.err = output_program.Diagnostics().str();
+        result.err = output_program.Diagnostics().Str();
         result.ast = Program::printer(output_program);
         return result;
     }
diff --git a/src/tint/lang/wgsl/writer/options.h b/src/tint/lang/wgsl/writer/options.h
index 6fab6bb..09279a9 100644
--- a/src/tint/lang/wgsl/writer/options.h
+++ b/src/tint/lang/wgsl/writer/options.h
@@ -48,10 +48,15 @@
     /// Set to `true` to use the syntax tree writer
     bool use_syntax_tree_writer = false;
 
-    TINT_REFLECT(use_syntax_tree_writer);
+    TINT_REFLECT(Options, use_syntax_tree_writer);
 #endif
 };
 
+#ifdef TINT_BUILD_SYNTAX_TREE_WRITER
+/// Ensure that all the fields of SamplerTexturePair are reflected.
+TINT_ASSERT_ALL_FIELDS_REFLECTED(Options);
+#endif
+
 }  // namespace tint::wgsl::writer
 
 #endif  // SRC_TINT_LANG_WGSL_WRITER_OPTIONS_H_
diff --git a/src/tint/lang/wgsl/writer/writer_bench.cc b/src/tint/lang/wgsl/writer/writer_bench.cc
index 68dc9a2..285710e 100644
--- a/src/tint/lang/wgsl/writer/writer_bench.cc
+++ b/src/tint/lang/wgsl/writer/writer_bench.cc
@@ -36,13 +36,13 @@
 void GenerateWGSL(benchmark::State& state, std::string input_name) {
     auto res = bench::LoadProgram(input_name);
     if (res != Success) {
-        state.SkipWithError(res.Failure().reason.str());
+        state.SkipWithError(res.Failure().reason.Str());
         return;
     }
     for (auto _ : state) {
         auto gen_res = Generate(res->program, {});
         if (gen_res != Success) {
-            state.SkipWithError(gen_res.Failure().reason.str());
+            state.SkipWithError(gen_res.Failure().reason.Str());
         }
     }
 }
diff --git a/src/tint/utils/bytes/decoder.h b/src/tint/utils/bytes/decoder.h
index 6901f7c..a62d2e5 100644
--- a/src/tint/utils/bytes/decoder.h
+++ b/src/tint/utils/bytes/decoder.h
@@ -113,7 +113,7 @@
             if (value == Success) {
                 field = value.Get();
             } else {
-                errs.add(value.Failure().reason);
+                errs.Add(value.Failure().reason);
             }
         });
         if (errs.empty()) {
diff --git a/src/tint/utils/bytes/decoder_test.cc b/src/tint/utils/bytes/decoder_test.cc
index 3535298..d33dc42 100644
--- a/src/tint/utils/bytes/decoder_test.cc
+++ b/src/tint/utils/bytes/decoder_test.cc
@@ -114,7 +114,7 @@
     uint8_t a;
     uint16_t b;
     uint32_t c;
-    TINT_REFLECT(a, b, c);
+    TINT_REFLECT(S, a, b, c);
 };
 
 TEST(BytesDecoderTest, ReflectedObject) {
diff --git a/src/tint/utils/cli/cli_test.cc b/src/tint/utils/cli/cli_test.cc
index 273d972..470a3b7 100644
--- a/src/tint/utils/cli/cli_test.cc
+++ b/src/tint/utils/cli/cli_test.cc
@@ -165,7 +165,7 @@
 
     auto res = opts.Parse(Split("--myoption false", " "));
     ASSERT_NE(res, Success);
-    EXPECT_EQ(res.Failure().reason.str(), R"(error: unknown flag: --myoption
+    EXPECT_EQ(res.Failure().reason.Str(), R"(error: unknown flag: --myoption
 Did you mean '--my_option'?)");
 }
 
diff --git a/src/tint/utils/containers/enum_set.h b/src/tint/utils/containers/enum_set.h
index 611a314..5736c13 100644
--- a/src/tint/utils/containers/enum_set.h
+++ b/src/tint/utils/containers/enum_set.h
@@ -33,6 +33,7 @@
 #include <type_traits>
 #include <utility>
 
+#include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/traits/traits.h"
 
 namespace tint {
@@ -148,7 +149,7 @@
     inline bool Empty() const { return set == 0; }
 
     /// @return the hash value of this object
-    inline size_t HashCode() const { return std::hash<uint64_t>()(Value()); }
+    tint::HashCode HashCode() const { return Hash(Value()); }
 
     /// Equality operator
     /// @param rhs the other EnumSet to compare this to
diff --git a/src/tint/utils/containers/hashmap.h b/src/tint/utils/containers/hashmap.h
index 58f653d..69790f3 100644
--- a/src/tint/utils/containers/hashmap.h
+++ b/src/tint/utils/containers/hashmap.h
@@ -331,7 +331,7 @@
 struct Hasher<Hashmap<K, V, N, HASH, EQUAL>> {
     /// @param map the Hashmap to hash
     /// @returns a hash of the map
-    size_t operator()(const Hashmap<K, V, N, HASH, EQUAL>& map) const {
+    HashCode operator()(const Hashmap<K, V, N, HASH, EQUAL>& map) const {
         auto hash = Hash(map.Count());
         for (auto it : map) {
             // Use an XOR to ensure that the non-deterministic ordering of the map still produces
diff --git a/src/tint/utils/containers/hashmap_base.h b/src/tint/utils/containers/hashmap_base.h
index 1697959..2a86e3a 100644
--- a/src/tint/utils/containers/hashmap_base.h
+++ b/src/tint/utils/containers/hashmap_base.h
@@ -75,12 +75,12 @@
     /// Constructor using pre-computed hash and copied value.
     /// @param hash_ the precomputed hash of @p value
     /// @param value the key value
-    HashmapKey(size_t hash_, const T& value) : value_(value), hash(hash_) {}
+    HashmapKey(HashCode hash_, const T& value) : value_(value), hash(hash_) {}
 
     /// Constructor using pre-computed hash and moved value.
     /// @param hash_ the precomputed hash of @p value
     /// @param value the key value
-    HashmapKey(size_t hash_, T&& value) : value_(std::forward<T>(value)), hash(hash_) {}
+    HashmapKey(HashCode hash_, T&& value) : value_(std::forward<T>(value)), hash(hash_) {}
 
     /// Copy constructor
     HashmapKey(const HashmapKey&) = default;
@@ -145,7 +145,7 @@
     }
 
     /// The hash of value
-    const size_t hash;
+    const HashCode hash;
 };
 
 /// Writes the HashmapKey to the stream.
@@ -298,7 +298,7 @@
     /// the map is cleared, or the map is destructed.
     template <typename K>
     Entry* GetEntry(K&& key) {
-        size_t hash = Hash{}(key);
+        HashCode hash = Hash{}(key);
         auto& slot = slots_[hash % slots_.Length()];
         return slot.Find(hash, key);
     }
@@ -310,7 +310,7 @@
     /// the map is cleared, or the map is destructed.
     template <typename K>
     const Entry* GetEntry(K&& key) const {
-        size_t hash = Hash{}(key);
+        HashCode hash = Hash{}(key);
         auto& slot = slots_[hash % slots_.Length()];
         return slot.Find(hash, key);
     }
@@ -327,7 +327,7 @@
     /// @param key the key to look for.
     template <typename K = Key>
     bool Remove(K&& key) {
-        size_t hash = Hash{}(key);
+        HashCode hash = Hash{}(key);
         auto& slot = slots_[hash % slots_.Length()];
         Node** edge = &slot.nodes;
         for (auto* node = *edge; node; node = node->next) {
@@ -442,7 +442,7 @@
         /// @returns true if the Entry's hash is equal to @p hash, and the Entry's key is equal to
         /// @p value.
         template <typename T>
-        bool Equals(size_t hash, T&& value) const {
+        bool Equals(HashCode hash, T&& value) const {
             auto& key = Key();
             return key.hash == hash && HashmapBase::Equal{}(key.Value(), value);
         }
@@ -497,7 +497,7 @@
         /// The slot that will hold the edit.
         Slot& slot;
         /// The hash of the key, passed to EditAt().
-        size_t hash;
+        HashCode hash;
         /// The resolved node entry, or nullptr if EditAt() did not resolve to an existing entry.
         Entry* entry = nullptr;
 
@@ -540,7 +540,7 @@
             capacity_ += capacity_;
             Rehash();
         }
-        size_t hash = Hash{}(key);
+        HashCode hash = Hash{}(key);
         auto& slot = slots_[hash % slots_.Length()];
         auto* entry = slot.Find(hash, key);
         return {*this, slot, hash, entry};
@@ -582,7 +582,7 @@
         /// @param hash the key hash to search for.
         /// @param key the key value to search for.
         template <typename K>
-        const Entry* Find(size_t hash, K&& key) const {
+        const Entry* Find(HashCode hash, K&& key) const {
             for (auto* node = nodes; node; node = node->next) {
                 if (node->Equals(hash, key)) {
                     return &node->Entry();
@@ -595,7 +595,7 @@
         /// @param hash the key hash to search for.
         /// @param key the key value to search for.
         template <typename K>
-        Entry* Find(size_t hash, K&& key) {
+        Entry* Find(HashCode hash, K&& key) {
             for (auto* node = nodes; node; node = node->next) {
                 if (node->Equals(hash, key)) {
                     return &node->Entry();
diff --git a/src/tint/utils/containers/unique_allocator.h b/src/tint/utils/containers/unique_allocator.h
index 8d88623..b6d7224 100644
--- a/src/tint/utils/containers/unique_allocator.h
+++ b/src/tint/utils/containers/unique_allocator.h
@@ -37,7 +37,7 @@
 namespace tint {
 
 /// UniqueAllocator is used to allocate unique instances of the template type `T`.
-template <typename T, typename HASH = std::hash<T>, typename EQUAL = std::equal_to<T>>
+template <typename T, typename HASH = Hasher<T>, typename EQUAL = std::equal_to<T>>
 class UniqueAllocator {
   public:
     /// Iterator is the type returned by begin() and end()
@@ -90,7 +90,7 @@
         /// Hashing function
         /// @param e the entry
         /// @returns the hash of the entry
-        size_t operator()(T* e) const { return HASH{}(*e); }
+        HashCode operator()(T* e) const { return HASH{}(*e); }
     };
 
     /// Equality is the equality function used by the Hashset
diff --git a/src/tint/utils/containers/unique_vector.h b/src/tint/utils/containers/unique_vector.h
index bf59b06..38e4714 100644
--- a/src/tint/utils/containers/unique_vector.h
+++ b/src/tint/utils/containers/unique_vector.h
@@ -41,7 +41,7 @@
 
 /// UniqueVector is an ordered container that only contains unique items.
 /// Attempting to add a duplicate is a no-op.
-template <typename T, size_t N, typename HASH = std::hash<T>, typename EQUAL = std::equal_to<T>>
+template <typename T, size_t N, typename HASH = Hasher<T>, typename EQUAL = std::equal_to<T>>
 struct UniqueVector {
     /// STL-friendly alias to T. Used by gmock.
     using value_type = T;
diff --git a/src/tint/utils/containers/vector.h b/src/tint/utils/containers/vector.h
index 663e310..c7edd0e 100644
--- a/src/tint/utils/containers/vector.h
+++ b/src/tint/utils/containers/vector.h
@@ -777,7 +777,7 @@
 #endif
 
     /// @returns a hash code for this Vector
-    size_t HashCode() const {
+    tint::HashCode HashCode() const {
         auto hash = Hash(Length());
         for (auto& el : *this) {
             hash = HashCombine(hash, el);
@@ -1160,7 +1160,7 @@
     auto rend() const { return slice_.rend(); }
 
     /// @returns a hash code of the Vector
-    size_t HashCode() const {
+    tint::HashCode HashCode() const {
         auto hash = Hash(Length());
         for (auto& el : *this) {
             hash = HashCombine(hash, el);
diff --git a/src/tint/utils/diagnostic/diagnostic.cc b/src/tint/utils/diagnostic/diagnostic.cc
index ff0170c..404d9fa 100644
--- a/src/tint/utils/diagnostic/diagnostic.cc
+++ b/src/tint/utils/diagnostic/diagnostic.cc
@@ -66,10 +66,10 @@
 
 List& List::operator=(List&& rhs) = default;
 
-std::string List::str() const {
+std::string List::Str() const {
     diag::Formatter::Style style;
     style.print_newline_at_end = false;
-    return Formatter{style}.format(*this);
+    return Formatter{style}.Format(*this);
 }
 
 }  // namespace tint::diag
diff --git a/src/tint/utils/diagnostic/diagnostic.h b/src/tint/utils/diagnostic/diagnostic.h
index a077f47..fc4438d 100644
--- a/src/tint/utils/diagnostic/diagnostic.h
+++ b/src/tint/utils/diagnostic/diagnostic.h
@@ -137,11 +137,23 @@
     /// @return this list.
     List& operator=(List&& list);
 
-    /// adds a diagnostic to the end of this list.
+    /// Adds a diagnostic to the end of this list.
     /// @param diag the diagnostic to append to this list.
     /// @returns a reference to the new diagnostic.
     /// @note The returned reference must not be used after the list is mutated again.
-    diag::Diagnostic& add(Diagnostic&& diag) {
+    diag::Diagnostic& Add(const Diagnostic& diag) {
+        if (diag.severity >= Severity::Error) {
+            error_count_++;
+        }
+        entries_.Push(diag);
+        return entries_.Back();
+    }
+
+    /// Adds a diagnostic to the end of this list.
+    /// @param diag the diagnostic to append to this list.
+    /// @returns a reference to the new diagnostic.
+    /// @note The returned reference must not be used after the list is mutated again.
+    diag::Diagnostic& Add(Diagnostic&& diag) {
         if (diag.severity >= Severity::Error) {
             error_count_++;
         }
@@ -149,113 +161,121 @@
         return entries_.Back();
     }
 
-    /// adds a list of diagnostics to the end of this list.
+    /// Adds a list of diagnostics to the end of this list.
     /// @param list the diagnostic to append to this list.
-    void add(const List& list) {
+    void Add(const List& list) {
         for (auto diag : list) {
-            add(std::move(diag));
+            Add(std::move(diag));
         }
     }
 
-    /// adds the note message with the given Source to the end of this list.
+    /// Adds the note message with the given Source to the end of this list.
     /// @param system the system raising the note message
     /// @param note_msg the note message
     /// @param source the source of the note diagnostic
     /// @returns a reference to the new diagnostic.
     /// @note The returned reference must not be used after the list is mutated again.
-    diag::Diagnostic& add_note(System system, std::string_view note_msg, const Source& source) {
+    diag::Diagnostic& AddNote(System system, std::string_view note_msg, const Source& source) {
         diag::Diagnostic note{};
         note.severity = diag::Severity::Note;
         note.system = system;
         note.source = source;
         note.message = note_msg;
-        return add(std::move(note));
+        return Add(std::move(note));
     }
 
-    /// adds the warning message with the given Source to the end of this list.
+    /// Adds the warning message with the given Source to the end of this list.
     /// @param system the system raising the warning message
     /// @param warning_msg the warning message
     /// @param source the source of the warning diagnostic
     /// @returns a reference to the new diagnostic.
     /// @note The returned reference must not be used after the list is mutated again.
-    diag::Diagnostic& add_warning(System system,
-                                  std::string_view warning_msg,
-                                  const Source& source) {
+    diag::Diagnostic& AddWarning(System system,
+                                 std::string_view warning_msg,
+                                 const Source& source) {
         diag::Diagnostic warning{};
         warning.severity = diag::Severity::Warning;
         warning.system = system;
         warning.source = source;
         warning.message = warning_msg;
-        return add(std::move(warning));
+        return Add(std::move(warning));
     }
 
-    /// adds the error message without a source to the end of this list.
+    /// Adds the error message without a source to the end of this list.
     /// @param system the system raising the error message
     /// @param err_msg the error message
     /// @returns a reference to the new diagnostic.
     /// @note The returned reference must not be used after the list is mutated again.
-    diag::Diagnostic& add_error(System system, std::string_view err_msg) {
+    diag::Diagnostic& AddError(System system, std::string_view err_msg) {
         diag::Diagnostic error{};
         error.severity = diag::Severity::Error;
         error.system = system;
         error.message = err_msg;
-        return add(std::move(error));
+        return Add(std::move(error));
     }
 
-    /// adds the error message with the given Source to the end of this list.
+    /// Adds the error message with the given Source to the end of this list.
     /// @param system the system raising the error message
     /// @param err_msg the error message
     /// @param source the source of the error diagnostic
     /// @returns a reference to the new diagnostic.
     /// @note The returned reference must not be used after the list is mutated again.
-    diag::Diagnostic& add_error(System system, std::string_view err_msg, const Source& source) {
+    diag::Diagnostic& AddError(System system, std::string_view err_msg, const Source& source) {
         diag::Diagnostic error{};
         error.severity = diag::Severity::Error;
         error.system = system;
         error.source = source;
         error.message = err_msg;
-        return add(std::move(error));
+        return Add(std::move(error));
     }
 
-    /// adds an internal compiler error message to the end of this list.
+    /// 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
     /// @param source the source of the internal compiler error
     /// @param file the Source::File owned by this diagnostic
     /// @returns a reference to the new diagnostic.
     /// @note The returned reference must not be used after the list is mutated again.
-    diag::Diagnostic& add_ice(System system,
-                              std::string_view err_msg,
-                              const Source& source,
-                              std::shared_ptr<Source::File> file) {
+    diag::Diagnostic& AddIce(System system,
+                             std::string_view err_msg,
+                             const Source& source,
+                             std::shared_ptr<Source::File> file) {
         diag::Diagnostic ice{};
         ice.severity = diag::Severity::InternalCompilerError;
         ice.system = system;
         ice.source = source;
         ice.message = err_msg;
         ice.owned_file = std::move(file);
-        return add(std::move(ice));
+        return Add(std::move(ice));
     }
 
     /// @returns true iff the diagnostic list contains errors diagnostics (or of
     /// higher severity).
-    bool contains_errors() const { return error_count_ > 0; }
+    bool ContainsErrors() const { return error_count_ > 0; }
+    /// deprecated, use `ContainsErrors`
+    bool contains_errors() const { return ContainsErrors(); }
     /// @returns the number of error diagnostics (or of higher severity).
-    size_t error_count() const { return error_count_; }
+    size_t NumErrors() const { return error_count_; }
     /// @returns the number of entries in the list.
-    size_t count() const { return entries_.Length(); }
+    size_t Count() const { return entries_.Length(); }
+    /// @returns true if the diagnostics list is empty
+    bool IsEmpty() const { return entries_.IsEmpty(); }
+
+    /// @returns a formatted string of all the diagnostics in this list.
+    std::string Str() const;
+
+    ////////////////////////////////////////////////////////////////////////////
+    /// STL-interface support
+    ////////////////////////////////////////////////////////////////////////////
     /// @returns true if the diagnostics list is empty
     bool empty() const { return entries_.IsEmpty(); }
-    /// @returns the number of entrise in the diagnostics list
+    /// @returns the number of entries in the list.
     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.
     iterator end() const { return entries_.end(); }
 
-    /// @returns a formatted string of all the diagnostics in this list.
-    std::string str() const;
-
   private:
     Vector<Diagnostic, 0> entries_;
     size_t error_count_ = 0;
@@ -267,7 +287,7 @@
 /// @returns the output stream
 template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
 auto& operator<<(STREAM& out, const List& list) {
-    return out << list.str();
+    return out << list.Str();
 }
 
 }  // namespace tint::diag
diff --git a/src/tint/utils/diagnostic/diagnostic_test.cc b/src/tint/utils/diagnostic/diagnostic_test.cc
index f947b62..07c44fb 100644
--- a/src/tint/utils/diagnostic/diagnostic_test.cc
+++ b/src/tint/utils/diagnostic/diagnostic_test.cc
@@ -38,7 +38,7 @@
     err_a.severity = Severity::Error;
     err_b.severity = Severity::Fatal;
     List list{err_a, err_b};
-    EXPECT_EQ(list.count(), 2u);
+    EXPECT_EQ(list.Count(), 2u);
 }
 
 TEST(DiagListTest, CtorVectorRef) {
@@ -46,7 +46,7 @@
     err_a.severity = Severity::Error;
     err_b.severity = Severity::Fatal;
     List list(Vector{err_a, err_b});
-    EXPECT_EQ(list.count(), 2u);
+    EXPECT_EQ(list.Count(), 2u);
 }
 
 TEST(DiagListTest, OwnedFilesShared) {
@@ -56,12 +56,12 @@
     {
         Diagnostic diag{};
         diag.source = Source{Source::Range{{0, 0}}, file.get()};
-        list_a.add(std::move(diag));
+        list_a.Add(std::move(diag));
     }
 
     list_b = list_a;
 
-    ASSERT_EQ(list_b.count(), list_a.count());
+    ASSERT_EQ(list_b.Count(), list_a.Count());
     EXPECT_EQ(list_b.begin()->source.file, file.get());
 }
 
diff --git a/src/tint/utils/diagnostic/formatter.cc b/src/tint/utils/diagnostic/formatter.cc
index 7b4ea24..a256a8a 100644
--- a/src/tint/utils/diagnostic/formatter.cc
+++ b/src/tint/utils/diagnostic/formatter.cc
@@ -75,10 +75,10 @@
     explicit State(Printer* p) : printer(p) {}
     ~State() { flush(); }
 
-    /// set_style() sets the current style to new_style, flushing any pending
-    /// messages to the printer if the style changed.
+    /// SetStyle sets the current style to new_style, flushing any pending messages to the printer
+    /// if the style changed.
     /// @param new_style the new style to apply for future written messages.
-    void set_style(const diag::Style& new_style) {
+    void SetStyle(const diag::Style& new_style) {
         if (style.color != new_style.color || style.bold != new_style.bold) {
             flush();
             style = new_style;
@@ -89,7 +89,7 @@
     void flush() {
         auto str = stream.str();
         if (str.length() > 0) {
-            printer->write(str, style);
+            printer->Write(str, style);
             StringStream reset;
             stream.swap(reset);
         }
@@ -104,8 +104,8 @@
         return *this;
     }
 
-    /// newline queues a newline to be written to the printer.
-    void newline() { stream << std::endl; }
+    /// Newline queues a newline to be written to the printer.
+    void Newline() { stream << std::endl; }
 
     /// repeat queues the character c to be written to the printer n times.
     /// @param c the character to print `n` times
@@ -121,29 +121,29 @@
 Formatter::Formatter() {}
 Formatter::Formatter(const Style& style) : style_(style) {}
 
-void Formatter::format(const List& list, Printer* printer) const {
+void Formatter::Format(const List& list, Printer* printer) const {
     State state{printer};
 
     bool first = true;
     for (auto diag : list) {
-        state.set_style({});
+        state.SetStyle({});
         if (!first) {
-            state.newline();
+            state.Newline();
         }
-        format(diag, state);
+        Format(diag, state);
         first = false;
     }
 
     if (style_.print_newline_at_end) {
-        state.newline();
+        state.Newline();
     }
 }
 
-void Formatter::format(const Diagnostic& diag, State& state) const {
+void Formatter::Format(const Diagnostic& diag, State& state) const {
     auto const& src = diag.source;
     auto const& rng = src.range;
 
-    state.set_style({Color::kDefault, true});
+    state.SetStyle({Color::kDefault, true});
 
     struct TextAndColor {
         std::string text;
@@ -187,19 +187,19 @@
         if (i > 0) {
             state << " ";
         }
-        state.set_style({prefix[i].color, prefix[i].bold});
+        state.SetStyle({prefix[i].color, prefix[i].bold});
         state << prefix[i].text;
     }
 
-    state.set_style({Color::kDefault, true});
+    state.SetStyle({Color::kDefault, true});
     if (!prefix.empty()) {
         state << ": ";
     }
     state << diag.message;
 
     if (style_.print_line && src.file && rng.begin.line > 0) {
-        state.newline();
-        state.set_style({Color::kDefault, false});
+        state.Newline();
+        state.SetStyle({Color::kDefault, false});
 
         for (size_t line_num = rng.begin.line;
              (line_num <= rng.end.line) && (line_num <= src.file->content.lines.size());
@@ -219,7 +219,7 @@
                 }
             }
 
-            state.newline();
+            state.Newline();
 
             // If the line contains non-ascii characters, then we cannot assume that
             // a single utf8 code unit represents a single glyph, so don't attempt to
@@ -228,7 +228,7 @@
                 continue;
             }
 
-            state.set_style({Color::kCyan, false});
+            state.SetStyle({Color::kCyan, false});
 
             // Count the number of glyphs in the line span.
             // start and end use 1-based indexing.
@@ -258,16 +258,16 @@
                 // Middle of multi-line
                 state.repeat('^', num_glyphs(1, line_len + 1));
             }
-            state.newline();
+            state.Newline();
         }
 
-        state.set_style({});
+        state.SetStyle({});
     }
 }
 
-std::string Formatter::format(const List& list) const {
+std::string Formatter::Format(const List& list) const {
     StringPrinter printer;
-    format(list, &printer);
+    Format(list, &printer);
     return printer.str();
 }
 
diff --git a/src/tint/utils/diagnostic/formatter.h b/src/tint/utils/diagnostic/formatter.h
index ad18793..1841fe0 100644
--- a/src/tint/utils/diagnostic/formatter.h
+++ b/src/tint/utils/diagnostic/formatter.h
@@ -64,16 +64,18 @@
 
     /// @param list the list of diagnostic messages to format
     /// @param printer the printer used to display the formatted diagnostics
-    void format(const List& list, Printer* printer) const;
+    void Format(const List& list, Printer* printer) const;
 
     /// @return the list of diagnostics `list` formatted to a string.
     /// @param list the list of diagnostic messages to format
-    std::string format(const List& list) const;
+    std::string Format(const List& list) const;
+    /// deprecated, use `Format`
+    std::string format(const List& list) const { return Format(list); }
 
   private:
     struct State;
 
-    void format(const Diagnostic& diag, State& state) const;
+    void Format(const Diagnostic& diag, State& state) const;
 
     const Style style_;
 };
diff --git a/src/tint/utils/diagnostic/formatter_test.cc b/src/tint/utils/diagnostic/formatter_test.cc
index cde6d83..44e63dc 100644
--- a/src/tint/utils/diagnostic/formatter_test.cc
+++ b/src/tint/utils/diagnostic/formatter_test.cc
@@ -106,7 +106,7 @@
 
 TEST_F(DiagFormatterTest, Simple) {
     Formatter fmt{{false, false, false, false}};
-    auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+    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: hiss)";
@@ -115,7 +115,7 @@
 
 TEST_F(DiagFormatterTest, SimpleNewlineAtEnd) {
     Formatter fmt{{false, false, false, true}};
-    auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+    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: hiss
@@ -126,14 +126,14 @@
 TEST_F(DiagFormatterTest, SimpleNoSource) {
     Formatter fmt{{false, false, false, false}};
     auto diag = Diag(Severity::Note, Source{}, "no source!", System::Test);
-    auto got = fmt.format(List{diag});
+    auto got = fmt.Format(List{diag});
     auto* expect = "no source!";
     ASSERT_EQ(expect, got);
 }
 
 TEST_F(DiagFormatterTest, WithFile) {
     Formatter fmt{{true, false, false, false}};
-    auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+    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: hiss)";
@@ -142,7 +142,7 @@
 
 TEST_F(DiagFormatterTest, WithSeverity) {
     Formatter fmt{{false, true, false, false}};
-    auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+    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: hiss)";
@@ -151,7 +151,7 @@
 
 TEST_F(DiagFormatterTest, WithLine) {
     Formatter fmt{{false, false, true, false}};
-    auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+    auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
     auto* expect = R"(1:14: purr
 the  cat  says  meow
                 ^
@@ -169,7 +169,7 @@
 
 TEST_F(DiagFormatterTest, UnicodeWithLine) {
     Formatter fmt{{false, false, true, false}};
-    auto got = fmt.format(List{utf8_diag_note, utf8_diag_warn, utf8_diag_err});
+    auto got = fmt.Format(List{utf8_diag_note, utf8_diag_warn, utf8_diag_err});
     auto* expect =
         "1:15: purr\n"
         "the  \xf0\x9f\x90\xb1  says  meow\n"
@@ -184,7 +184,7 @@
 
 TEST_F(DiagFormatterTest, BasicWithFileSeverityLine) {
     Formatter fmt{{true, true, true, false}};
-    auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+    auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
     auto* expect = R"(file.name:1:14 note: purr
 the  cat  says  meow
                 ^
@@ -204,7 +204,7 @@
     auto multiline = Diag(Severity::Warning, Source{Source::Range{{2, 9}, {4, 15}}, &ascii_file},
                           "multiline", System::Test);
     Formatter fmt{{false, false, true, false}};
-    auto got = fmt.format(List{multiline});
+    auto got = fmt.Format(List{multiline});
     auto* expect = R"(2:9: multiline
 the  dog  says  woof
           ^^^^^^^^^^
@@ -220,7 +220,7 @@
     auto multiline = Diag(Severity::Warning, Source{Source::Range{{2, 9}, {4, 15}}, &utf8_file},
                           "multiline", System::Test);
     Formatter fmt{{false, false, true, false}};
-    auto got = fmt.format(List{multiline});
+    auto got = fmt.Format(List{multiline});
     auto* expect =
         "2:9: multiline\n"
         "the  \xf0\x9f\x90\x95  says  woof\n"
@@ -231,7 +231,7 @@
 
 TEST_F(DiagFormatterTest, BasicWithFileSeverityLineTab4) {
     Formatter fmt{{true, true, true, false, 4u}};
-    auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+    auto got = fmt.Format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
     auto* expect = R"(file.name:1:14 note: purr
 the    cat    says    meow
                       ^
@@ -251,7 +251,7 @@
     auto multiline = Diag(Severity::Warning, Source{Source::Range{{2, 9}, {4, 15}}, &ascii_file},
                           "multiline", System::Test);
     Formatter fmt{{false, false, true, false, 4u}};
-    auto got = fmt.format(List{multiline});
+    auto got = fmt.Format(List{multiline});
     auto* expect = R"(2:9: multiline
 the    dog    says    woof
               ^^^^^^^^^^^^
@@ -265,7 +265,7 @@
 
 TEST_F(DiagFormatterTest, ICE) {
     Formatter fmt{{}};
-    auto got = fmt.format(List{ascii_diag_ice});
+    auto got = fmt.Format(List{ascii_diag_ice});
     auto* expect = R"(file.name:4:16 internal compiler error: unreachable
 the  snail  says  ???
                   ^^^
@@ -276,7 +276,7 @@
 
 TEST_F(DiagFormatterTest, Fatal) {
     Formatter fmt{{}};
-    auto got = fmt.format(List{ascii_diag_fatal});
+    auto got = fmt.Format(List{ascii_diag_fatal});
     auto* expect = R"(file.name:4:16 fatal: nothing
 the  snail  says  ???
                   ^^^
@@ -288,8 +288,8 @@
 TEST_F(DiagFormatterTest, RangeOOB) {
     Formatter fmt{{true, true, true, true}};
     diag::List list;
-    list.add_error(System::Test, "oob", Source{{{10, 20}, {30, 20}}, &ascii_file});
-    auto got = fmt.format(list);
+    list.AddError(System::Test, "oob", Source{{{10, 20}, {30, 20}}, &ascii_file});
+    auto got = fmt.Format(list);
     auto* expect = R"(file.name:10:20 error: oob
 
 )";
diff --git a/src/tint/utils/diagnostic/printer.cc b/src/tint/utils/diagnostic/printer.cc
index 5f91b1b..819dc58 100644
--- a/src/tint/utils/diagnostic/printer.cc
+++ b/src/tint/utils/diagnostic/printer.cc
@@ -40,7 +40,7 @@
     return stream.str();
 }
 
-void StringPrinter::write(const std::string& str, const Style&) {
+void StringPrinter::Write(const std::string& str, const Style&) {
     stream << str;
 }
 
diff --git a/src/tint/utils/diagnostic/printer.h b/src/tint/utils/diagnostic/printer.h
index 986d76d..2b361b8 100644
--- a/src/tint/utils/diagnostic/printer.h
+++ b/src/tint/utils/diagnostic/printer.h
@@ -57,21 +57,21 @@
     bool bold = false;
 };
 
-/// Printers are used to print formatted diagnostic messages to a terminal.
+/// Printers are used to print formatted diagnostic messages to a stream.
 class Printer {
   public:
     /// @returns a diagnostic Printer
     /// @param out the file to print to.
-    /// @param use_colors if true, the printer will use colors if `out` is a
-    /// terminal and supports them.
-    static std::unique_ptr<Printer> create(FILE* out, bool use_colors);
+    /// @param use_colors if true, the printer will use colors if `out` is a terminal and supports
+    /// them.
+    static std::unique_ptr<Printer> Create(FILE* out, bool use_colors);
 
     virtual ~Printer();
 
     /// writes the string str to the printer with the given style.
     /// @param str the string to write to the printer
     /// @param style the style used to print `str`
-    virtual void write(const std::string& str, const Style& style) = 0;
+    virtual void Write(const std::string& str, const Style& style) = 0;
 };
 
 /// StringPrinter is an implementation of Printer that writes to a std::string.
@@ -83,7 +83,7 @@
     /// @returns the printed string.
     std::string str() const;
 
-    void write(const std::string& str, const Style&) override;
+    void Write(const std::string& str, const Style&) override;
 
   private:
     std::stringstream stream;
diff --git a/src/tint/utils/diagnostic/printer_other.cc b/src/tint/utils/diagnostic/printer_other.cc
index 2f93fa7..b311e5a 100644
--- a/src/tint/utils/diagnostic/printer_other.cc
+++ b/src/tint/utils/diagnostic/printer_other.cc
@@ -38,7 +38,7 @@
   public:
     explicit PrinterOther(FILE* f) : file(f) {}
 
-    void write(const std::string& str, const Style&) override {
+    void Write(const std::string& str, const Style&) override {
         fwrite(str.data(), 1, str.size(), file);
     }
 
@@ -48,7 +48,7 @@
 
 }  // namespace
 
-std::unique_ptr<Printer> Printer::create(FILE* out, bool) {
+std::unique_ptr<Printer> Printer::Create(FILE* out, bool) {
     return std::make_unique<PrinterOther>(out);
 }
 
diff --git a/src/tint/utils/diagnostic/printer_posix.cc b/src/tint/utils/diagnostic/printer_posix.cc
index 3c7ba22..156c3ce 100644
--- a/src/tint/utils/diagnostic/printer_posix.cc
+++ b/src/tint/utils/diagnostic/printer_posix.cc
@@ -61,14 +61,14 @@
   public:
     PrinterPosix(FILE* f, bool colors) : file(f), use_colors(colors && supports_colors(f)) {}
 
-    void write(const std::string& str, const Style& style) override {
-        write_color(style.color, style.bold);
+    void Write(const std::string& str, const Style& style) override {
+        WriteColor(style.color, style.bold);
         fwrite(str.data(), 1, str.size(), file);
-        write_color(Color::kDefault, false);
+        WriteColor(Color::kDefault, false);
     }
 
   private:
-    constexpr const char* color_code(Color color, bool bold) {
+    constexpr const char* ColorCode(Color color, bool bold) {
         switch (color) {
             case Color::kDefault:
                 return bold ? "\u001b[1m" : "\u001b[0m";
@@ -92,9 +92,9 @@
         return "";  // unreachable
     }
 
-    void write_color(Color color, bool bold) {
+    void WriteColor(Color color, bool bold) {
         if (use_colors) {
-            auto* code = color_code(color, bold);
+            auto* code = ColorCode(color, bold);
             fwrite(code, 1, strlen(code), file);
         }
     }
@@ -105,7 +105,7 @@
 
 }  // namespace
 
-std::unique_ptr<Printer> Printer::create(FILE* out, bool use_colors) {
+std::unique_ptr<Printer> Printer::Create(FILE* out, bool use_colors) {
     return std::make_unique<PrinterPosix>(out, use_colors);
 }
 
diff --git a/src/tint/utils/diagnostic/printer_test.cc b/src/tint/utils/diagnostic/printer_test.cc
index d847c91..aeb1fa2 100644
--- a/src/tint/utils/diagnostic/printer_test.cc
+++ b/src/tint/utils/diagnostic/printer_test.cc
@@ -49,58 +49,58 @@
 using PrinterTest = testing::Test;
 
 TEST_F(PrinterTest, WithColors) {
-    auto printer = Printer::create(stdout, true);
-    printer->write("Default", Style{Color::kDefault, false});
-    printer->write("Black", Style{Color::kBlack, false});
-    printer->write("Red", Style{Color::kRed, false});
-    printer->write("Green", Style{Color::kGreen, false});
-    printer->write("Yellow", Style{Color::kYellow, false});
-    printer->write("Blue", Style{Color::kBlue, false});
-    printer->write("Magenta", Style{Color::kMagenta, false});
-    printer->write("Cyan", Style{Color::kCyan, false});
-    printer->write("White", Style{Color::kWhite, false});
+    auto printer = Printer::Create(stdout, true);
+    printer->Write("Default", Style{Color::kDefault, false});
+    printer->Write("Black", Style{Color::kBlack, false});
+    printer->Write("Red", Style{Color::kRed, false});
+    printer->Write("Green", Style{Color::kGreen, false});
+    printer->Write("Yellow", Style{Color::kYellow, false});
+    printer->Write("Blue", Style{Color::kBlue, false});
+    printer->Write("Magenta", Style{Color::kMagenta, false});
+    printer->Write("Cyan", Style{Color::kCyan, false});
+    printer->Write("White", Style{Color::kWhite, false});
     printf("\n");
 }
 
 TEST_F(PrinterTest, BoldWithColors) {
-    auto printer = Printer::create(stdout, true);
-    printer->write("Default", Style{Color::kDefault, true});
-    printer->write("Black", Style{Color::kBlack, true});
-    printer->write("Red", Style{Color::kRed, true});
-    printer->write("Green", Style{Color::kGreen, true});
-    printer->write("Yellow", Style{Color::kYellow, true});
-    printer->write("Blue", Style{Color::kBlue, true});
-    printer->write("Magenta", Style{Color::kMagenta, true});
-    printer->write("Cyan", Style{Color::kCyan, true});
-    printer->write("White", Style{Color::kWhite, true});
+    auto printer = Printer::Create(stdout, true);
+    printer->Write("Default", Style{Color::kDefault, true});
+    printer->Write("Black", Style{Color::kBlack, true});
+    printer->Write("Red", Style{Color::kRed, true});
+    printer->Write("Green", Style{Color::kGreen, true});
+    printer->Write("Yellow", Style{Color::kYellow, true});
+    printer->Write("Blue", Style{Color::kBlue, true});
+    printer->Write("Magenta", Style{Color::kMagenta, true});
+    printer->Write("Cyan", Style{Color::kCyan, true});
+    printer->Write("White", Style{Color::kWhite, true});
     printf("\n");
 }
 
 TEST_F(PrinterTest, WithoutColors) {
-    auto printer = Printer::create(stdout, false);
-    printer->write("Default", Style{Color::kDefault, false});
-    printer->write("Black", Style{Color::kBlack, false});
-    printer->write("Red", Style{Color::kRed, false});
-    printer->write("Green", Style{Color::kGreen, false});
-    printer->write("Yellow", Style{Color::kYellow, false});
-    printer->write("Blue", Style{Color::kBlue, false});
-    printer->write("Magenta", Style{Color::kMagenta, false});
-    printer->write("Cyan", Style{Color::kCyan, false});
-    printer->write("White", Style{Color::kWhite, false});
+    auto printer = Printer::Create(stdout, false);
+    printer->Write("Default", Style{Color::kDefault, false});
+    printer->Write("Black", Style{Color::kBlack, false});
+    printer->Write("Red", Style{Color::kRed, false});
+    printer->Write("Green", Style{Color::kGreen, false});
+    printer->Write("Yellow", Style{Color::kYellow, false});
+    printer->Write("Blue", Style{Color::kBlue, false});
+    printer->Write("Magenta", Style{Color::kMagenta, false});
+    printer->Write("Cyan", Style{Color::kCyan, false});
+    printer->Write("White", Style{Color::kWhite, false});
     printf("\n");
 }
 
 TEST_F(PrinterTest, BoldWithoutColors) {
-    auto printer = Printer::create(stdout, false);
-    printer->write("Default", Style{Color::kDefault, true});
-    printer->write("Black", Style{Color::kBlack, true});
-    printer->write("Red", Style{Color::kRed, true});
-    printer->write("Green", Style{Color::kGreen, true});
-    printer->write("Yellow", Style{Color::kYellow, true});
-    printer->write("Blue", Style{Color::kBlue, true});
-    printer->write("Magenta", Style{Color::kMagenta, true});
-    printer->write("Cyan", Style{Color::kCyan, true});
-    printer->write("White", Style{Color::kWhite, true});
+    auto printer = Printer::Create(stdout, false);
+    printer->Write("Default", Style{Color::kDefault, true});
+    printer->Write("Black", Style{Color::kBlack, true});
+    printer->Write("Red", Style{Color::kRed, true});
+    printer->Write("Green", Style{Color::kGreen, true});
+    printer->Write("Yellow", Style{Color::kYellow, true});
+    printer->Write("Blue", Style{Color::kBlue, true});
+    printer->Write("Magenta", Style{Color::kMagenta, true});
+    printer->Write("Cyan", Style{Color::kCyan, true});
+    printer->Write("White", Style{Color::kWhite, true});
     printf("\n");
 }
 
diff --git a/src/tint/utils/diagnostic/printer_windows.cc b/src/tint/utils/diagnostic/printer_windows.cc
index 52d3790..485e9a9 100644
--- a/src/tint/utils/diagnostic/printer_windows.cc
+++ b/src/tint/utils/diagnostic/printer_windows.cc
@@ -43,7 +43,7 @@
     operator bool() const { return handle != INVALID_HANDLE_VALUE; }
 };
 
-ConsoleInfo console_info(FILE* file) {
+ConsoleInfo ConsoleInfoFor(FILE* file) {
     if (file == nullptr) {
         return {};
     }
@@ -69,16 +69,16 @@
 class PrinterWindows : public Printer {
   public:
     PrinterWindows(FILE* f, bool use_colors)
-        : file(f), console(console_info(use_colors ? f : nullptr)) {}
+        : file(f), console(ConsoleInfoFor(use_colors ? f : nullptr)) {}
 
-    void write(const std::string& str, const Style& style) override {
-        write_color(style.color, style.bold);
+    void Write(const std::string& str, const Style& style) override {
+        WriteColor(style.color, style.bold);
         fwrite(str.data(), 1, str.size(), file);
-        write_color(Color::kDefault, false);
+        WriteColor(Color::kDefault, false);
     }
 
   private:
-    WORD attributes(Color color, bool bold) {
+    WORD Attributes(Color color, bool bold) {
         switch (color) {
             case Color::kDefault:
                 return console.default_attributes;
@@ -103,9 +103,9 @@
         return 0;  // unreachable
     }
 
-    void write_color(Color color, bool bold) {
+    void WriteColor(Color color, bool bold) {
         if (console) {
-            SetConsoleTextAttribute(console.handle, attributes(color, bold));
+            SetConsoleTextAttribute(console.handle, Attributes(color, bold));
             fflush(file);
         }
     }
@@ -116,7 +116,7 @@
 
 }  // namespace
 
-std::unique_ptr<Printer> Printer::create(FILE* out, bool use_colors) {
+std::unique_ptr<Printer> Printer::Create(FILE* out, bool use_colors) {
     return std::make_unique<PrinterWindows>(out, use_colors);
 }
 
diff --git a/src/tint/utils/math/hash.h b/src/tint/utils/math/hash.h
index 43c97f4..a148f2c 100644
--- a/src/tint/utils/math/hash.h
+++ b/src/tint/utils/math/hash.h
@@ -40,39 +40,9 @@
 #include "src/tint/utils/math/crc32.h"
 
 namespace tint {
+
 namespace detail {
 
-/// Helper for obtaining a seed bias value for HashCombine with a bit-width
-/// dependent on the size of size_t.
-template <int SIZE_OF_SIZE_T>
-struct HashCombineOffset {};
-
-/// Specialization of HashCombineOffset for size_t == 4.
-template <>
-struct HashCombineOffset<4> {
-    /// @returns the seed bias value for HashCombine()
-    static constexpr inline uint32_t value() {
-        constexpr uint32_t base = 0x7f4a7c16;
-#ifdef TINT_HASH_SEED
-        return base ^ static_cast<uint32_t>(TINT_HASH_SEED);
-#endif
-        return base;
-    }
-};
-
-/// Specialization of HashCombineOffset for size_t == 8.
-template <>
-struct HashCombineOffset<8> {
-    /// @returns the seed bias value for HashCombine()
-    static constexpr inline uint64_t value() {
-        constexpr uint64_t base = 0x9e3779b97f4a7c16;
-#ifdef TINT_HASH_SEED
-        return base ^ static_cast<uint64_t>(TINT_HASH_SEED);
-#endif
-        return base;
-    }
-};
-
 template <typename T, typename = void>
 struct HasHashCodeMember : std::false_type {};
 
@@ -84,49 +54,53 @@
 
 }  // namespace detail
 
+/// The type of a hash code
+using HashCode = uint32_t;
+
 /// Forward declarations (see below)
 template <typename... ARGS>
-size_t Hash(const ARGS&... values);
+HashCode Hash(const ARGS&... values);
 
 template <typename... ARGS>
-size_t HashCombine(size_t hash, const ARGS&... values);
+HashCode HashCombine(HashCode hash, const ARGS&... values);
 
 /// A STL-compatible hasher that does a more thorough job than most implementations of std::hash.
 /// Hasher has been optimized for a better quality hash at the expense of increased computation
 /// costs.
 /// Hasher is specialized for various core Tint data types. The default implementation will use a
-/// `size_t HashCode()` method on the `T` type, and will fallback to `std::hash<T>` if
+/// `HashCode HashCode()` method on the `T` type, and will fallback to `std::hash<T>` if
 /// `T::HashCode` is missing.
 template <typename T>
 struct Hasher {
     /// @param value the value to hash
     /// @returns a hash of the value
-    size_t operator()(const T& value) const {
+    HashCode operator()(const T& value) const {
         if constexpr (detail::HasHashCodeMember<T>::value) {
             auto hash = value.HashCode();
-            static_assert(std::is_same_v<decltype(hash), size_t>,
-                          "T::HashCode() must return size_t");
+            static_assert(std::is_same_v<decltype(hash), HashCode>,
+                          "T::HashCode() must return HashCode");
             return hash;
         } else {
-            return std::hash<T>()(value);
+            return static_cast<HashCode>(std::hash<T>()(value));
         }
     }
 };
 
 /// Hasher specialization for pointers
-/// std::hash<T*> typically uses a reinterpret of the pointer to a size_t.
-/// As most pointers a 4 or 16 byte aligned, this usually results in the LSBs of the hash being 0,
-/// resulting in bad hashes for hashtables. This implementation mixes up those LSBs.
 template <typename T>
 struct Hasher<T*> {
     /// @param ptr the pointer to hash
     /// @returns a hash of the pointer
-    size_t operator()(T* ptr) const {
-        auto hash = static_cast<size_t>(reinterpret_cast<uintptr_t>(ptr));
+    HashCode operator()(T* ptr) const {
+        auto hash = reinterpret_cast<uintptr_t>(ptr);
 #ifdef TINT_HASH_SEED
         hash ^= static_cast<uint32_t>(TINT_HASH_SEED);
 #endif
-        return hash >> 4;
+        if constexpr (sizeof(hash) > 4) {
+            return static_cast<HashCode>(hash >> 4 | hash >> 32);
+        } else {
+            return static_cast<HashCode>(hash >> 4);
+        }
     }
 };
 
@@ -135,7 +109,7 @@
 struct Hasher<std::vector<T>> {
     /// @param vector the vector to hash
     /// @returns a hash of the vector
-    size_t operator()(const std::vector<T>& vector) const {
+    HashCode operator()(const std::vector<T>& vector) const {
         auto hash = Hash(vector.size());
         for (auto& el : vector) {
             hash = HashCombine(hash, el);
@@ -149,7 +123,7 @@
 struct Hasher<std::tuple<TYPES...>> {
     /// @param tuple the tuple to hash
     /// @returns a hash of the tuple
-    size_t operator()(const std::tuple<TYPES...>& tuple) const {
+    HashCode operator()(const std::tuple<TYPES...>& tuple) const {
         return std::apply(Hash<TYPES...>, tuple);
     }
 };
@@ -159,7 +133,9 @@
 struct Hasher<std::pair<A, B>> {
     /// @param tuple the tuple to hash
     /// @returns a hash of the tuple
-    size_t operator()(const std::pair<A, B>& tuple) const { return std::apply(Hash<A, B>, tuple); }
+    HashCode operator()(const std::pair<A, B>& tuple) const {
+        return std::apply(Hash<A, B>, tuple);
+    }
 };
 
 /// Hasher specialization for std::variant
@@ -167,7 +143,7 @@
 struct Hasher<std::variant<TYPES...>> {
     /// @param variant the variant to hash
     /// @returns a hash of the tuple
-    size_t operator()(const std::variant<TYPES...>& variant) const {
+    HashCode operator()(const std::variant<TYPES...>& variant) const {
         return std::visit([](auto&& val) { return Hash(val); }, variant);
     }
 };
@@ -178,20 +154,20 @@
 struct Hasher<std::string> {
     /// @param str the string to hash
     /// @returns a hash of the string
-    size_t operator()(const std::string& str) const {
-        return std::hash<std::string_view>()(std::string_view(str));
+    HashCode operator()(const std::string& str) const {
+        return static_cast<HashCode>(std::hash<std::string_view>()(std::string_view(str)));
     }
 
     /// @param str the string to hash
     /// @returns a hash of the string
-    size_t operator()(const char* str) const {
-        return std::hash<std::string_view>()(std::string_view(str));
+    HashCode operator()(const char* str) const {
+        return static_cast<HashCode>(std::hash<std::string_view>()(std::string_view(str)));
     }
 
     /// @param str the string to hash
     /// @returns a hash of the string
-    size_t operator()(const std::string_view& str) const {
-        return std::hash<std::string_view>()(str);
+    HashCode operator()(const std::string_view& str) const {
+        return static_cast<HashCode>(std::hash<std::string_view>()(str));
     }
 };
 
@@ -199,14 +175,14 @@
 /// @returns a hash of the variadic list of arguments.
 ///          The returned hash is dependent on the order of the arguments.
 template <typename... ARGS>
-size_t Hash(const ARGS&... args) {
+HashCode Hash(const ARGS&... args) {
     if constexpr (sizeof...(ARGS) == 0) {
         return 0;
     } else if constexpr (sizeof...(ARGS) == 1) {
         using T = std::tuple_element_t<0, std::tuple<ARGS...>>;
         return Hasher<T>()(args...);
     } else {
-        size_t hash = 102931;  // seed with an arbitrary prime
+        HashCode hash = 102931;  // seed with an arbitrary prime
         return HashCombine(hash, args...);
     }
 }
@@ -216,8 +192,13 @@
 /// @returns a hash of the variadic list of arguments.
 ///          The returned hash is dependent on the order of the arguments.
 template <typename... ARGS>
-size_t HashCombine(size_t hash, const ARGS&... values) {
-    constexpr size_t offset = tint::detail::HashCombineOffset<sizeof(size_t)>::value();
+HashCode HashCombine(HashCode hash, const ARGS&... values) {
+#ifdef TINT_HASH_SEED
+    constexpr uint32_t offset = 0x7f4a7c16 ^ static_cast<uint32_t>(TINT_HASH_SEED);
+#else
+    constexpr uint32_t offset = 0x7f4a7c16;
+#endif
+
     ((hash ^= Hash(values) + (offset ^ (hash >> 2))), ...);
     return hash;
 }
@@ -270,7 +251,7 @@
     /// The wrapped value
     T value;
     /// The hash of value
-    size_t hash;
+    HashCode hash;
 
     /// Constructor
     /// @param v the value to wrap
diff --git a/src/tint/utils/reflection/BUILD.bazel b/src/tint/utils/reflection/BUILD.bazel
index e5a25ef..28efe09 100644
--- a/src/tint/utils/reflection/BUILD.bazel
+++ b/src/tint/utils/reflection/BUILD.bazel
@@ -46,6 +46,7 @@
   ],
   deps = [
     "//src/tint/utils/macros",
+    "//src/tint/utils/math",
   ],
   copts = COPTS,
   visibility = ["//visibility:public"],
@@ -58,7 +59,10 @@
   ],
   deps = [
     "//src/tint/utils/macros",
+    "//src/tint/utils/math",
     "//src/tint/utils/reflection",
+    "//src/tint/utils/rtti",
+    "//src/tint/utils/traits",
     "@gtest",
   ],
   copts = COPTS,
diff --git a/src/tint/utils/reflection/BUILD.cmake b/src/tint/utils/reflection/BUILD.cmake
index c2af545..143b121 100644
--- a/src/tint/utils/reflection/BUILD.cmake
+++ b/src/tint/utils/reflection/BUILD.cmake
@@ -45,6 +45,7 @@
 
 tint_target_add_dependencies(tint_utils_reflection lib
   tint_utils_macros
+  tint_utils_math
 )
 
 ################################################################################
@@ -57,7 +58,10 @@
 
 tint_target_add_dependencies(tint_utils_reflection_test test
   tint_utils_macros
+  tint_utils_math
   tint_utils_reflection
+  tint_utils_rtti
+  tint_utils_traits
 )
 
 tint_target_add_external_dependencies(tint_utils_reflection_test test
diff --git a/src/tint/utils/reflection/BUILD.gn b/src/tint/utils/reflection/BUILD.gn
index 42d0ab9..721544b 100644
--- a/src/tint/utils/reflection/BUILD.gn
+++ b/src/tint/utils/reflection/BUILD.gn
@@ -47,7 +47,10 @@
     "reflection.cc",
     "reflection.h",
   ]
-  deps = [ "${tint_src_dir}/utils/macros" ]
+  deps = [
+    "${tint_src_dir}/utils/macros",
+    "${tint_src_dir}/utils/math",
+  ]
 }
 if (tint_build_unittests) {
   tint_unittests_source_set("unittests") {
@@ -55,7 +58,10 @@
     deps = [
       "${tint_src_dir}:gmock_and_gtest",
       "${tint_src_dir}/utils/macros",
+      "${tint_src_dir}/utils/math",
       "${tint_src_dir}/utils/reflection",
+      "${tint_src_dir}/utils/rtti",
+      "${tint_src_dir}/utils/traits",
     ]
   }
 }
diff --git a/src/tint/utils/reflection/reflection.h b/src/tint/utils/reflection/reflection.h
index d674db1..7d192d8 100644
--- a/src/tint/utils/reflection/reflection.h
+++ b/src/tint/utils/reflection/reflection.h
@@ -28,10 +28,18 @@
 #ifndef SRC_TINT_UTILS_REFLECTION_REFLECTION_H_
 #define SRC_TINT_UTILS_REFLECTION_REFLECTION_H_
 
+#include <cstddef>
+#include <tuple>
 #include <type_traits>
 
 #include "src/tint/utils/macros/concat.h"
 #include "src/tint/utils/macros/foreach.h"
+#include "src/tint/utils/math/math.h"
+
+/// Forward declarations
+namespace tint {
+class CastableBase;
+}
 
 namespace tint {
 
@@ -45,6 +53,60 @@
 template <typename T>
 struct HasReflection<T, std::void_t<typename T::Reflection>> : std::true_type {};
 
+/// Helper for inferring the base class size of T.
+template <typename T, typename ENABLE = void>
+struct BaseClassSize {
+    /// Zero as T::Base does not exist
+    static constexpr size_t value = 0;
+};
+
+/// Specialization for types that contain a 'Base' type alias.
+template <typename T>
+struct BaseClassSize<T, std::void_t<typename T::Base>> {
+    /// The size of T::Base, or zero if T::Base is not a base of T
+    static constexpr size_t value =
+        std::is_base_of_v<typename T::Base, T> ? sizeof(typename T::Base) : 0;
+};
+
+/// A helper to check at compile-time that all the fields of a class are passed to TINT_REFLECT().
+template <typename CLASS, size_t INDEX, size_t OFFSET, typename FIELDS, bool ASSERT = true>
+struct CheckAllFieldsReflected;
+
+/// CheckAllFieldsReflected specialization that the final computed offset matches the size of the
+/// class.
+template <typename CLASS, size_t INDEX, size_t OFFSET, bool ASSERT>
+struct CheckAllFieldsReflected<CLASS, INDEX, OFFSET, std::tuple<void>, ASSERT> {
+    /// True iff the calculated size of class from all the fields matches the actual class size.
+    static constexpr bool value =
+        tint::RoundUp(alignof(CLASS), BaseClassSize<CLASS>::value + OFFSET) == sizeof(CLASS);
+    static_assert(value || (ASSERT == false),
+                  "TINT_REFLECT() was not passed all the fields of the class, or the fields were "
+                  "not passed in the same order they're declared in the class");
+};
+
+/// CheckAllFieldsReflected specialization that the field with index INDEX is at the expected offset
+/// in the class.
+template <typename CLASS,
+          size_t INDEX,
+          size_t OFFSET,
+          typename FIELD,
+          bool ASSERT,
+          typename... OTHERS>
+struct CheckAllFieldsReflected<CLASS, INDEX, OFFSET, std::tuple<FIELD, OTHERS...>, ASSERT> {
+    /// True iff the calculated size of class from all the fields matches the actual class size.
+    static constexpr bool value =
+        CheckAllFieldsReflected<CLASS,
+                                INDEX + 1,
+                                tint::RoundUp(alignof(FIELD), OFFSET) + sizeof(FIELD),
+                                std::tuple<OTHERS...>,
+                                ASSERT>::value;
+};
+
+/// Evaluates to true if type `T` can be used with TINT_ASSERT_ALL_FIELDS_REFLECTED().
+template <typename T>
+static constexpr bool CanUseTintAssertAllFieldsReflected =
+    !std::has_virtual_destructor_v<T> || std::is_base_of_v<CastableBase, T>;
+
 }  // namespace detail
 
 /// Is true if the class T has reflected its fields with TINT_REFLECT()
@@ -59,23 +121,39 @@
 void ForeachField(OBJECT&& object, CB&& callback) {
     using T = std::decay_t<OBJECT>;
     static_assert(HasReflection<T>, "object type requires a tint::Reflect<> specialization");
-    T::Reflection::Fields(object, callback);
+    T::Reflection::ForeachField(object, callback);
 }
 
+/// Macro used by TINT_FOREACH() in TINT_REFLECT() to generate the T::Reflection::Fields tuple.
+#define TINT_REFLECT_FIELD_TYPE(FIELD) decltype(Class::FIELD),
+
 /// Macro used by TINT_FOREACH() in TINT_REFLECT() to call the callback function with each field in
 /// the variadic.
-#define TINT_REFLECT_CALLBACK_FIELD(field) callback(object.field);
+#define TINT_REFLECT_CALLBACK_FIELD(FIELD) callback(object.FIELD);
 
-// TINT_REFLECT(...) reflects each of the fields arguments so that the types can be used with
-// tint::ForeachField().
-#define TINT_REFLECT(...)                                          \
-    struct Reflection {                                            \
-        template <typename OBJECT, typename CB>                    \
-        static void Fields(OBJECT&& object, CB&& callback) {       \
-            TINT_FOREACH(TINT_REFLECT_CALLBACK_FIELD, __VA_ARGS__) \
-        }                                                          \
+// TINT_REFLECT(CLASS, ...) reflects each of the fields arguments of CLASS so that the types can be
+// used with tint::ForeachField().
+#define TINT_REFLECT(CLASS, ...)                                                            \
+    struct Reflection {                                                                     \
+        using Class = CLASS;                                                                \
+        using Fields = std::tuple<TINT_FOREACH(TINT_REFLECT_FIELD_TYPE, __VA_ARGS__) void>; \
+        template <typename OBJECT, typename CB>                                             \
+        [[maybe_unused]] static void ForeachField(OBJECT&& object, CB&& callback) {         \
+            TINT_FOREACH(TINT_REFLECT_CALLBACK_FIELD, __VA_ARGS__)                          \
+        }                                                                                   \
     }
 
+/// TINT_ASSERT_ALL_FIELDS_REFLECTED(...) performs a compile-time assertion that all the fields of
+/// CLASS have been reflected with TINT_REFLECT().
+/// @note The order in which the fields are passed to TINT_REFLECT must match the declaration order
+/// in the class.
+#define TINT_ASSERT_ALL_FIELDS_REFLECTED(CLASS)                                                   \
+    static_assert(::tint::detail::CanUseTintAssertAllFieldsReflected<CLASS>,                      \
+                  "TINT_ASSERT_ALL_FIELDS_REFLECTED() cannot be used on virtual classes, except " \
+                  "for types using the tint::Castable framework");                                \
+    static_assert(                                                                                \
+        ::tint::detail::CheckAllFieldsReflected<CLASS, 0, 0, CLASS::Reflection::Fields>::value)
+
 /// A template that can be specialized to reflect the valid range of an enum
 /// Use TINT_REFLECT_ENUM_RANGE to specialize this class
 template <typename T>
diff --git a/src/tint/utils/reflection/reflection_test.cc b/src/tint/utils/reflection/reflection_test.cc
index d7335d5..558c1bf 100644
--- a/src/tint/utils/reflection/reflection_test.cc
+++ b/src/tint/utils/reflection/reflection_test.cc
@@ -27,6 +27,7 @@
 
 #include "src/tint/utils/reflection/reflection.h"
 #include "gtest/gtest.h"
+#include "src/tint/utils/rtti/castable.h"
 
 namespace tint {
 namespace {
@@ -35,7 +36,7 @@
     int i;
     unsigned u;
     bool b;
-    TINT_REFLECT(i, u, b);
+    TINT_REFLECT(S, i, u, b);
 };
 
 static_assert(!HasReflection<int>);
@@ -100,5 +101,57 @@
     EXPECT_EQ(s.b, false);
 }
 
+////////////////////////////////////////////////////////////////////////////////
+// TINT_ASSERT_ALL_FIELDS_REFLECTED tests
+////////////////////////////////////////////////////////////////////////////////
+static_assert(detail::CanUseTintAssertAllFieldsReflected<S> == true);
+
+struct VirtualNonCastable {
+    virtual ~VirtualNonCastable() = default;
+};
+static_assert(detail::CanUseTintAssertAllFieldsReflected<VirtualNonCastable> == false);
+
+struct VirtualCastable : Castable<VirtualCastable, CastableBase> {
+    ~VirtualCastable() override = default;
+    int a, b, c;
+    TINT_REFLECT(VirtualCastable, a, b, c);
+};
+static_assert(detail::CanUseTintAssertAllFieldsReflected<VirtualCastable> == true);
+static_assert(detail::CheckAllFieldsReflected<VirtualCastable,
+                                              0,
+                                              0,
+                                              VirtualCastable::Reflection::Fields,
+                                              /* assert */ false>::value == true);
+
+struct MissingFirst {
+    int a, b, c;
+    TINT_REFLECT(MissingFirst, b, c);
+};
+static_assert(detail::CheckAllFieldsReflected<MissingFirst,
+                                              0,
+                                              0,
+                                              MissingFirst::Reflection::Fields,
+                                              /* assert */ false>::value == false);
+
+struct MissingMid {
+    int a, b, c;
+    TINT_REFLECT(MissingMid, a, c);
+};
+static_assert(detail::CheckAllFieldsReflected<MissingMid,
+                                              0,
+                                              0,
+                                              MissingMid::Reflection::Fields,
+                                              /* assert */ false>::value == false);
+
+struct MissingLast {
+    int a, b, c;
+    TINT_REFLECT(MissingLast, a, b);
+};
+static_assert(detail::CheckAllFieldsReflected<MissingLast,
+                                              0,
+                                              0,
+                                              MissingLast::Reflection::Fields,
+                                              /* assert */ false>::value == false);
+
 }  // namespace
 }  // namespace tint
diff --git a/src/tint/utils/result/result.cc b/src/tint/utils/result/result.cc
index 2450bee..016e2fb 100644
--- a/src/tint/utils/result/result.cc
+++ b/src/tint/utils/result/result.cc
@@ -32,7 +32,7 @@
 Failure::Failure() = default;
 
 Failure::Failure(std::string_view err) {
-    reason.add_error(diag::System::Unknown, err, Source{});
+    reason.AddError(diag::System::Unknown, err, Source{});
 }
 
 Failure::Failure(diag::Diagnostic diagnostic) : reason(diag::List{std::move(diagnostic)}) {}
diff --git a/src/tint/utils/rtti/castable.cc b/src/tint/utils/rtti/castable.cc
index 3b23676..5c47323 100644
--- a/src/tint/utils/rtti/castable.cc
+++ b/src/tint/utils/rtti/castable.cc
@@ -33,11 +33,8 @@
 /// @return doxygen-thinks-this-static-field-is-a-function :(
 template <>
 const TypeInfo tint::detail::TypeInfoOf<CastableBase>::info{
-    nullptr,
-    "CastableBase",
-    tint::TypeInfo::HashCodeOf<CastableBase>(),
-    tint::TypeInfo::FullHashCodeOf<CastableBase>(),
-};
+    nullptr, "CastableBase", tint::TypeCode::Of<CastableBase>(),
+    tint::TypeCodeSet::OfHierarchy<CastableBase>()};
 
 CastableBase::CastableBase(const CastableBase&) = default;
 
diff --git a/src/tint/utils/rtti/castable.h b/src/tint/utils/rtti/castable.h
index e877d23..c944074 100644
--- a/src/tint/utils/rtti/castable.h
+++ b/src/tint/utils/rtti/castable.h
@@ -34,7 +34,9 @@
 #include <type_traits>
 #include <utility>
 
+#include "src/tint/utils/macros/compiler.h"
 #include "src/tint/utils/math/crc32.h"
+#include "src/tint/utils/math/hash.h"
 #include "src/tint/utils/rtti/ignore.h"
 #include "src/tint/utils/traits/traits.h"
 
@@ -43,15 +45,15 @@
 #define TINT_CASTABLE_PUSH_DISABLE_WARNINGS()                                 \
     _Pragma("clang diagnostic push")                                     /**/ \
         _Pragma("clang diagnostic ignored \"-Wundefined-var-template\"") /**/ \
-        static_assert(true, "require extra semicolon")
+        TINT_REQUIRE_SEMICOLON
 
 /// Restore disabled warnings
 #define TINT_CASTABLE_POP_DISABLE_WARNINGS() \
     _Pragma("clang diagnostic pop") /**/     \
-        static_assert(true, "require extra semicolon")
+        TINT_REQUIRE_SEMICOLON
 #else
-#define TINT_CASTABLE_PUSH_DISABLE_WARNINGS() static_assert(true, "require extra semicolon")
-#define TINT_CASTABLE_POP_DISABLE_WARNINGS() static_assert(true, "require extra semicolon")
+#define TINT_CASTABLE_PUSH_DISABLE_WARNINGS() TINT_REQUIRE_SEMICOLON
+#define TINT_CASTABLE_POP_DISABLE_WARNINGS() TINT_REQUIRE_SEMICOLON
 #endif
 
 TINT_CASTABLE_PUSH_DISABLE_WARNINGS();
@@ -81,8 +83,8 @@
     const tint::TypeInfo tint::detail::TypeInfoOf<CLASS>::info{ \
         &tint::detail::TypeInfoOf<CLASS::TrueBase>::info,       \
         #CLASS,                                                 \
-        tint::TypeInfo::HashCodeOf<CLASS>(),                    \
-        tint::TypeInfo::FullHashCodeOf<CLASS>(),                \
+        tint::TypeCode::Of<CLASS>(),                            \
+        tint::TypeCodeSet::OfHierarchy<CLASS>(),                \
     };                                                          \
     TINT_CASTABLE_POP_DISABLE_WARNINGS();                       \
     static_assert(std::is_same_v<CLASS, CLASS::Base::Class>,    \
@@ -97,33 +99,89 @@
     kDontErrorOnImpossibleCast = 1,
 };
 
-/// The type of a hash code
-using HashCode = uint64_t;
+/// TypeCode is a bit pattern used by Tint's RTTI system to determine whether two types are related
+/// by inheritance.
+/// Each TypeCode has exactly two bits set.
+struct TypeCode {
+    /// @returns a compile-time TypeCode for the type `T`.
+    template <typename T>
+    static constexpr inline TypeCode Of() {
+        static_assert(IsCastable<T>, "T is not Castable");
+        static_assert(std::is_same_v<T, std::remove_cv_t<T>>,
+                      "Strip const / volatile decorations before calling Of");
+        /// Use the compiler's "pretty" function name, which includes the template type, to obtain a
+        /// unique hash value.
+#ifdef _MSC_VER
+        constexpr Bits crc = tint::CRC32(__FUNCSIG__);
+#else
+        constexpr Bits crc = tint::CRC32(__PRETTY_FUNCTION__);
+#endif
+        constexpr Bits bit_a = (crc & 63);
+        constexpr Bits bit_b = ((crc >> 6) & 63);
+        constexpr Bits bit_c = (bit_a == bit_b) ? ((bit_a + 1) & 63) : bit_b;
+        return {(static_cast<Bits>(1) << bit_a) | (static_cast<Bits>(1) << bit_c)};
+    }
 
-/// Maybe checks to see if an object with the full hashcode @p object_full_hashcode could
-/// potentially be of, or derive from the type with the hashcode @p query_hashcode.
-/// @param type_hashcode the hashcode of the type
-/// @param object_full_hashcode the full hashcode of the object being queried
-/// @returns true if the object with the given full hashcode could be one of the template types.
-inline bool Maybe(HashCode type_hashcode, HashCode object_full_hashcode) {
-    return (object_full_hashcode & type_hashcode) == type_hashcode;
-}
+    /// The unsigned integer type that holds the bits of the TypeCode
+    using Bits = uint64_t;
 
-/// MaybeAnyOf checks to see if an object with the full hashcode @p object_full_hashcode could
-/// potentially be of, or derive from the types with the combined hashcode @p combined_hashcode.
-/// @param combined_hashcode the bitwise OR'd hashcodes of the types
-/// @param object_full_hashcode the full hashcode of the object being queried
-/// @returns true if the object with the given full hashcode could be one of the template types.
-inline bool MaybeAnyOf(HashCode combined_hashcode, HashCode object_full_hashcode) {
-    // Compare the object's hashcode to the bitwise-or of all the tested type's hashcodes. If
-    // there's no intersection of bits in the two masks, then we can guarantee that the type is not
-    // in `TO`.
-    HashCode mask = object_full_hashcode & combined_hashcode;
-    // HashCodeOf() ensures that two bits are always set for every hash, so we can quickly
-    // eliminate the bitmask where only one bit is set.
-    HashCode two_bits = mask & (mask - 1);
-    return two_bits != 0;
-}
+    /// The bits pattern of the TypeCode
+    const Bits bits;
+};
+
+/// TypeCodeSet is a set of TypeCodes, and internally uses a single integer to represent its
+/// contents. TypeCodeSet acts as a bloom-filter, exposing methods to query whether the set _may_
+/// contain one or more TypeCodes. If these methods return `false` then the set definitely does
+/// contain the TypeCode(s), however returning `true` means the *set has a possibility* of
+/// containing the TypeCodes(s).
+/// @see https://en.wikipedia.org/wiki/Bloom_filter
+struct TypeCodeSet {
+    /// @returns the TypeCodeSet that contains the TypeCode of `T` and all its ancestor types.
+    template <typename T>
+    static constexpr inline TypeCodeSet OfHierarchy() {
+        if constexpr (std::is_same_v<T, CastableBase>) {
+            return {TypeCode::Of<T>().bits};
+        } else {
+            return {TypeCode::Of<T>().bits | TypeCodeSet::OfHierarchy<typename T::TrueBase>().bits};
+        }
+    }
+
+    /// @returns the TypeCodeSet of all the types in the tuple `TUPLE`.
+    template <typename TUPLE>
+    static constexpr inline TypeCodeSet OfTuple() {
+        constexpr auto kCount = std::tuple_size_v<TUPLE>;
+        if constexpr (kCount == 0) {
+            return {0};
+        } else if constexpr (kCount == 1) {
+            return {TypeCode::Of<std::remove_cv_t<std::tuple_element_t<0, TUPLE>>>().bits};
+        } else {
+            constexpr auto kMid = kCount / 2;
+            return {OfTuple<tint::traits::SliceTuple<0, kMid, TUPLE>>().bits |
+                    OfTuple<tint::traits::SliceTuple<kMid, kCount - kMid, TUPLE>>().bits};
+        }
+    }
+
+    /// @returns true if this TypeCodeSet may contain the TypeCode @p type_code.
+    inline bool MayContain(TypeCode type_code) const {
+        return (bits & type_code.bits) == type_code.bits;
+    }
+
+    /// @returns true if TypeCodeSet may contain any of the TypeCodes in @p type_codes.
+    inline bool MayContainAnyOf(TypeCodeSet type_codes) const {
+        // TypeCode always has exactly two bits set, so if the intersection of this TypeCodeSet and
+        // type_codes contains fewer than two bits set, we know there's no possibility of the same
+        // type being part of both sets.
+        Bits mask = bits & type_codes.bits;
+        bool has_at_least_two_bits = (mask & (mask - 1)) != 0;
+        return has_at_least_two_bits;
+    }
+
+    /// The unsigned integer type that holds the bits of the TypeCode
+    using Bits = typename TypeCode::Bits;
+
+    /// The bits pattern of the TypeCode
+    const Bits bits;
+};
 
 /// TypeInfo holds type information for a Castable type.
 struct TypeInfo {
@@ -131,10 +189,10 @@
     const TypeInfo* base;
     /// The type name
     const char* name;
-    /// The type hash code
-    const HashCode hashcode;
-    /// The type hash code bitwise-or'd with all ancestor's hashcodes.
-    const HashCode full_hashcode;
+    /// The type's TypeCode
+    const TypeCode type_code;
+    /// The set of this type's TypeCode and all ancestor's TypeCodes
+    const TypeCodeSet full_type_code;
 
     /// @returns true if `type` derives from the class `TO`
     /// @param object the object type to test from, which must be, or derive from type `FROM`.
@@ -169,7 +227,7 @@
     /// @returns true if the class with this TypeInfo is of, or derives from the
     /// class with the given TypeInfo.
     inline bool Is(const tint::TypeInfo* type) const {
-        if (!Maybe(type->hashcode, full_hashcode)) {
+        if (!full_type_code.MayContain(type->type_code)) {
             return false;
         }
 
@@ -189,62 +247,6 @@
         return tint::detail::TypeInfoOf<std::remove_cv_t<T>>::info;
     }
 
-    /// @returns a compile-time hashcode for the type `T`.
-    /// @note the returned hashcode will have exactly 2 bits set, as the hashes are expected to be
-    /// used in bloom-filters which will quickly saturate when multiple hashcodes are bitwise-or'd
-    /// together.
-    template <typename T>
-    static constexpr HashCode HashCodeOf() {
-        static_assert(IsCastable<T>, "T is not Castable");
-        static_assert(std::is_same_v<T, std::remove_cv_t<T>>,
-                      "Strip const / volatile decorations before calling HashCodeOf");
-        /// Use the compiler's "pretty" function name, which includes the template
-        /// type, to obtain a unique hash value.
-#ifdef _MSC_VER
-        constexpr uint32_t crc = tint::CRC32(__FUNCSIG__);
-#else
-        constexpr uint32_t crc = tint::CRC32(__PRETTY_FUNCTION__);
-#endif
-        constexpr uint32_t bit_a = (crc & 63);
-        constexpr uint32_t bit_b = ((crc >> 6) & 63);
-        constexpr uint32_t bit_c = (bit_a == bit_b) ? ((bit_a + 1) & 63) : bit_b;
-        return (static_cast<HashCode>(1) << bit_a) | (static_cast<HashCode>(1) << bit_c);
-    }
-
-    /// @returns the hashcode of the given type, bitwise-or'd with the hashcodes of all base
-    /// classes.
-    template <typename T>
-    static constexpr HashCode FullHashCodeOf() {
-        if constexpr (std::is_same_v<T, CastableBase>) {
-            return HashCodeOf<CastableBase>();
-        } else {
-            return HashCodeOf<T>() | FullHashCodeOf<typename T::TrueBase>();
-        }
-    }
-
-    /// @returns the bitwise-or'd hashcodes of all the types of the tuple `TUPLE`.
-    /// @see HashCodeOf
-    template <typename TUPLE>
-    static constexpr HashCode CombinedHashCodeOfTuple() {
-        constexpr auto kCount = std::tuple_size_v<TUPLE>;
-        if constexpr (kCount == 0) {
-            return 0;
-        } else if constexpr (kCount == 1) {
-            return HashCodeOf<std::remove_cv_t<std::tuple_element_t<0, TUPLE>>>();
-        } else {
-            constexpr auto kMid = kCount / 2;
-            return CombinedHashCodeOfTuple<tint::traits::SliceTuple<0, kMid, TUPLE>>() |
-                   CombinedHashCodeOfTuple<tint::traits::SliceTuple<kMid, kCount - kMid, TUPLE>>();
-        }
-    }
-
-    /// @returns the bitwise-or'd hashcodes of all the template parameter types.
-    /// @see HashCodeOf
-    template <typename... TYPES>
-    static constexpr HashCode CombinedHashCodeOf() {
-        return CombinedHashCodeOfTuple<std::tuple<TYPES...>>();
-    }
-
     /// @returns true if this TypeInfo is of, or derives from any of the types in `TUPLE`.
     template <typename TUPLE>
     inline bool IsAnyOfTuple() const {
@@ -254,7 +256,7 @@
         } else if constexpr (kCount == 1) {
             return Is(&Of<std::tuple_element_t<0, TUPLE>>());
         } else {
-            if (MaybeAnyOf(TypeInfo::CombinedHashCodeOfTuple<TUPLE>(), full_hashcode)) {
+            if (full_type_code.MayContainAnyOf(TypeCodeSet::OfTuple<TUPLE>())) {
                 // Possibly one of the types in `TUPLE`.
                 // Split the search in two, and scan each block.
                 static constexpr auto kMid = kCount / 2;