[ir] Support non-type template parameters

* Switches template parameters in ir::Call to TemplateParameter
  * brought into scope from core::intrinsic for convenience
* updates all uses
* Still not yet used in core or any backend

Bug: 520804445
Change-Id: I41302444cd528c8dd0a65fc7ad716272e1dda48f
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/317195
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Alan Baker <alanbaker@google.com>
diff --git a/src/tint/api/helpers/BUILD.bazel b/src/tint/api/helpers/BUILD.bazel
index 3720526..1120f7f 100644
--- a/src/tint/api/helpers/BUILD.bazel
+++ b/src/tint/api/helpers/BUILD.bazel
@@ -52,6 +52,7 @@
     "//src/tint/api/common",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/intrinsic",
     "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/utils",
diff --git a/src/tint/api/helpers/BUILD.cmake b/src/tint/api/helpers/BUILD.cmake
index 41b4ed2..07ae970 100644
--- a/src/tint/api/helpers/BUILD.cmake
+++ b/src/tint/api/helpers/BUILD.cmake
@@ -47,6 +47,7 @@
   tint_api_common
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_intrinsic
   tint_lang_core_ir
   tint_lang_core_type
   tint_utils
diff --git a/src/tint/api/helpers/BUILD.gn b/src/tint/api/helpers/BUILD.gn
index bdee779..72964b0 100644
--- a/src/tint/api/helpers/BUILD.gn
+++ b/src/tint/api/helpers/BUILD.gn
@@ -49,6 +49,7 @@
     "${tint_src_dir}/api/common",
     "${tint_src_dir}/lang/core",
     "${tint_src_dir}/lang/core/constant",
+    "${tint_src_dir}/lang/core/intrinsic",
     "${tint_src_dir}/lang/core/ir",
     "${tint_src_dir}/lang/core/type",
     "${tint_src_dir}/utils",
diff --git a/src/tint/cmd/tint/BUILD.bazel b/src/tint/cmd/tint/BUILD.bazel
index 3aade87..c74ad23 100644
--- a/src/tint/cmd/tint/BUILD.bazel
+++ b/src/tint/cmd/tint/BUILD.bazel
@@ -52,6 +52,7 @@
     "//src/tint/cmd/common",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/intrinsic",
     "//src/tint/lang/core/ir",
     "//src/tint/lang/core/ir/transform",
     "//src/tint/lang/core/type",
diff --git a/src/tint/cmd/tint/BUILD.cmake b/src/tint/cmd/tint/BUILD.cmake
index aba4727..138f5ed 100644
--- a/src/tint/cmd/tint/BUILD.cmake
+++ b/src/tint/cmd/tint/BUILD.cmake
@@ -49,6 +49,7 @@
   tint_cmd_common
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_intrinsic
   tint_lang_core_ir
   tint_lang_core_ir_transform
   tint_lang_core_type
diff --git a/src/tint/cmd/tint/BUILD.gn b/src/tint/cmd/tint/BUILD.gn
index ab7887c..37991b6 100644
--- a/src/tint/cmd/tint/BUILD.gn
+++ b/src/tint/cmd/tint/BUILD.gn
@@ -50,6 +50,7 @@
     "${tint_src_dir}/cmd/common",
     "${tint_src_dir}/lang/core",
     "${tint_src_dir}/lang/core/constant",
+    "${tint_src_dir}/lang/core/intrinsic",
     "${tint_src_dir}/lang/core/ir",
     "${tint_src_dir}/lang/core/ir/transform",
     "${tint_src_dir}/lang/core/type",
diff --git a/src/tint/lang/core/intrinsic/table.cc b/src/tint/lang/core/intrinsic/table.cc
index cb383d7..40b8da8 100644
--- a/src/tint/lang/core/intrinsic/table.cc
+++ b/src/tint/lang/core/intrinsic/table.cc
@@ -741,31 +741,26 @@
 Result<Overload, StyledText> LookupMemberFn(Context& context,
                                             std::string_view intrinsic_name,
                                             size_t function_id,
-                                            VectorRef<const core::type::Type*> template_args,
+                                            VectorRef<TemplateParameter> template_args,
                                             VectorRef<const core::type::Type*> args,
                                             EvaluationStage earliest_eval_stage) {
     // Generates an error when no overloads match the provided arguments
-    // TODO(520804445): Support templated member functions with non-type parameters.
-    Vector<TemplateParameter, 1> converted;
-    converted.Reserve(template_args.Length());
-    for (auto* ty : template_args) {
-        converted.Push(ty);
-    }
     auto on_no_match = [&](VectorRef<Candidate> candidates) {
         StyledText err;
-        err << "no matching call to " << CallSignature(intrinsic_name, converted, args) << "\n";
+        err << "no matching call to " << CallSignature(intrinsic_name, template_args, args) << "\n";
         if (!candidates.IsEmpty()) {
             err << "\n"
                 << candidates.Length() << " candidate function"
                 << (candidates.Length() > 1 ? "s:" : ":") << "\n";
-            PrintCandidates(err, context, candidates, intrinsic_name, converted, args);
+            PrintCandidates(err, context, candidates, intrinsic_name, template_args, args);
         }
         return err;
     };
 
     // Resolve the intrinsic overload
-    return MatchIntrinsic(context, context.data.builtins[function_id], intrinsic_name, converted,
-                          args, earliest_eval_stage, /* member_function */ true, on_no_match);
+    return MatchIntrinsic(context, context.data.builtins[function_id], intrinsic_name,
+                          template_args, args, earliest_eval_stage, /* member_function */ true,
+                          on_no_match);
 }
 
 Result<Overload, StyledText> LookupUnary(Context& context,
@@ -923,19 +918,14 @@
 Result<Overload, StyledText> LookupCtorConv(Context& context,
                                             std::string_view type_name,
                                             size_t type_id,
-                                            VectorRef<const core::type::Type*> template_args,
+                                            VectorRef<TemplateParameter> template_args,
                                             VectorRef<const core::type::Type*> args,
                                             EvaluationStage earliest_eval_stage) {
     // Generates an error when no overloads match the provided arguments
-    // TODO(520804445): Support ctor/conv with non-type template parameters.
-    Vector<TemplateParameter, 1> converted;
-    converted.Reserve(template_args.Length());
-    for (auto* ty : template_args) {
-        converted.Push(ty);
-    }
     auto on_no_match = [&](VectorRef<Candidate> candidates) {
         StyledText err;
-        err << "no matching constructor for " << CallSignature(type_name, converted, args) << "\n";
+        err << "no matching constructor for " << CallSignature(type_name, template_args, args)
+            << "\n";
         Candidates ctor, conv;
         for (auto candidate : candidates) {
             if (candidate.overload->flags.Contains(OverloadFlag::kIsConstructor)) {
@@ -948,19 +938,19 @@
             err << "\n"
                 << ctor.Length() << " candidate constructor" << (ctor.Length() > 1 ? "s:" : ":")
                 << "\n";
-            PrintCandidates(err, context, ctor, type_name, converted, args);
+            PrintCandidates(err, context, ctor, type_name, template_args, args);
         }
         if (!conv.IsEmpty()) {
             err << "\n"
                 << conv.Length() << " candidate conversion" << (conv.Length() > 1 ? "s:" : ":")
                 << "\n";
-            PrintCandidates(err, context, conv, type_name, converted, args);
+            PrintCandidates(err, context, conv, type_name, template_args, args);
         }
         return err;
     };
 
     // Resolve the intrinsic overload
-    return MatchIntrinsic(context, context.data.ctor_conv[type_id], type_name, converted, args,
+    return MatchIntrinsic(context, context.data.ctor_conv[type_id], type_name, template_args, args,
                           earliest_eval_stage, /* member_function */ false, on_no_match);
 }
 
diff --git a/src/tint/lang/core/intrinsic/table.h b/src/tint/lang/core/intrinsic/table.h
index 7650cd7..7328d9e 100644
--- a/src/tint/lang/core/intrinsic/table.h
+++ b/src/tint/lang/core/intrinsic/table.h
@@ -29,8 +29,10 @@
 #define SRC_TINT_LANG_CORE_INTRINSIC_TABLE_H_
 
 #include <memory>
+#include <ostream>
 #include <string>
 #include <utility>
+#include <variant>
 
 #include "src/tint/lang/core/binary_op.h"
 #include "src/tint/lang/core/enums.h"
@@ -183,7 +185,7 @@
 Result<Overload, StyledText> LookupMemberFn(Context& context,
                                             std::string_view function_name,
                                             size_t function_id,
-                                            VectorRef<const core::type::Type*> template_args,
+                                            VectorRef<TemplateParameter> template_args,
                                             VectorRef<const core::type::Type*> args,
                                             EvaluationStage earliest_eval_stage);
 
@@ -241,7 +243,7 @@
 Result<Overload, StyledText> LookupCtorConv(Context& context,
                                             std::string_view type_name,
                                             size_t type_id,
-                                            VectorRef<const core::type::Type*> template_args,
+                                            VectorRef<TemplateParameter> template_args,
                                             VectorRef<const core::type::Type*> args,
                                             EvaluationStage earliest_eval_stage);
 
@@ -299,7 +301,7 @@
     /// @return the resolved builtin function overload
     Result<Overload, StyledText> Lookup(BuiltinFn builtin_fn,
                                         const core::type::Type* object,
-                                        VectorRef<const core::type::Type*> template_args,
+                                        VectorRef<TemplateParameter> template_args,
                                         VectorRef<const core::type::Type*> args,
                                         EvaluationStage earliest_eval_stage) {
         // Push the object type into the argument list.
@@ -365,7 +367,7 @@
     ///        after shader creation time (EvaluationStage::kConstant).
     /// @return the resolved type constructor or conversion function overload
     Result<Overload, StyledText> Lookup(CtorConv type,
-                                        VectorRef<const core::type::Type*> template_args,
+                                        VectorRef<TemplateParameter> template_args,
                                         VectorRef<const core::type::Type*> args,
                                         EvaluationStage earliest_eval_stage) {
         std::string_view name = DIALECT::ToString(type);
@@ -396,6 +398,19 @@
     }
 };
 
+template <typename STREAM, typename... TYPES>
+    requires(traits::IsOStream<STREAM>)
+auto& operator<<(STREAM& out, const core::intrinsic::TemplateParameter param) {
+    if (std::holds_alternative<const core::type::Type*>(param)) {
+        out << (std::get<const core::type::Type*>(param))->FriendlyName();
+    } else if (std::holds_alternative<core::Majorness>(param)) {
+        out << std::get<core::Majorness>(param);
+    } else {
+        TINT_UNREACHABLE() << "Unhandled template kind";
+    }
+    return out;
+}
+
 }  // namespace tint
 
 #endif  // SRC_TINT_LANG_CORE_INTRINSIC_TABLE_H_
diff --git a/src/tint/lang/core/intrinsic/table_test.cc b/src/tint/lang/core/intrinsic/table_test.cc
index 2040057..613d4e9 100644
--- a/src/tint/lang/core/intrinsic/table_test.cc
+++ b/src/tint/lang/core/intrinsic/table_test.cc
@@ -801,8 +801,8 @@
 TEST_F(CoreIntrinsicTableTest, MatchTypeInitializer) {
     auto* i32 = ty.i32();
     auto* vec3i = ty.vec3i();
-    auto result = table.Lookup(CtorConv::kVec3, Vector{i32}, Vector{i32, i32, i32},
-                               EvaluationStage::kConstant);
+    auto result = table.Lookup(CtorConv::kVec3, Vector<TemplateParameter, 1>{i32},
+                               Vector{i32, i32, i32}, EvaluationStage::kConstant);
     ASSERT_EQ(result, Success);
     EXPECT_EQ(result->return_type, vec3i);
     EXPECT_TRUE(result->info->flags.Contains(OverloadFlag::kIsConstructor));
@@ -816,8 +816,8 @@
 TEST_F(CoreIntrinsicTableTest, MismatchTypeInitializer) {
     auto* i32 = ty.i32();
     auto* f32 = ty.f32();
-    auto result = table.Lookup(CtorConv::kVec3, Vector{i32}, Vector{i32, f32, i32},
-                               EvaluationStage::kConstant);
+    auto result = table.Lookup(CtorConv::kVec3, Vector<TemplateParameter, 1>{i32},
+                               Vector{i32, f32, i32}, EvaluationStage::kConstant);
     ASSERT_NE(result, Success);
     EXPECT_EQ(result.Failure().Plain(),
               R"(no matching constructor for 'vec3<i32>(i32, f32, i32)'
@@ -863,8 +863,8 @@
 TEST_F(CoreIntrinsicTableTest, MatchTypeInitializer_ConstantEval) {
     auto* i32 = ty.i32();
     auto* vec3i = ty.vec3i();
-    auto result = table.Lookup(CtorConv::kVec3, Vector{i32}, Vector{i32, i32, i32},
-                               EvaluationStage::kConstant);
+    auto result = table.Lookup(CtorConv::kVec3, Vector<TemplateParameter, 1>{i32},
+                               Vector{i32, i32, i32}, EvaluationStage::kConstant);
     ASSERT_EQ(result, Success);
     EXPECT_NE(result->const_eval_fn, nullptr);
     EXPECT_EQ(result->return_type, vec3i);
@@ -878,8 +878,8 @@
 
 TEST_F(CoreIntrinsicTableTest, MatchTypeInitializer_RuntimeEval) {
     auto* i32 = ty.i32();
-    auto result = table.Lookup(CtorConv::kVec3, Vector{i32}, Vector{i32, i32, i32},
-                               EvaluationStage::kRuntime);
+    auto result = table.Lookup(CtorConv::kVec3, Vector<TemplateParameter, 1>{i32},
+                               Vector{i32, i32, i32}, EvaluationStage::kRuntime);
     auto* vec3i = ty.vec3i();
     ASSERT_EQ(result, Success);
     EXPECT_NE(result->const_eval_fn, nullptr);
@@ -896,8 +896,8 @@
     auto* i32 = ty.i32();
     auto* vec3i = ty.vec3i();
     auto* vec3f = ty.vec3f();
-    auto result =
-        table.Lookup(CtorConv::kVec3, Vector{i32}, Vector{vec3f}, EvaluationStage::kConstant);
+    auto result = table.Lookup(CtorConv::kVec3, Vector<TemplateParameter, 1>{i32}, Vector{vec3f},
+                               EvaluationStage::kConstant);
     ASSERT_EQ(result, Success);
     EXPECT_EQ(result->return_type, vec3i);
     EXPECT_FALSE(result->info->flags.Contains(OverloadFlag::kIsConstructor));
@@ -908,8 +908,8 @@
 TEST_F(CoreIntrinsicTableTest, MismatchTypeConversion) {
     auto* arr = ty.runtime_array(ty.u32());
     auto* f32 = ty.f32();
-    auto result =
-        table.Lookup(CtorConv::kVec3, Vector{f32}, Vector{arr}, EvaluationStage::kConstant);
+    auto result = table.Lookup(CtorConv::kVec3, Vector<TemplateParameter, 1>{f32}, Vector{arr},
+                               EvaluationStage::kConstant);
     ASSERT_NE(result, Success);
     EXPECT_EQ(result.Failure().Plain(),
               R"(no matching constructor for 'vec3<f32>(array<u32>)'
@@ -955,8 +955,8 @@
     auto* f32 = ty.f32();
     auto* vec3i = ty.vec3i();
     auto* vec3f = ty.vec3f();
-    auto result =
-        table.Lookup(CtorConv::kVec3, Vector{f32}, Vector{vec3i}, EvaluationStage::kConstant);
+    auto result = table.Lookup(CtorConv::kVec3, Vector<TemplateParameter, 1>{f32}, Vector{vec3i},
+                               EvaluationStage::kConstant);
     ASSERT_EQ(result, Success);
     EXPECT_NE(result->const_eval_fn, nullptr);
     // NOTE: Conversions are explicit, so there's no way to have it return abstracts
@@ -970,8 +970,8 @@
     auto* f32 = ty.f32();
     auto* vec3i = ty.vec3i();
     auto* vec3f = ty.vec3f();
-    auto result =
-        table.Lookup(CtorConv::kVec3, Vector{f32}, Vector{vec3i}, EvaluationStage::kRuntime);
+    auto result = table.Lookup(CtorConv::kVec3, Vector<TemplateParameter, 1>{f32}, Vector{vec3i},
+                               EvaluationStage::kRuntime);
     ASSERT_EQ(result, Success);
     EXPECT_NE(result->const_eval_fn, nullptr);
     EXPECT_EQ(result->return_type, vec3f);
diff --git a/src/tint/lang/core/ir/analysis/subgroup_matrix_test.cc b/src/tint/lang/core/ir/analysis/subgroup_matrix_test.cc
index fda2e08..895631d 100644
--- a/src/tint/lang/core/ir/analysis/subgroup_matrix_test.cc
+++ b/src/tint/lang/core/ir/analysis/subgroup_matrix_test.cc
@@ -544,8 +544,8 @@
             b.Load(b.Var("right", ty.ptr(function, ty.subgroup_matrix_right(ty.f32(), 8u, 2u))));
 
         b.Let("result", b.CallExplicit(ty.subgroup_matrix_result(ty.f32(), 8u, 8u),
-                                       core::BuiltinFn::kSubgroupMatrixMultiply, Vector{ty.f32()},
-                                       left, right));
+                                       core::BuiltinFn::kSubgroupMatrixMultiply,
+                                       Vector<TemplateParameter, 1>{ty.f32()}, left, right));
 
         b.Return(func);
     });
@@ -676,8 +676,8 @@
             b.Load(b.Var("right", ty.ptr(function, ty.subgroup_matrix_right(ty.i8(), 8u, 2u))));
 
         b.Let("result", b.CallExplicit(ty.subgroup_matrix_result(ty.i32(), 8u, 8u),
-                                       core::BuiltinFn::kSubgroupMatrixMultiply, Vector{ty.i32()},
-                                       left, right));
+                                       core::BuiltinFn::kSubgroupMatrixMultiply,
+                                       Vector<TemplateParameter, 1>{ty.i32()}, left, right));
 
         b.Return(func);
     });
@@ -741,8 +741,8 @@
             b.Load(b.Var("right", ty.ptr(function, ty.subgroup_matrix_right(ty.f32(), 8u, 2u))));
 
         b.Let("result", b.CallExplicit(ty.subgroup_matrix_result(ty.f32(), 8u, 8u),
-                                       core::BuiltinFn::kSubgroupMatrixMultiply, Vector{ty.f32()},
-                                       left, right));
+                                       core::BuiltinFn::kSubgroupMatrixMultiply,
+                                       Vector<TemplateParameter, 1>{ty.f32()}, left, right));
 
         auto* if_ = b.If(true);
         b.Append(if_->True(), [&] {
@@ -753,7 +753,7 @@
 
             b.Let("result2", b.CallExplicit(ty.subgroup_matrix_result(ty.u32(), 8u, 8u),
                                             core::BuiltinFn::kSubgroupMatrixMultiply,
-                                            Vector{ty.u32()}, left2, right2));
+                                            Vector<TemplateParameter, 1>{ty.u32()}, left2, right2));
 
             b.Exit(if_);
         });
diff --git a/src/tint/lang/core/ir/binary/decode.cc b/src/tint/lang/core/ir/binary/decode.cc
index 31484cf..49973f1 100644
--- a/src/tint/lang/core/ir/binary/decode.cc
+++ b/src/tint/lang/core/ir/binary/decode.cc
@@ -584,9 +584,9 @@
     ir::CoreBuiltinCall* CreateInstructionBuiltinCall(const pb::InstructionBuiltinCall& call_in) {
         auto* call_out = mod_out_.CreateInstruction<ir::CoreBuiltinCall>();
         call_out->SetFunc(BuiltinFn(call_in.builtin()));
-        Vector<const core::type::Type*, 1> params;
-        for (auto param : call_in.explicit_template_params()) {
-            params.Push(Type(param));
+        Vector<TemplateParameter, 1> params;
+        for (auto param : call_in.explicit_template_parameters()) {
+            params.Push(CreateTemplateParameter(param));
         }
         call_out->SetExplicitTemplateParams(params);
         return call_out;
@@ -1278,6 +1278,28 @@
         return value_out;
     }
 
+    ir::TemplateParameter CreateTemplateParameter(const pb::TemplateParameter& value_in) {
+        ir::TemplateParameter value_out = nullptr;
+        switch (value_in.kind_case()) {
+            case pb::TemplateParameter::KindCase::kType:
+                value_out = Type(value_in.type());
+                break;
+            case pb::TemplateParameter::KindCase::kMajorness:
+                value_out = Majorness(value_in.majorness());
+                break;
+            case pb::TemplateParameter::KindCase::KIND_NOT_SET:
+                break;
+        }
+
+        if (value_out.index() == std::variant_npos) {
+            err_ << "invalid template parameter kind: " << std::to_string(value_in.kind_case())
+                 << "\n";
+            return mod_out_.Types().invalid();
+        }
+
+        return value_out;
+    }
+
     ir::InstructionResult* InstructionResult(const pb::InstructionResult& res_in) {
         auto* type = Type(res_in.type());
         if (type == nullptr || type->Is<core::type::Invalid>()) {
diff --git a/src/tint/lang/core/ir/binary/encode.cc b/src/tint/lang/core/ir/binary/encode.cc
index d77e256..1304bef 100644
--- a/src/tint/lang/core/ir/binary/encode.cc
+++ b/src/tint/lang/core/ir/binary/encode.cc
@@ -284,8 +284,16 @@
     void InstructionBuiltinCall(pb::InstructionBuiltinCall& call_out,
                                 const ir::CoreBuiltinCall* call_in) {
         call_out.set_builtin(BuiltinFn(call_in->Func()));
-        for (auto* param : call_in->ExplicitTemplateParams()) {
-            call_out.add_explicit_template_params(Type(param));
+        for (auto param : call_in->ExplicitTemplateParams()) {
+            if (std::holds_alternative<const core::type::Type*>(param)) {
+                auto* p = call_out.add_explicit_template_parameters();
+                p->set_type(Type(std::get<const core::type::Type*>(param)));
+            } else if (std::holds_alternative<core::Majorness>(param)) {
+                auto* p = call_out.add_explicit_template_parameters();
+                p->set_majorness(Majorness(std::get<core::Majorness>(param)));
+            } else {
+                TINT_ICE() << "invalid template parameter kind";
+            }
         }
     }
 
@@ -879,6 +887,18 @@
         TINT_ICE() << "invalid Access: " << in;
     }
 
+    pb::Majorness Majorness(core::Majorness in) {
+        switch (in) {
+            case core::Majorness::kRowMajor:
+                return pb::Majorness::row_major;
+            case core::Majorness::kColMajor:
+                return pb::Majorness::col_major;
+            case core::Majorness::kUndefined:
+                break;
+        }
+        TINT_ICE() << "invalid Majorness: " << in;
+    }
+
     pb::UnaryOp UnaryOp(core::UnaryOp in) {
         switch (in) {
             case core::UnaryOp::kComplement:
diff --git a/src/tint/lang/core/ir/builder.h b/src/tint/lang/core/ir/builder.h
index 639b5de..e1809d8 100644
--- a/src/tint/lang/core/ir/builder.h
+++ b/src/tint/lang/core/ir/builder.h
@@ -1040,7 +1040,7 @@
     template <typename VAL>
     ir::CoreBuiltinCall* Bitcast(const core::type::Type* type, VAL&& val) {
         return CallExplicit(type, core::BuiltinFn::kBitcast,
-                            Vector<const core::type::Type*, 1>{type},
+                            Vector<core::ir::TemplateParameter, 1>{type},
                             Vector{Value(std::forward<VAL>(val))});
     }
 
@@ -1062,7 +1062,8 @@
     template <typename VAL>
     ir::CoreBuiltinCall* BitcastWithResult(ir::InstructionResult* result, VAL&& val) {
         return CallExplicitWithResult<ir::CoreBuiltinCall>(
-            result, core::BuiltinFn::kBitcast, Vector<const core::type::Type*, 1>{result->Type()},
+            result, core::BuiltinFn::kBitcast,
+            Vector<core::ir::TemplateParameter, 1>{result->Type()},
             Vector{Value(std::forward<VAL>(val))});
     }
 
@@ -1157,7 +1158,7 @@
         requires(tint::traits::IsTypeOrDerived<KLASS, ir::BuiltinCall>)
     KLASS* CallExplicitWithResult(ir::InstructionResult* result,
                                   FUNC func,
-                                  VectorRef<const core::type::Type*> explicit_params,
+                                  VectorRef<core::ir::TemplateParameter> explicit_params,
                                   ARGS&&... args) {
         auto* inst = ir.CreateInstruction<KLASS>(result, func, Values(std::forward<ARGS>(args)...));
         inst->SetExplicitTemplateParams(explicit_params);
@@ -1186,7 +1187,7 @@
         requires(tint::traits::IsTypeOrDerived<KLASS, ir::BuiltinCall>)
     KLASS* CallExplicit(const core::type::Type* type,
                         FUNC func,
-                        VectorRef<const core::type::Type*> explicit_params,
+                        VectorRef<core::ir::TemplateParameter> explicit_params,
                         ARGS&&... args) {
         return CallExplicitWithResult<KLASS>(InstructionResult(type), func, explicit_params,
                                              Values(std::forward<ARGS>(args)...));
@@ -1201,7 +1202,7 @@
     template <typename... ARGS>
     ir::CoreBuiltinCall* CallExplicit(const core::type::Type* type,
                                       core::BuiltinFn func,
-                                      VectorRef<const core::type::Type*> explicit_params,
+                                      VectorRef<core::ir::TemplateParameter> explicit_params,
                                       ARGS&&... args) {
         return CallExplicitWithResult<core::ir::CoreBuiltinCall>(
             InstructionResult(type), func, explicit_params, Values(std::forward<ARGS>(args)...));
diff --git a/src/tint/lang/core/ir/call.h b/src/tint/lang/core/ir/call.h
index 8cb6c6b..3a23536 100644
--- a/src/tint/lang/core/ir/call.h
+++ b/src/tint/lang/core/ir/call.h
@@ -31,12 +31,15 @@
 #include <span>
 #include <string>
 
+#include "src/tint/lang/core/intrinsic/table.h"
 #include "src/tint/lang/core/ir/operand_instruction.h"
 #include "src/tint/lang/core/type/type.h"
 #include "src/tint/utils/rtti/castable.h"
 
 namespace tint::core::ir {
 
+using TemplateParameter = core::intrinsic::TemplateParameter;
+
 /// A Call instruction in the IR.
 class Call : public Castable<Call, OperandInstruction<4, 1>> {
   public:
@@ -46,12 +49,12 @@
     virtual size_t ArgsOperandOffset() const { return 0; }
 
     /// Sets the explicit template params for the call
-    void SetExplicitTemplateParams(VectorRef<const core::type::Type*> params) {
+    void SetExplicitTemplateParams(VectorRef<TemplateParameter> params) {
         explicit_template_params_ = params;
     }
 
     /// Retrieves the explicit template params for the call
-    tint::VectorRef<const core::type::Type*> ExplicitTemplateParams() const {
+    tint::VectorRef<TemplateParameter> ExplicitTemplateParams() const {
         return explicit_template_params_;
     }
 
@@ -78,7 +81,7 @@
     /// Constructor
     explicit Call(Id id);
 
-    Vector<const core::type::Type*, 1> explicit_template_params_;
+    Vector<TemplateParameter, 1> explicit_template_params_;
 };
 
 }  // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/core_builtin_call_test.cc b/src/tint/lang/core/ir/core_builtin_call_test.cc
index a4a7d5e..5f0615b 100644
--- a/src/tint/lang/core/ir/core_builtin_call_test.cc
+++ b/src/tint/lang/core/ir/core_builtin_call_test.cc
@@ -111,7 +111,7 @@
 
 TEST_F(IR_CoreBuiltinCallTest, CloneWithExplicitParams) {
     auto* builtin = b.Call(mod.Types().i32(), core::BuiltinFn::kAbs, 1_u);
-    builtin->SetExplicitTemplateParams(Vector{mod.Types().i32()});
+    builtin->SetExplicitTemplateParams(Vector<TemplateParameter, 1>{mod.Types().i32()});
 
     auto* new_b = clone_ctx.Clone(builtin);
     EXPECT_NE(builtin->Result(), new_b->Result());
diff --git a/src/tint/lang/core/ir/disassembler.cc b/src/tint/lang/core/ir/disassembler.cc
index 0856499..33f0066 100644
--- a/src/tint/lang/core/ir/disassembler.cc
+++ b/src/tint/lang/core/ir/disassembler.cc
@@ -37,6 +37,7 @@
 #include "src/tint/lang/core/constant/scalar.h"
 #include "src/tint/lang/core/constant/splat.h"
 #include "src/tint/lang/core/constant/string.h"
+#include "src/tint/lang/core/intrinsic/table.h"
 #include "src/tint/lang/core/ir/binary.h"
 #include "src/tint/lang/core/ir/block.h"
 #include "src/tint/lang/core/ir/block_param.h"
@@ -556,7 +557,7 @@
                     if (i > 0) {
                         out_ << ", ";
                     }
-                    out_ << ep[i]->FriendlyName();
+                    out_ << ep[i];
                 }
                 out_ << ">";
             }
diff --git a/src/tint/lang/core/ir/evaluator.cc b/src/tint/lang/core/ir/evaluator.cc
index 8c960ca..9e4b086 100644
--- a/src/tint/lang/core/ir/evaluator.cc
+++ b/src/tint/lang/core/ir/evaluator.cc
@@ -155,8 +155,8 @@
 
     auto mat_vec = [&](const core::type::Type* type,
                        core::intrinsic::CtorConv intrinsic) -> constant::Eval::Result {
-        auto op =
-            table.Lookup(intrinsic, Vector{type}, arg_types, core::EvaluationStage::kOverride);
+        auto op = table.Lookup(intrinsic, Vector<TemplateParameter, 1>{type}, arg_types,
+                               core::EvaluationStage::kOverride);
         if (op != Success) {
             AddError(SourceOf(c)) << "unable to find intrinsic for construct: " << op.Failure();
             return Failure();
@@ -345,15 +345,9 @@
         args.Push(val);
     }
 
-    // TODO(520804445): Remove this when calls support additionally template kinds.
-    Vector<core::intrinsic::TemplateParameter, 1> converted;
-    converted.Reserve(c->ExplicitTemplateParams().Length());
-    for (auto* ty : c->ExplicitTemplateParams()) {
-        converted.Push(ty);
-    }
-    auto overload =
-        core::intrinsic::LookupFn(context, c->FriendlyName().c_str(), c->FuncId(), converted,
-                                  arg_types, core::EvaluationStage::kOverride);
+    auto overload = core::intrinsic::LookupFn(context, c->FriendlyName().c_str(), c->FuncId(),
+                                              c->ExplicitTemplateParams(), arg_types,
+                                              core::EvaluationStage::kOverride);
     if (overload != Success) {
         AddError(SourceOf(c)) << overload.Failure();
         return Failure();
diff --git a/src/tint/lang/core/ir/functional_validator.cc b/src/tint/lang/core/ir/functional_validator.cc
index c7451a1..864a490 100644
--- a/src/tint/lang/core/ir/functional_validator.cc
+++ b/src/tint/lang/core/ir/functional_validator.cc
@@ -693,8 +693,8 @@
     auto arg_types = Transform<4>(args, [&](auto* v) { return v->Type(); });
     if (auto* vec = result_type->As<core::type::Vector>()) {
         auto ctor_conv = intrinsic::VectorCtorConv(vec->Width());
-        auto match = table.Lookup(ctor_conv, Vector{vec->Type()}, std::move(arg_types),
-                                  core::EvaluationStage::kConstant);
+        auto match = table.Lookup(ctor_conv, Vector<TemplateParameter, 1>{vec->Type()},
+                                  std::move(arg_types), core::EvaluationStage::kConstant);
         if (match != Success || vec->Type() != arg_types[0]->DeepestElement()) {
             AddError(construct) << "no matching overload for " << vec->FriendlyName()
                                 << " constructor";
@@ -704,8 +704,8 @@
 
     if (auto* mat = result_type->As<core::type::Matrix>()) {
         auto ctor_conv = intrinsic::MatrixCtorConv(mat->Columns(), mat->Rows());
-        auto match = table.Lookup(ctor_conv, Vector{mat->Type()}, std::move(arg_types),
-                                  core::EvaluationStage::kConstant);
+        auto match = table.Lookup(ctor_conv, Vector<TemplateParameter, 1>{mat->Type()},
+                                  std::move(arg_types), core::EvaluationStage::kConstant);
         if (match != Success) {
             AddError(construct) << "no matching overload for " << mat->FriendlyName()
                                 << " constructor";
@@ -1205,15 +1205,10 @@
 void Functional::CheckBuiltinCall(const BuiltinCall* call) {
     auto args = Transform<8>(call->Args(), [&](const ir::Value* v) { return v->Type(); });
 
-    // TODO(520804445): Remove this when calls support more template kinds.
-    Vector<core::intrinsic::TemplateParameter, 1> converted;
-    converted.Reserve(call->ExplicitTemplateParams().Length());
-    for (auto* ty : call->ExplicitTemplateParams()) {
-        converted.Push(ty);
-    }
     intrinsic::Context context{call->TableData(), type_mgr_, symbols_};
     auto builtin = core::intrinsic::LookupFn(context, call->FriendlyName().c_str(), call->FuncId(),
-                                             converted, args, core::EvaluationStage::kRuntime);
+                                             call->ExplicitTemplateParams(), args,
+                                             core::EvaluationStage::kRuntime);
     if (builtin != Success) {
         AddError(call) << builtin.Failure();
         return;
@@ -1378,7 +1373,7 @@
     auto* value_type = convert->Operand(Convert::kValueOperandOffset)->Type();
 
     intrinsic::CtorConv conv_ty;
-    Vector<const core::type::Type*, 1> template_type;
+    Vector<TemplateParameter, 1> template_type;
     tint::Switch(
         result_type,                                                             //
         [&](const core::type::I32*) { conv_ty = intrinsic::CtorConv::kI32; },    //
diff --git a/src/tint/lang/core/ir/structural_validator.cc b/src/tint/lang/core/ir/structural_validator.cc
index f18d29b..8780fda 100644
--- a/src/tint/lang/core/ir/structural_validator.cc
+++ b/src/tint/lang/core/ir/structural_validator.cc
@@ -2503,15 +2503,10 @@
 
     auto args = Transform<8>(call->Args(), [&](const ir::Value* v) { return v->Type(); });
 
-    // TODO(520804445): Remove this when calls support more template kinds.
-    Vector<core::intrinsic::TemplateParameter, 1> converted;
-    converted.Reserve(call->ExplicitTemplateParams().Length());
-    for (auto* ty : call->ExplicitTemplateParams()) {
-        converted.Push(ty);
-    }
     intrinsic::Context context{call->TableData(), type_mgr_, symbols_};
     auto builtin = core::intrinsic::LookupFn(context, call->FriendlyName().c_str(), call->FuncId(),
-                                             converted, args, core::EvaluationStage::kRuntime);
+                                             call->ExplicitTemplateParams(), args,
+                                             core::EvaluationStage::kRuntime);
     if (builtin != Success) {
         AddError(call) << builtin.Failure();
         return;
diff --git a/src/tint/lang/core/ir/transform/array_length_from_immediate_test.cc b/src/tint/lang/core/ir/transform/array_length_from_immediate_test.cc
index 2d76e12..4612366 100644
--- a/src/tint/lang/core/ir/transform/array_length_from_immediate_test.cc
+++ b/src/tint/lang/core/ir/transform/array_length_from_immediate_test.cc
@@ -1897,7 +1897,8 @@
     auto* foo = b.ComputeFunction("foo", 1_u, 1_u, 1_u);
     b.Append(foo->Block(), [&] {
         auto* offset = b.Let("offset", 16_u);
-        auto* view = b.CallExplicit(S_ptr, core::BuiltinFn::kBufferView, Vector{S}, gv, offset);
+        auto* view = b.CallExplicit(S_ptr, core::BuiltinFn::kBufferView,
+                                    Vector<TemplateParameter, 1>{S}, gv, offset);
         auto* access = b.Access(arr_ptr, view, 1_u);
         b.Call(ty.u32(), core::BuiltinFn::kArrayLength, access);
         b.Return(foo);
@@ -1994,8 +1995,8 @@
 
     auto* foo = b.ComputeFunction("foo", 1_u, 1_u, 1_u);
     b.Append(foo->Block(), [&] {
-        auto* offset = b.CallExplicit(arr_ptr, core::BuiltinFn::kBufferArrayView, Vector{arr}, gv,
-                                      0_u, 128_u, 256_u);
+        auto* offset = b.CallExplicit(arr_ptr, core::BuiltinFn::kBufferArrayView,
+                                      Vector<TemplateParameter, 1>{arr}, gv, 0_u, 128_u, 256_u);
         b.Call(ty.u32(), core::BuiltinFn::kArrayLength, offset);
         b.Return(foo);
     });
@@ -2091,7 +2092,8 @@
 
     auto* foo = b.ComputeFunction("foo", 1_u, 1_u, 1_u);
     b.Append(foo->Block(), [&] {
-        auto* offset = b.CallExplicit(arr_ptr, core::BuiltinFn::kBufferView, Vector{arr}, gv, 0_u);
+        auto* offset = b.CallExplicit(arr_ptr, core::BuiltinFn::kBufferView,
+                                      Vector<TemplateParameter, 1>{arr}, gv, 0_u);
         auto* construct = b.Construct(bundle, offset, 0_u, 0_u, 0_u, 0_u);
         b.Call(ty.void_(), bar, construct);
         b.Return(foo);
diff --git a/src/tint/lang/core/ir/transform/array_length_from_uniform_test.cc b/src/tint/lang/core/ir/transform/array_length_from_uniform_test.cc
index cba22c5..1abb9aa 100644
--- a/src/tint/lang/core/ir/transform/array_length_from_uniform_test.cc
+++ b/src/tint/lang/core/ir/transform/array_length_from_uniform_test.cc
@@ -1551,7 +1551,8 @@
     auto* foo = b.ComputeFunction("foo", 1_u, 1_u, 1_u);
     b.Append(foo->Block(), [&] {
         auto* offset = b.Let("offset", 16_u);
-        auto* view = b.CallExplicit(S_ptr, core::BuiltinFn::kBufferView, Vector{S}, gv, offset);
+        auto* view = b.CallExplicit(S_ptr, core::BuiltinFn::kBufferView,
+                                    Vector<TemplateParameter, 1>{S}, gv, offset);
         auto* access = b.Access(arr_ptr, view, 1_u);
         auto* length = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, access);
         b.Let("len", length);
@@ -1635,8 +1636,8 @@
 
     auto* foo = b.ComputeFunction("foo", 1_u, 1_u, 1_u);
     b.Append(foo->Block(), [&] {
-        auto* offset = b.CallExplicit(arr_ptr, core::BuiltinFn::kBufferArrayView, Vector{arr}, gv,
-                                      0_u, 128_u, 256_u);
+        auto* offset = b.CallExplicit(arr_ptr, core::BuiltinFn::kBufferArrayView,
+                                      Vector<TemplateParameter, 1>{arr}, gv, 0_u, 128_u, 256_u);
         auto* length = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, offset);
         b.Let("len", length);
         b.Return(foo);
@@ -1717,7 +1718,8 @@
 
     auto* foo = b.ComputeFunction("foo", 1_u, 1_u, 1_u);
     b.Append(foo->Block(), [&] {
-        auto* offset = b.CallExplicit(arr_ptr, core::BuiltinFn::kBufferView, Vector{arr}, gv, 0_u);
+        auto* offset = b.CallExplicit(arr_ptr, core::BuiltinFn::kBufferView,
+                                      Vector<TemplateParameter, 1>{arr}, gv, 0_u);
         auto* construct = b.Construct(bundle, offset, 0_u, 0_u, 0_u, 0_u);
         b.Call(ty.void_(), bar, construct);
         b.Return(foo);
diff --git a/src/tint/lang/core/ir/transform/decompose_access_test.cc b/src/tint/lang/core/ir/transform/decompose_access_test.cc
index 50c0436..3862bbc 100644
--- a/src/tint/lang/core/ir/transform/decompose_access_test.cc
+++ b/src/tint/lang/core/ir/transform/decompose_access_test.cc
@@ -5823,7 +5823,7 @@
     b.Append(func->Block(), [&] {
         auto* call = b.CallExplicit<core::ir::CoreBuiltinCall>(
             ty.ptr(storage, ty.u32(), core::Access::kReadWrite), core::BuiltinFn::kBufferView,
-            Vector{ty.u32()}, var, 16_u);
+            Vector<TemplateParameter, 1>{ty.u32()}, var, 16_u);
         b.Store(call, 33_u);
         b.Return(func);
     });
@@ -5871,7 +5871,7 @@
     b.Append(func->Block(), [&] {
         auto* call = b.CallExplicit<core::ir::CoreBuiltinCall>(
             ty.ptr(workgroup, ty.u32(), core::Access::kReadWrite), core::BuiltinFn::kBufferView,
-            Vector{ty.u32()}, var, 16_u);
+            Vector<TemplateParameter, 1>{ty.u32()}, var, 16_u);
         b.Store(call, 33_u);
         b.Return(func);
     });
@@ -5920,7 +5920,7 @@
     b.Append(func->Block(), [&] {
         auto* call = b.CallExplicit<core::ir::CoreBuiltinCall>(
             ty.ptr(uniform, ty.u32(), core::Access::kRead), core::BuiltinFn::kBufferView,
-            Vector{ty.u32()}, var, 36_u);
+            Vector<TemplateParameter, 1>{ty.u32()}, var, 36_u);
         b.Load(call);
         b.Return(func);
     });
@@ -6306,9 +6306,9 @@
 
     auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
-        auto* view =
-            b.CallExplicit(ty.ptr(storage, ty.runtime_array(sb), core::Access::kRead),
-                           core::BuiltinFn::kBufferView, Vector{ty.runtime_array(sb)}, var, 64_u);
+        auto* view = b.CallExplicit(ty.ptr(storage, ty.runtime_array(sb), core::Access::kRead),
+                                    core::BuiltinFn::kBufferView,
+                                    Vector<TemplateParameter, 1>{ty.runtime_array(sb)}, var, 64_u);
         auto* call = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, view);
         b.Let("a", call->Result());
         b.Return(func);
@@ -6390,9 +6390,10 @@
 
     auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
-        auto* view = b.CallExplicit(ty.ptr(storage, ty.runtime_array(sb), core::Access::kRead),
-                                    core::BuiltinFn::kBufferView, Vector{ty.runtime_array(sb)}, var,
-                                    b.Load(val));
+        auto* view =
+            b.CallExplicit(ty.ptr(storage, ty.runtime_array(sb), core::Access::kRead),
+                           core::BuiltinFn::kBufferView,
+                           Vector<TemplateParameter, 1>{ty.runtime_array(sb)}, var, b.Load(val));
         auto* call = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, view);
         b.Let("a", call->Result());
         b.Return(func);
@@ -6482,7 +6483,8 @@
     auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
     b.Append(func->Block(), [&] {
         auto* view = b.CallExplicit(ty.ptr(storage, outer, core::Access::kRead),
-                                    core::BuiltinFn::kBufferView, Vector{outer}, var, b.Load(val));
+                                    core::BuiltinFn::kBufferView,
+                                    Vector<TemplateParameter, 1>{outer}, var, b.Load(val));
         auto* call =
             b.Call(ty.u32(), core::BuiltinFn::kArrayLength,
                    b.Access(ty.ptr(storage, ty.runtime_array(sb), core::Access::kRead), view, 1_u));
@@ -6661,7 +6663,7 @@
         auto* arr_ty = ty.array<u32>();
         auto* call = b.CallExplicit<core::ir::CoreBuiltinCall>(
             ty.ptr(storage, arr_ty, core::Access::kReadWrite), core::BuiltinFn::kBufferArrayView,
-            Vector{arr_ty}, var, 16_u, 100_u);
+            Vector<TemplateParameter, 1>{arr_ty}, var, 16_u, 100_u);
         auto* access = b.Access(ty.ptr(storage, ty.u32(), core::Access::kReadWrite), call, 5_u);
         b.Load(access);
         b.Return(func);
@@ -6713,7 +6715,7 @@
         auto* arr_ty = ty.runtime_array(ty.vec4(ty.f32()));
         auto* call = b.CallExplicit<core::ir::CoreBuiltinCall>(
             ty.ptr(storage, arr_ty, core::Access::kReadWrite), core::BuiltinFn::kBufferArrayView,
-            Vector{arr_ty}, var, 16_u, 100_u);
+            Vector<TemplateParameter, 1>{arr_ty}, var, 16_u, 100_u);
         auto* access =
             b.Access(ty.ptr(storage, ty.vec4(ty.f32()), core::Access::kReadWrite), call, 5_u);
         b.Load(access);
@@ -6772,7 +6774,7 @@
         auto* arr_ty = ty.runtime_array(str_);
         auto* call = b.CallExplicit<core::ir::CoreBuiltinCall>(
             ty.ptr(storage, arr_ty, core::Access::kReadWrite), core::BuiltinFn::kBufferArrayView,
-            Vector{arr_ty}, var, 16_u, 100_u);
+            Vector<TemplateParameter, 1>{arr_ty}, var, 16_u, 100_u);
         auto* access = b.Access(ty.ptr(storage, str_, core::Access::kReadWrite), call, 5_u);
         b.Load(access);
         b.Return(func);
@@ -6848,7 +6850,7 @@
         auto* arr_ty = ty.array<u32>();
         auto* call = b.CallExplicit<core::ir::CoreBuiltinCall>(
             ty.ptr(storage, arr_ty, core::Access::kReadWrite), core::BuiltinFn::kBufferArrayView,
-            Vector{arr_ty}, var, 16_u, 100_u);
+            Vector<TemplateParameter, 1>{arr_ty}, var, 16_u, 100_u);
         auto* len = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, call);
         b.Let("a", len->Result());
         b.Return(func);
@@ -6900,7 +6902,7 @@
         auto* arr_ty = ty.runtime_array(ty.vec4(ty.f32()));
         auto* call = b.CallExplicit<core::ir::CoreBuiltinCall>(
             ty.ptr(storage, arr_ty, core::Access::kReadWrite), core::BuiltinFn::kBufferArrayView,
-            Vector{arr_ty}, var, 16_u, 100_u);
+            Vector<TemplateParameter, 1>{arr_ty}, var, 16_u, 100_u);
         auto* len = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, call);
         b.Let("a", len->Result());
         b.Return(func);
@@ -6957,7 +6959,7 @@
         auto* arr_ty = ty.runtime_array(str_);
         auto* call = b.CallExplicit<core::ir::CoreBuiltinCall>(
             ty.ptr(storage, arr_ty, core::Access::kReadWrite), core::BuiltinFn::kBufferArrayView,
-            Vector{arr_ty}, var, 16_u, 100_u);
+            Vector<TemplateParameter, 1>{arr_ty}, var, 16_u, 100_u);
         auto* len = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, call);
         b.Let("a", len->Result());
         b.Return(func);
@@ -7027,7 +7029,7 @@
     b.Append(func->Block(), [&] {
         auto* call = b.CallExplicit<core::ir::CoreBuiltinCall>(
             ty.ptr(storage, str_, core::Access::kReadWrite), core::BuiltinFn::kBufferArrayView,
-            Vector{str_}, var, offset, size);
+            Vector<TemplateParameter, 1>{str_}, var, offset, size);
         auto* access = b.Access(ty.ptr(storage, ty.runtime_array(ty.f32())), call, 1_u);
         auto* len = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, access);
         b.Let("a", len->Result());
@@ -7102,7 +7104,7 @@
         auto* arr_ty = ty.runtime_array(ty.f32());
         auto* call = b.CallExplicit<core::ir::CoreBuiltinCall>(
             ty.ptr(storage, str_, core::Access::kReadWrite), core::BuiltinFn::kBufferView,
-            Vector{str_}, var, offset, length);
+            Vector<TemplateParameter, 1>{str_}, var, offset, length);
         auto* access = b.Access(ty.ptr(storage, arr_ty), call, 1_u);
         auto* len = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, access);
         b.Let("a", len->Result());
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 0b0b9e2..3b16df7 100644
--- a/src/tint/lang/core/ir/transform/direct_variable_access.cc
+++ b/src/tint/lang/core/ir/transform/direct_variable_access.cc
@@ -694,8 +694,9 @@
                                                   (v->fn == BuiltinFn::kBufferView ? 1_u : 2_u))
                                              ->Result();
                             }
-                            auto* call = b.CallExplicit(v->type, v->fn,
-                                                        Vector{v->type->UnwrapPtr()}, replacement);
+                            auto* call = b.CallExplicit(
+                                v->type, v->fn, Vector<TemplateParameter, 1>{v->type->UnwrapPtr()},
+                                replacement);
                             call->AppendArg(offset);
                             if (size) {
                                 call->AppendArg(size);
diff --git a/src/tint/lang/core/ir/transform/direct_variable_access_test.cc b/src/tint/lang/core/ir/transform/direct_variable_access_test.cc
index 2d61108..db48364 100644
--- a/src/tint/lang/core/ir/transform/direct_variable_access_test.cc
+++ b/src/tint/lang/core/ir/transform/direct_variable_access_test.cc
@@ -8328,8 +8328,8 @@
     auto* offset = b.FunctionParam("offset", ty.u32());
     foo->SetParams({p, offset});
     b.Append(foo->Block(), [&] {
-        b.CallExplicit(ty.ptr(storage, ty.u32()), BuiltinFn::kBufferView, Vector{ty.u32()}, p,
-                       offset);
+        b.CallExplicit(ty.ptr(storage, ty.u32()), BuiltinFn::kBufferView,
+                       Vector<TemplateParameter, 1>{ty.u32()}, p, offset);
         b.Return(foo);
     });
 
@@ -8396,7 +8396,7 @@
     foo->SetParams({p, offset, size});
     b.Append(foo->Block(), [&] {
         b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())), BuiltinFn::kBufferArrayView,
-                       Vector{ty.runtime_array(ty.u32())}, p, offset, size);
+                       Vector<TemplateParameter, 1>{ty.runtime_array(ty.u32())}, p, offset, size);
         b.Return(foo);
     });
 
@@ -8470,7 +8470,7 @@
     foo->SetParams({offset});
     b.Append(foo->Block(), [&] {
         auto* call = b.CallExplicit(ty.ptr(workgroup, arr_ty), BuiltinFn::kBufferView,
-                                    Vector{arr_ty}, v, offset);
+                                    Vector<TemplateParameter, 1>{arr_ty}, v, offset);
         b.Call(ty.void_(), bar, call);
         b.Return(foo);
     });
@@ -8546,7 +8546,7 @@
     foo->SetParams({offset, length});
     b.Append(foo->Block(), [&] {
         auto* call = b.CallExplicit(ty.ptr(workgroup, arr_ty), BuiltinFn::kBufferView,
-                                    Vector{arr_ty}, v, offset, length);
+                                    Vector<TemplateParameter, 1>{arr_ty}, v, offset, length);
         b.Call(ty.void_(), bar, call);
         b.Return(foo);
     });
@@ -8623,7 +8623,7 @@
     foo->SetParams({offset, size});
     b.Append(foo->Block(), [&] {
         auto* call = b.CallExplicit(ty.ptr(workgroup, arr_ty), BuiltinFn::kBufferArrayView,
-                                    Vector{arr_ty}, v, offset, size);
+                                    Vector<TemplateParameter, 1>{arr_ty}, v, offset, size);
         b.Call(ty.void_(), bar, call);
         b.Return(foo);
     });
@@ -8701,7 +8701,7 @@
     foo->SetParams({offset, size, length});
     b.Append(foo->Block(), [&] {
         auto* call = b.CallExplicit(ty.ptr(workgroup, arr_ty), BuiltinFn::kBufferArrayView,
-                                    Vector{arr_ty}, v, offset, size, length);
+                                    Vector<TemplateParameter, 1>{arr_ty}, v, offset, size, length);
         b.Call(ty.void_(), bar, call);
         b.Return(foo);
     });
@@ -8788,7 +8788,7 @@
     foo->SetParams({offset});
     b.Append(foo->Block(), [&] {
         auto* call = b.CallExplicit(ty.ptr(workgroup, arr_ty), BuiltinFn::kBufferView,
-                                    Vector{arr_ty}, v, offset);
+                                    Vector<TemplateParameter, 1>{arr_ty}, v, offset);
         b.Call(ty.void_(), foobar, call);
         b.Return(foo);
     });
@@ -8892,7 +8892,7 @@
     foo->SetParams({offset, size});
     b.Append(foo->Block(), [&] {
         auto* call = b.CallExplicit(ty.ptr(workgroup, arr_ty), BuiltinFn::kBufferArrayView,
-                                    Vector{arr_ty}, v, offset, size);
+                                    Vector<TemplateParameter, 1>{arr_ty}, v, offset, size);
         b.Call(ty.void_(), foobar, call);
         b.Return(foo);
     });
@@ -8982,12 +8982,12 @@
 
     auto* main = b.Function("main", ty.void_());
     b.Append(main->Block(), [&] {
-        auto* v1 =
-            b.CallExplicit(ty.ptr(storage, arr_ty), BuiltinFn::kBufferView, Vector{arr_ty}, v, 0_u);
+        auto* v1 = b.CallExplicit(ty.ptr(storage, arr_ty), BuiltinFn::kBufferView,
+                                  Vector<TemplateParameter, 1>{arr_ty}, v, 0_u);
         b.Call(ty.void_(), bar, v1);
 
         auto* v2 = b.CallExplicit(ty.ptr(storage, arr_ty), BuiltinFn::kBufferArrayView,
-                                  Vector{arr_ty}, v, 0_u, 10_u);
+                                  Vector<TemplateParameter, 1>{arr_ty}, v, 0_u, 10_u);
         b.Call(ty.void_(), bar, v2);
 
         b.Return(main);
@@ -9066,12 +9066,12 @@
 
     auto* main = b.Function("main", ty.void_());
     b.Append(main->Block(), [&] {
-        auto* v1 =
-            b.CallExplicit(ty.ptr(storage, arr_ty), BuiltinFn::kBufferView, Vector{arr_ty}, v, 0_u);
+        auto* v1 = b.CallExplicit(ty.ptr(storage, arr_ty), BuiltinFn::kBufferView,
+                                  Vector<TemplateParameter, 1>{arr_ty}, v, 0_u);
         b.Call(ty.void_(), bar, v1);
 
-        auto* v2 = b.CallExplicit(ty.ptr(storage, arr_ty), BuiltinFn::kBufferView, Vector{arr_ty},
-                                  v, 0_u, 100_u);
+        auto* v2 = b.CallExplicit(ty.ptr(storage, arr_ty), BuiltinFn::kBufferView,
+                                  Vector<TemplateParameter, 1>{arr_ty}, v, 0_u, 100_u);
         b.Call(ty.void_(), bar, v2);
 
         b.Return(main);
@@ -9161,8 +9161,8 @@
 
     auto* main = b.Function("main", ty.void_());
     b.Append(main->Block(), [&] {
-        auto* v1 =
-            b.CallExplicit(ty.ptr(storage, arr_ty), BuiltinFn::kBufferView, Vector{arr_ty}, v, 0_u);
+        auto* v1 = b.CallExplicit(ty.ptr(storage, arr_ty), BuiltinFn::kBufferView,
+                                  Vector<TemplateParameter, 1>{arr_ty}, v, 0_u);
         b.Call(ty.void_(), foo, v1);
         b.Return(main);
     });
@@ -9244,8 +9244,8 @@
 
     auto* main = b.Function("main", ty.void_());
     b.Append(main->Block(), [&] {
-        auto* v1 =
-            b.CallExplicit(ty.ptr(storage, arr_ty), BuiltinFn::kBufferView, Vector{arr_ty}, v, 0_u);
+        auto* v1 = b.CallExplicit(ty.ptr(storage, arr_ty), BuiltinFn::kBufferView,
+                                  Vector<TemplateParameter, 1>{arr_ty}, v, 0_u);
         auto* l = b.Let("l", v1);
         b.Call(ty.void_(), foo, l);
         b.Return(main);
@@ -9316,8 +9316,8 @@
     main->SetParams({offset});
     b.Append(main->Block(), [&] {
         auto* dyn_offset = b.Add(offset, 4_u);
-        auto* v1 = b.CallExplicit(ty.ptr(storage, arr_ty), BuiltinFn::kBufferView, Vector{arr_ty},
-                                  v, dyn_offset);
+        auto* v1 = b.CallExplicit(ty.ptr(storage, arr_ty), BuiltinFn::kBufferView,
+                                  Vector<TemplateParameter, 1>{arr_ty}, v, dyn_offset);
         b.Call(ty.void_(), foo, v1);
         b.Return(main);
     });
@@ -9385,8 +9385,8 @@
 
     auto* main = b.Function("main", ty.void_());
     b.Append(main->Block(), [&] {
-        auto* v1 =
-            b.CallExplicit(ty.ptr(uniform, arr_ty), BuiltinFn::kBufferView, Vector{arr_ty}, v, 0_u);
+        auto* v1 = b.CallExplicit(ty.ptr(uniform, arr_ty), BuiltinFn::kBufferView,
+                                  Vector<TemplateParameter, 1>{arr_ty}, v, 0_u);
         b.Call(ty.void_(), foo, v1);
         b.Return(main);
     });
@@ -9459,8 +9459,8 @@
 
     auto* main = b.Function("main", ty.void_());
     b.Append(main->Block(), [&] {
-        auto* v1 =
-            b.CallExplicit(ty.ptr(storage, str_), BuiltinFn::kBufferView, Vector{str_}, v, 0_u);
+        auto* v1 = b.CallExplicit(ty.ptr(storage, str_), BuiltinFn::kBufferView,
+                                  Vector<TemplateParameter, 1>{str_}, v, 0_u);
         b.Call(ty.void_(), foo, v1);
         b.Return(main);
     });
@@ -9536,7 +9536,8 @@
     auto* p = b.FunctionParam("p", ty.ptr(storage, ty.unsized_buffer()));
     bar->SetParams({p});
     b.Append(bar->Block(), [&] {
-        b.CallExplicit(ty.ptr(storage, ty.u32()), BuiltinFn::kBufferView, Vector{ty.u32()}, p, 0_u);
+        b.CallExplicit(ty.ptr(storage, ty.u32()), BuiltinFn::kBufferView,
+                       Vector<TemplateParameter, 1>{ty.u32()}, p, 0_u);
         b.Return(bar);
     });
 
diff --git a/src/tint/lang/core/ir/transform/propagate_buffer_sizes_test.cc b/src/tint/lang/core/ir/transform/propagate_buffer_sizes_test.cc
index 3cffb05..f18ac32 100644
--- a/src/tint/lang/core/ir/transform/propagate_buffer_sizes_test.cc
+++ b/src/tint/lang/core/ir/transform/propagate_buffer_sizes_test.cc
@@ -79,7 +79,7 @@
     b.Append(func->Block(), [&] {
         auto* call =
             b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())), BuiltinFn::kBufferArrayView,
-                           Vector{ty.runtime_array(ty.u32())}, gv, 0_u, 32_u);
+                           Vector<TemplateParameter, 1>{ty.runtime_array(ty.u32())}, gv, 0_u, 32_u);
         b.Let("a", call);
         b.Return(func);
     });
@@ -186,7 +186,7 @@
     foo->SetParams({foo_p});
     b.Append(foo->Block(), [&] {
         auto* call = b.CallExplicit(ty.ptr(storage, ty.u32()), BuiltinFn::kBufferView,
-                                    Vector{ty.u32()}, foo_p, 0_u);
+                                    Vector<TemplateParameter, 1>{ty.u32()}, foo_p, 0_u);
         b.Let("a", call);
         b.Return(foo);
     });
@@ -254,7 +254,7 @@
     foo->SetParams({foo_p});
     b.Append(foo->Block(), [&] {
         auto* call = b.CallExplicit(ty.ptr(storage, ty.u32()), BuiltinFn::kBufferView,
-                                    Vector{ty.u32()}, foo_p, 0_u);
+                                    Vector<TemplateParameter, 1>{ty.u32()}, foo_p, 0_u);
         b.Let("a", call);
         b.Return(foo);
     });
@@ -423,7 +423,7 @@
     foo1->SetParams({foo1_p});
     b.Append(foo1->Block(), [&] {
         auto* call = b.CallExplicit(ty.ptr(storage, ty.u32()), BuiltinFn::kBufferView,
-                                    Vector{ty.u32()}, foo1_p, 0_u);
+                                    Vector<TemplateParameter, 1>{ty.u32()}, foo1_p, 0_u);
         b.Let("a", call);
         b.Return(foo1);
     });
@@ -559,7 +559,7 @@
     foo->SetParams({foo_p});
     b.Append(foo->Block(), [&] {
         auto* call = b.CallExplicit(ty.ptr(storage, ty.u32()), BuiltinFn::kBufferView,
-                                    Vector{ty.u32()}, foo_p, 0_u);
+                                    Vector<TemplateParameter, 1>{ty.u32()}, foo_p, 0_u);
         b.Let("a", call);
         b.Return(foo);
     });
@@ -655,7 +655,7 @@
         auto* l1 = b.Let("l1", foo_p);
         auto* l2 = b.Let("l2", l1);
         auto* call = b.CallExplicit(ty.ptr(storage, ty.u32()), BuiltinFn::kBufferView,
-                                    Vector{ty.u32()}, l2, 0_u);
+                                    Vector<TemplateParameter, 1>{ty.u32()}, l2, 0_u);
         b.Let("a", call);
         b.Return(foo);
     });
@@ -755,7 +755,8 @@
 
     auto* foo = b.Function("foo", ty.void_());
     b.Append(foo->Block(), [&] {
-        b.CallExplicit(ty.ptr(storage, ty.u32()), BuiltinFn::kBufferView, Vector{ty.u32()}, v, 5_u);
+        b.CallExplicit(ty.ptr(storage, ty.u32()), BuiltinFn::kBufferView,
+                       Vector<TemplateParameter, 1>{ty.u32()}, v, 5_u);
         b.Return(foo);
     });
 
@@ -800,8 +801,8 @@
     auto* offset = b.FunctionParam("offset", ty.i32());
     foo->SetParams({offset});
     b.Append(foo->Block(), [&] {
-        b.CallExplicit(ty.ptr(storage, ty.vec4u()), BuiltinFn::kBufferView, Vector{ty.vec4u()}, v,
-                       offset);
+        b.CallExplicit(ty.ptr(storage, ty.vec4u()), BuiltinFn::kBufferView,
+                       Vector<TemplateParameter, 1>{ty.vec4u()}, v, offset);
         b.Return(foo);
     });
 
@@ -847,7 +848,7 @@
     auto* foo = b.Function("foo", ty.void_());
     b.Append(foo->Block(), [&] {
         b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())), BuiltinFn::kBufferArrayView,
-                       Vector{ty.runtime_array(ty.u32())}, v, 5_u, 16_u);
+                       Vector<TemplateParameter, 1>{ty.runtime_array(ty.u32())}, v, 5_u, 16_u);
         b.Return(foo);
     });
 
@@ -893,7 +894,7 @@
     foo->SetParams({offset});
     b.Append(foo->Block(), [&] {
         b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.vec4u())), BuiltinFn::kBufferArrayView,
-                       Vector{ty.runtime_array(ty.vec4u())}, v, offset, 16_u);
+                       Vector<TemplateParameter, 1>{ty.runtime_array(ty.vec4u())}, v, offset, 16_u);
         b.Return(foo);
     });
 
@@ -943,7 +944,8 @@
 
     auto* foo = b.Function("foo", ty.void_());
     b.Append(foo->Block(), [&] {
-        b.CallExplicit(ty.ptr(storage, S), BuiltinFn::kBufferArrayView, Vector{S}, v, 0_u, 11_u);
+        b.CallExplicit(ty.ptr(storage, S), BuiltinFn::kBufferArrayView,
+                       Vector<TemplateParameter, 1>{S}, v, 0_u, 11_u);
         b.Return(foo);
     });
 
@@ -1003,7 +1005,8 @@
     auto* size = b.FunctionParam("size", ty.i32());
     foo->SetParams({size});
     b.Append(foo->Block(), [&] {
-        b.CallExplicit(ty.ptr(storage, S), BuiltinFn::kBufferArrayView, Vector{S}, v, 0_u, size);
+        b.CallExplicit(ty.ptr(storage, S), BuiltinFn::kBufferArrayView,
+                       Vector<TemplateParameter, 1>{S}, v, 0_u, size);
         b.Return(foo);
     });
 
diff --git a/src/tint/lang/core/ir/transform/resource_table.cc b/src/tint/lang/core/ir/transform/resource_table.cc
index c3d4fbe..6665d91 100644
--- a/src/tint/lang/core/ir/transform/resource_table.cc
+++ b/src/tint/lang/core/ir/transform/resource_table.cc
@@ -167,7 +167,10 @@
 
     std::pair<const type::Type*, ir::Value*> GetResourceTableCallInfo(
         core::ir::CoreBuiltinCall* call) {
-        const type::Type* binding_ty = call->ExplicitTemplateParams()[0];
+        TINT_IR_ASSERT(
+            ir, std::holds_alternative<const core::type::Type*>(call->ExplicitTemplateParams()[0]));
+        const type::Type* binding_ty =
+            std::get<const core::type::Type*>(call->ExplicitTemplateParams()[0]);
         ir::Value* idx = b.InsertConvertIfNeeded(ty.u32(), call->Args()[0]);
         return {binding_ty, idx};
     }
diff --git a/src/tint/lang/core/ir/transform/resource_table_helper.cc b/src/tint/lang/core/ir/transform/resource_table_helper.cc
index c87390e..9166705 100644
--- a/src/tint/lang/core/ir/transform/resource_table_helper.cc
+++ b/src/tint/lang/core/ir/transform/resource_table_helper.cc
@@ -54,13 +54,16 @@
         }
         auto exp = call->ExplicitTemplateParams();
         TINT_IR_ASSERT(mod, exp.Length() == 1);
+        TINT_IR_ASSERT(mod, std::holds_alternative<const core::type::Type*>(exp[0]));
 
-        std::vector<ResourceType> converts = ConvertsFrom(exp[0]);
+        std::vector<ResourceType> converts =
+            ConvertsFrom(std::get<const core::type::Type*>(exp[0]));
         // The converts from only contains values for the filterable types, for
         // the others it returns empty so we need to add the ResourceType for
         // that specific type.
         if (converts.empty()) {
-            default_binding_type_order.push_back(TypeToResourceType(exp[0]));
+            default_binding_type_order.push_back(
+                TypeToResourceType(std::get<const core::type::Type*>(exp[0])));
         } else {
             for (ResourceType from : converts) {
                 default_binding_type_order.push_back(from);
diff --git a/src/tint/lang/core/ir/transform/resource_table_test.cc b/src/tint/lang/core/ir/transform/resource_table_test.cc
index dc571bc..4314726 100644
--- a/src/tint/lang/core/ir/transform/resource_table_test.cc
+++ b/src/tint/lang/core/ir/transform/resource_table_test.cc
@@ -116,8 +116,8 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        b.Let("t",
-              b.CallExplicit(ty.bool_(), core::BuiltinFn::kHasResource, Vector{texture_ty}, 1_u));
+        b.Let("t", b.CallExplicit(ty.bool_(), core::BuiltinFn::kHasResource,
+                                  Vector<TemplateParameter, 1>{texture_ty}, 1_u));
         b.Return(func);
     });
 
@@ -144,8 +144,8 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        b.Let("t",
-              b.CallExplicit(ty.bool_(), core::BuiltinFn::kHasResource, Vector{texture_ty}, 1_u));
+        b.Let("t", b.CallExplicit(ty.bool_(), core::BuiltinFn::kHasResource,
+                                  Vector<TemplateParameter, 1>{texture_ty}, 1_u));
         b.Return(func);
     });
 
@@ -218,8 +218,8 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        b.Let("t",
-              b.CallExplicit(ty.bool_(), core::BuiltinFn::kHasResource, Vector{texture_ty}, 2_u));
+        b.Let("t", b.CallExplicit(ty.bool_(), core::BuiltinFn::kHasResource,
+                                  Vector<TemplateParameter, 1>{texture_ty}, 2_u));
         b.Return(func);
     });
 
@@ -295,8 +295,8 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        b.Let("t",
-              b.CallExplicit(ty.bool_(), core::BuiltinFn::kHasResource, Vector{texture_ty}, 2_u));
+        b.Let("t", b.CallExplicit(ty.bool_(), core::BuiltinFn::kHasResource,
+                                  Vector<TemplateParameter, 1>{texture_ty}, 2_u));
         b.Return(func);
     });
 
@@ -372,8 +372,8 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        auto* tex =
-            b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource, Vector{texture_ty}, 1_u);
+        auto* tex = b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource,
+                                   Vector<TemplateParameter, 1>{texture_ty}, 1_u);
         b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, tex);
         b.Return(func);
     });
@@ -461,10 +461,10 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        auto* tex =
-            b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource, Vector{texture_ty}, 1_u);
-        auto* sam =
-            b.CallExplicit(sampler_ty, core::BuiltinFn::kGetResource, Vector{sampler_ty}, 2_u);
+        auto* tex = b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource,
+                                   Vector<TemplateParameter, 1>{texture_ty}, 1_u);
+        auto* sam = b.CallExplicit(sampler_ty, core::BuiltinFn::kGetResource,
+                                   Vector<TemplateParameter, 1>{sampler_ty}, 2_u);
 
         b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSample, tex, sam,
                b.Splat(ty.vec2<f32>(), 0_f));
@@ -639,8 +639,8 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        auto* tex =
-            b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource, Vector{texture_ty}, 1_u);
+        auto* tex = b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource,
+                                   Vector<TemplateParameter, 1>{texture_ty}, 1_u);
 
         core::ir::Load* sam = b.Load(sam_var);
         b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSample, tex, sam,
@@ -776,8 +776,8 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        auto* tex =
-            b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource, Vector{texture_ty}, 1_u);
+        auto* tex = b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource,
+                                   Vector<TemplateParameter, 1>{texture_ty}, 1_u);
 
         core::ir::Load* sam = b.Load(sam_var);
         b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSample, tex, sam,
@@ -899,8 +899,8 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        auto* sam =
-            b.CallExplicit(sampler_ty, core::BuiltinFn::kGetResource, Vector{sampler_ty}, 1_u);
+        auto* sam = b.CallExplicit(sampler_ty, core::BuiltinFn::kGetResource,
+                                   Vector<TemplateParameter, 1>{sampler_ty}, 1_u);
 
         core::ir::Load* tex = b.Load(tex_var);
         b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSample, tex, sam,
@@ -1042,8 +1042,8 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        auto* tex =
-            b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource, Vector{texture_ty}, 1_u);
+        auto* tex = b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource,
+                                   Vector<TemplateParameter, 1>{texture_ty}, 1_u);
         b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, tex);
         b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, tex);
         b.Return(func);
@@ -1167,8 +1167,8 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        auto* tex =
-            b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource, Vector{texture_ty}, 1_u);
+        auto* tex = b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource,
+                                   Vector<TemplateParameter, 1>{texture_ty}, 1_u);
         auto* if_ = b.If(true);
         b.Append(if_->True(), [&] {
             b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, tex);
@@ -1309,7 +1309,8 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource, Vector{texture_ty}, 2_u);
+        b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource,
+                       Vector<TemplateParameter, 1>{texture_ty}, 2_u);
         b.Return(func);
     });
 
@@ -1366,8 +1367,8 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        b.Let("t",
-              b.CallExplicit(ty.bool_(), core::BuiltinFn::kHasResource, Vector{sampler_ty}, 1_u));
+        b.Let("t", b.CallExplicit(ty.bool_(), core::BuiltinFn::kHasResource,
+                                  Vector<TemplateParameter, 1>{sampler_ty}, 1_u));
         b.Return(func);
     });
 
@@ -1448,8 +1449,8 @@
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
         core::ir::Load* tex = b.Load(tex_var);
-        core::ir::Instruction* sam =
-            b.CallExplicit(sampler_ty, core::BuiltinFn::kGetResource, Vector{sampler_ty}, 1_u);
+        core::ir::Instruction* sam = b.CallExplicit(sampler_ty, core::BuiltinFn::kGetResource,
+                                                    Vector<TemplateParameter, 1>{sampler_ty}, 1_u);
 
         b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSample, tex, sam,
                b.Splat(ty.vec2<f32>(), 0_f));
@@ -1593,8 +1594,8 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        auto* tex =
-            b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource, Vector{texture_ty}, 1_u);
+        auto* tex = b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource,
+                                   Vector<TemplateParameter, 1>{texture_ty}, 1_u);
 
         core::ir::Load* sam = b.Load(sam_var);
         b.Call(ty.f32(), core::BuiltinFn::kTextureSampleCompare, tex, sam,
@@ -1696,10 +1697,10 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        auto* tex =
-            b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource, Vector{texture_ty}, 1_u);
-        auto* sam =
-            b.CallExplicit(sampler_ty, core::BuiltinFn::kGetResource, Vector{sampler_ty}, 2_u);
+        auto* tex = b.CallExplicit(texture_ty, core::BuiltinFn::kGetResource,
+                                   Vector<TemplateParameter, 1>{texture_ty}, 1_u);
+        auto* sam = b.CallExplicit(sampler_ty, core::BuiltinFn::kGetResource,
+                                   Vector<TemplateParameter, 1>{sampler_ty}, 2_u);
 
         b.Call(ty.f32(), core::BuiltinFn::kTextureSampleCompare, tex, sam,
                b.Splat(ty.vec2<f32>(), 0_f), 0_f);
diff --git a/src/tint/lang/core/ir/transform/robustness_test.cc b/src/tint/lang/core/ir/transform/robustness_test.cc
index 82f05b2..fcd0ed9 100644
--- a/src/tint/lang/core/ir/transform/robustness_test.cc
+++ b/src/tint/lang/core/ir/transform/robustness_test.cc
@@ -3301,8 +3301,8 @@
     auto* func = b.Function("foo", mat);
     b.Append(func->Block(), [&] {
         // Constant stride of 1 should be clamped to 4 even when predication is disabled.
-        auto* load =
-            b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, arr, 0_u, true, 1_u);
+        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<TemplateParameter, 1>{mat}, arr, 0_u, true, 1_u);
         b.Return(func, load);
     });
 
@@ -3378,8 +3378,8 @@
     auto* func = b.Function("foo", mat);
     b.Append(func->Block(), [&] {
         // Constant stride of 1 should be clamped to 4 even when predication is disabled.
-        auto* load =
-            b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, arr, 0_u, true, 1_u);
+        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<TemplateParameter, 1>{mat}, arr, 0_u, true, 1_u);
         b.Return(func, load);
     });
 
@@ -3456,8 +3456,8 @@
     auto* func = b.Function("foo", mat);
     b.Append(func->Block(), [&] {
         // Constant stride of 1 should be clamped to 4 even when predication is disabled.
-        auto* load =
-            b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, arr, 0_u, true, 1_u);
+        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<TemplateParameter, 1>{mat}, arr, 0_u, true, 1_u);
         b.Return(func, load);
     });
 
@@ -3534,8 +3534,8 @@
     func->AppendParam(stride);
     b.Append(func->Block(), [&] {
         // Dynamic stride should be clamped with `max` even when predication is disabled.
-        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, arr, 0_u,
-                                    true, stride);
+        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<TemplateParameter, 1>{mat}, arr, 0_u, true, stride);
         b.Return(func, load);
     });
 
@@ -3615,8 +3615,8 @@
     func->AppendParam(stride);
     b.Append(func->Block(), [&] {
         // Dynamic stride should be clamped with `max` even when predication is disabled.
-        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, arr, 0_u,
-                                    true, stride);
+        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<TemplateParameter, 1>{mat}, arr, 0_u, true, stride);
         b.Return(func, load);
     });
 
@@ -3697,8 +3697,8 @@
     func->AppendParam(stride);
     b.Append(func->Block(), [&] {
         // Dynamic stride should be clamped with `max` even when predication is disabled.
-        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, arr, 0_u,
-                                    true, stride);
+        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<TemplateParameter, 1>{mat}, arr, 0_u, true, stride);
         b.Return(func, load);
     });
 
@@ -3777,8 +3777,8 @@
     func->AppendParam(stride);
     b.Append(func->Block(), [&] {
         // Dynamic stride should be clamped with `max` even when predication is disabled.
-        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, arr, 0_u,
-                                    false, stride);
+        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<TemplateParameter, 1>{mat}, arr, 0_u, false, stride);
         b.Return(func, load);
     });
 
@@ -3858,8 +3858,8 @@
     func->AppendParam(stride);
     b.Append(func->Block(), [&] {
         // Dynamic stride should be clamped with `max` even when predication is disabled.
-        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, arr, 0_u,
-                                    false, stride);
+        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<TemplateParameter, 1>{mat}, arr, 0_u, false, stride);
         b.Return(func, load);
     });
 
@@ -3940,8 +3940,8 @@
     func->AppendParam(stride);
     b.Append(func->Block(), [&] {
         // Dynamic stride should be clamped with `max` even when predication is disabled.
-        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, arr, 0_u,
-                                    false, stride);
+        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<TemplateParameter, 1>{mat}, arr, 0_u, false, stride);
         b.Return(func, load);
     });
 
@@ -4019,8 +4019,8 @@
     func->AppendParam(stride);
     b.Append(func->Block(), [&] {
         // Dynamic stride should be clamped with `max` even when predication is disabled.
-        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, arr, 0_u,
-                                    true, stride);
+        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<TemplateParameter, 1>{mat}, arr, 0_u, true, stride);
         b.Return(func, load);
     });
 
@@ -4098,8 +4098,8 @@
     func->AppendParam(stride);
     b.Append(func->Block(), [&] {
         // Dynamic stride should be clamped with `max` even when predication is disabled.
-        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, arr, 0_u,
-                                    true, stride);
+        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<TemplateParameter, 1>{mat}, arr, 0_u, true, stride);
         b.Return(func, load);
     });
 
@@ -4177,8 +4177,8 @@
     func->AppendParam(stride);
     b.Append(func->Block(), [&] {
         // Dynamic stride should be clamped with `max` even when predication is disabled.
-        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, arr, 0_u,
-                                    true, stride);
+        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<TemplateParameter, 1>{mat}, arr, 0_u, true, stride);
         b.Return(func, load);
     });
 
@@ -4255,8 +4255,8 @@
     b.Append(func->Block(), [&] {
         // The final row will start at 1016. Another full stride will take it past the 1024 limit,
         // but the transform should understand that only 8 elements are accessed on that row.
-        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, arr, 920_u,
-                                    false, 32_u);
+        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<TemplateParameter, 1>{mat}, arr, 920_u, false, 32_u);
         b.Return(func, load);
     });
 
@@ -4295,8 +4295,8 @@
     b.Append(func->Block(), [&] {
         // The final row will start at 1016. Another full stride will take it past the 1024 limit,
         // but the transform should understand that only 8 elements are accessed on that row.
-        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, arr, 920_u,
-                                    false, 32_u);
+        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<TemplateParameter, 1>{mat}, arr, 920_u, false, 32_u);
         b.Return(func, load);
     });
 
@@ -4335,8 +4335,8 @@
     b.Append(func->Block(), [&] {
         // The final row will start at 1016. Another full stride will take it past the 1024 limit,
         // but the transform should understand that only 8 elements are accessed on that row.
-        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, arr, 920_u,
-                                    false, 32_u);
+        auto* load = b.CallExplicit(mat, BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<TemplateParameter, 1>{mat}, arr, 920_u, false, 32_u);
         b.Return(func, load);
     });
 
@@ -5424,13 +5424,13 @@
 
     auto* foo = b.Function("foo", ty.void_());
     b.Append(foo->Block(), [&] {
-        auto* v1 = b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())),
-                                  core::BuiltinFn::kBufferView, Vector{ty.runtime_array(ty.u32())},
-                                  b1, 0_u);
+        auto* v1 = b.CallExplicit(
+            ty.ptr(storage, ty.runtime_array(ty.u32())), core::BuiltinFn::kBufferView,
+            Vector<TemplateParameter, 1>{ty.runtime_array(ty.u32())}, b1, 0_u);
         b.Access(ty.ptr(storage, ty.u32()), v1, 128_u);
-        auto* v2 = b.CallExplicit(ty.ptr(uniform, ty.runtime_array(ty.u32())),
-                                  core::BuiltinFn::kBufferArrayView,
-                                  Vector{ty.runtime_array(ty.u32())}, b2, 0_u, 128_u);
+        auto* v2 = b.CallExplicit(
+            ty.ptr(uniform, ty.runtime_array(ty.u32())), core::BuiltinFn::kBufferArrayView,
+            Vector<TemplateParameter, 1>{ty.runtime_array(ty.u32())}, b2, 0_u, 128_u);
         b.Access(ty.ptr(uniform, ty.u32()), v2, 256_u);
         b.Return(foo);
     });
@@ -5497,8 +5497,8 @@
     auto* p = b.FunctionParam("p", ty.ptr(storage, ty.unsized_buffer()));
     func->SetParams({p});
     b.Append(func->Block(), [&] {
-        b.CallExplicit(ty.ptr(storage, ty.u32()), BuiltinFn::kBufferView, Vector{ty.u32()}, p, 16_u,
-                       32_u);
+        b.CallExplicit(ty.ptr(storage, ty.u32()), BuiltinFn::kBufferView,
+                       Vector<TemplateParameter, 1>{ty.u32()}, p, 16_u, 32_u);
         b.Return(func);
     });
 
@@ -5525,8 +5525,8 @@
     auto* p = b.FunctionParam("p", ty.ptr(storage, ty.unsized_buffer()));
     func->SetParams({p});
     b.Append(func->Block(), [&] {
-        b.CallExplicit(ty.ptr(storage, ty.u32()), BuiltinFn::kBufferView, Vector{ty.u32()}, p, 16_u,
-                       12_u);
+        b.CallExplicit(ty.ptr(storage, ty.u32()), BuiltinFn::kBufferView,
+                       Vector<TemplateParameter, 1>{ty.u32()}, p, 16_u, 12_u);
         b.Return(func);
     });
 
@@ -5567,7 +5567,8 @@
     auto* p = b.FunctionParam("p", ty.ptr(uniform, ty.unsized_buffer()));
     func->SetParams({p});
     b.Append(func->Block(), [&] {
-        b.CallExplicit(ty.ptr(uniform, s), BuiltinFn::kBufferView, Vector{s}, p, 16_u, 64_u);
+        b.CallExplicit(ty.ptr(uniform, s), BuiltinFn::kBufferView, Vector<TemplateParameter, 1>{s},
+                       p, 16_u, 64_u);
         b.Return(func);
     });
 
@@ -5604,7 +5605,8 @@
     auto* p = b.FunctionParam("p", ty.ptr(uniform, ty.unsized_buffer()));
     func->SetParams({p});
     b.Append(func->Block(), [&] {
-        b.CallExplicit(ty.ptr(uniform, s), BuiltinFn::kBufferView, Vector{s}, p, 16_u, 32_u);
+        b.CallExplicit(ty.ptr(uniform, s), BuiltinFn::kBufferView, Vector<TemplateParameter, 1>{s},
+                       p, 16_u, 32_u);
         b.Return(func);
     });
 
@@ -5656,7 +5658,8 @@
     auto* o = b.FunctionParam("o", ty.i32());
     func->SetParams({p, o});
     b.Append(func->Block(), [&] {
-        b.CallExplicit(ty.ptr(workgroup, s), BuiltinFn::kBufferView, Vector{s}, p, o);
+        b.CallExplicit(ty.ptr(workgroup, s), BuiltinFn::kBufferView,
+                       Vector<TemplateParameter, 1>{s}, p, o);
         b.Return(func);
     });
 
@@ -5711,7 +5714,8 @@
     auto* p = b.FunctionParam("p", ty.ptr(storage, ty.unsized_buffer()));
     func->SetParams({p});
     b.Append(func->Block(), [&] {
-        b.CallExplicit(ty.ptr(storage, s), BuiltinFn::kBufferView, Vector{s}, p, 16_u);
+        b.CallExplicit(ty.ptr(storage, s), BuiltinFn::kBufferView, Vector<TemplateParameter, 1>{s},
+                       p, 16_u);
         b.Return(func);
     });
 
@@ -5766,7 +5770,8 @@
     auto* o = b.FunctionParam("o", ty.i32());
     func->SetParams({p, o});
     b.Append(func->Block(), [&] {
-        b.CallExplicit(ty.ptr(storage, s), BuiltinFn::kBufferView, Vector{s}, p, o, 64_u);
+        b.CallExplicit(ty.ptr(storage, s), BuiltinFn::kBufferView, Vector<TemplateParameter, 1>{s},
+                       p, o, 64_u);
         b.Return(func);
     });
 
@@ -5817,7 +5822,8 @@
     func->SetParams({p});
     b.Append(func->Block(), [&] {
         b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())), BuiltinFn::kBufferArrayView,
-                       Vector{ty.runtime_array(ty.u32())}, p, 16_u, 8_u, 32_u);
+                       Vector<TemplateParameter, 1>{ty.runtime_array(ty.u32())}, p, 16_u, 8_u,
+                       32_u);
         b.Return(func);
     });
 
@@ -5845,7 +5851,8 @@
     func->SetParams({p});
     b.Append(func->Block(), [&] {
         b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())), BuiltinFn::kBufferArrayView,
-                       Vector{ty.runtime_array(ty.u32())}, p, 4_u, 12_u, 12_u);
+                       Vector<TemplateParameter, 1>{ty.runtime_array(ty.u32())}, p, 4_u, 12_u,
+                       12_u);
         b.Return(func);
     });
 
@@ -5886,8 +5893,8 @@
     auto* p = b.FunctionParam("p", ty.ptr(storage, ty.unsized_buffer()));
     func->SetParams({p});
     b.Append(func->Block(), [&] {
-        b.CallExplicit(ty.ptr(storage, s), BuiltinFn::kBufferArrayView, Vector{s}, p, 16_u, 32_u,
-                       64_u);
+        b.CallExplicit(ty.ptr(storage, s), BuiltinFn::kBufferArrayView,
+                       Vector<TemplateParameter, 1>{s}, p, 16_u, 32_u, 64_u);
         b.Return(func);
     });
 
@@ -5924,8 +5931,8 @@
     auto* p = b.FunctionParam("p", ty.ptr(storage, ty.unsized_buffer()));
     func->SetParams({p});
     b.Append(func->Block(), [&] {
-        b.CallExplicit(ty.ptr(storage, s), BuiltinFn::kBufferArrayView, Vector{s}, p, 16_u, 32_u,
-                       32_u);
+        b.CallExplicit(ty.ptr(storage, s), BuiltinFn::kBufferArrayView,
+                       Vector<TemplateParameter, 1>{s}, p, 16_u, 32_u, 32_u);
         b.Return(func);
     });
 
@@ -5978,7 +5985,8 @@
     auto* s = b.FunctionParam("s", ty.i32());
     func->SetParams({p, o, s});
     b.Append(func->Block(), [&] {
-        b.CallExplicit(ty.ptr(storage, S), BuiltinFn::kBufferArrayView, Vector{S}, p, o, s);
+        b.CallExplicit(ty.ptr(storage, S), BuiltinFn::kBufferArrayView,
+                       Vector<TemplateParameter, 1>{S}, p, o, s);
         b.Return(func);
     });
 
@@ -6038,7 +6046,8 @@
     auto* s = b.FunctionParam("s", ty.i32());
     func->SetParams({p, s});
     b.Append(func->Block(), [&] {
-        b.CallExplicit(ty.ptr(storage, S), BuiltinFn::kBufferArrayView, Vector{S}, p, 8_i, s);
+        b.CallExplicit(ty.ptr(storage, S), BuiltinFn::kBufferArrayView,
+                       Vector<TemplateParameter, 1>{S}, p, 8_i, s);
         b.Return(func);
     });
 
@@ -6097,7 +6106,8 @@
     auto* o = b.FunctionParam("o", ty.i32());
     func->SetParams({p, o});
     b.Append(func->Block(), [&] {
-        b.CallExplicit(ty.ptr(storage, S), BuiltinFn::kBufferArrayView, Vector{S}, p, o, 64_i);
+        b.CallExplicit(ty.ptr(storage, S), BuiltinFn::kBufferArrayView,
+                       Vector<TemplateParameter, 1>{S}, p, o, 64_i);
         b.Return(func);
     });
 
diff --git a/src/tint/lang/core/ir/transform/substitute_overrides_test.cc b/src/tint/lang/core/ir/transform/substitute_overrides_test.cc
index 74183a2..a8b7df7 100644
--- a/src/tint/lang/core/ir/transform/substitute_overrides_test.cc
+++ b/src/tint/lang/core/ir/transform/substitute_overrides_test.cc
@@ -2307,7 +2307,7 @@
     b.Append(ep->Block(), [&] {
         auto* let = b.Let("l", v);
         b.CallExplicit(ty.ptr(workgroup, ty.array(ty.u32(), 4u)), BuiltinFn::kBufferView,
-                       Vector{ty.array(ty.u32(), 4u)}, let, 0_u);
+                       Vector<TemplateParameter, 1>{ty.array(ty.u32(), 4u)}, let, 0_u);
         b.Return(ep);
     });
 
@@ -2352,7 +2352,7 @@
     b.Append(ep->Block(), [&] {
         auto* let = b.Let("l", v);
         b.CallExplicit(ty.ptr(workgroup, ty.array(ty.u32(), 4u)), BuiltinFn::kBufferView,
-                       Vector{ty.array(ty.u32(), 4u)}, let, 4_u);
+                       Vector<TemplateParameter, 1>{ty.array(ty.u32(), 4u)}, let, 4_u);
         b.Return(ep);
     });
 
@@ -2397,7 +2397,7 @@
     b.Append(ep->Block(), [&] {
         auto* let = b.Let("l", v);
         b.CallExplicit(ty.ptr(workgroup, ty.runtime_array(ty.vec4u())), BuiltinFn::kBufferView,
-                       Vector{ty.runtime_array(ty.vec4u())}, let, 0_u);
+                       Vector<TemplateParameter, 1>{ty.runtime_array(ty.vec4u())}, let, 0_u);
         b.Return(ep);
     });
 
@@ -2442,7 +2442,7 @@
     b.Append(ep->Block(), [&] {
         auto* let = b.Let("l", v);
         b.CallExplicit(ty.ptr(workgroup, ty.runtime_array(ty.vec4u())), BuiltinFn::kBufferView,
-                       Vector{ty.runtime_array(ty.vec4u())}, let, 4_u);
+                       Vector<TemplateParameter, 1>{ty.runtime_array(ty.vec4u())}, let, 4_u);
         b.Return(ep);
     });
 
@@ -2491,7 +2491,8 @@
     auto* ep = b.ComputeFunction("ep", 1_u, 1_u, 1_u);
     b.Append(ep->Block(), [&] {
         auto* let = b.Let("l", v);
-        b.CallExplicit(ty.ptr(workgroup, S), BuiltinFn::kBufferView, Vector{S}, let, 0_u);
+        b.CallExplicit(ty.ptr(workgroup, S), BuiltinFn::kBufferView,
+                       Vector<TemplateParameter, 1>{S}, let, 0_u);
         b.Return(ep);
     });
 
@@ -2545,7 +2546,8 @@
     auto* ep = b.ComputeFunction("ep", 1_u, 1_u, 1_u);
     b.Append(ep->Block(), [&] {
         auto* let = b.Let("l", v);
-        b.CallExplicit(ty.ptr(workgroup, S), BuiltinFn::kBufferView, Vector{S}, let, 4_u);
+        b.CallExplicit(ty.ptr(workgroup, S), BuiltinFn::kBufferView,
+                       Vector<TemplateParameter, 1>{S}, let, 4_u);
         b.Return(ep);
     });
 
@@ -2591,7 +2593,8 @@
 
     auto* ep = b.ComputeFunction("ep", 1_u, 1_u, 1_u);
     b.Append(ep->Block(), [&] {
-        b.CallExplicit(ty.ptr(workgroup, ty.u32()), BuiltinFn::kBufferView, Vector{ty.u32()}, v, o);
+        b.CallExplicit(ty.ptr(workgroup, ty.u32()), BuiltinFn::kBufferView,
+                       Vector<TemplateParameter, 1>{ty.u32()}, v, o);
         b.Return(ep);
     });
 
@@ -2644,7 +2647,8 @@
 
     auto* ep = b.ComputeFunction("ep", 1_u, 1_u, 1_u);
     b.Append(ep->Block(), [&] {
-        b.CallExplicit(ty.ptr(workgroup, S), BuiltinFn::kBufferArrayView, Vector{S}, v, o, s);
+        b.CallExplicit(ty.ptr(workgroup, S), BuiltinFn::kBufferArrayView,
+                       Vector<TemplateParameter, 1>{S}, v, o, s);
         b.Return(ep);
     });
 
@@ -2706,7 +2710,8 @@
 
     auto* ep = b.ComputeFunction("ep", 1_u, 1_u, 1_u);
     b.Append(ep->Block(), [&] {
-        b.CallExplicit(ty.ptr(workgroup, S), BuiltinFn::kBufferArrayView, Vector{S}, v, o, s);
+        b.CallExplicit(ty.ptr(workgroup, S), BuiltinFn::kBufferArrayView,
+                       Vector<TemplateParameter, 1>{S}, v, o, s);
         b.Return(ep);
     });
 
@@ -2767,7 +2772,8 @@
 
     auto* ep = b.ComputeFunction("ep", 1_u, 1_u, 1_u);
     b.Append(ep->Block(), [&] {
-        b.CallExplicit(ty.ptr(workgroup, S), BuiltinFn::kBufferArrayView, Vector{S}, v, o, s);
+        b.CallExplicit(ty.ptr(workgroup, S), BuiltinFn::kBufferArrayView,
+                       Vector<TemplateParameter, 1>{S}, v, o, s);
         b.Return(ep);
     });
 
@@ -2820,8 +2826,8 @@
     auto* p = b.FunctionParam("p", ty.ptr(workgroup, ty.unsized_buffer()));
     foo->SetParams({p});
     b.Append(foo->Block(), [&] {
-        b.CallExplicit(ty.ptr(workgroup, ty.vec4u()), BuiltinFn::kBufferView, Vector{ty.vec4u()}, p,
-                       0_u);
+        b.CallExplicit(ty.ptr(workgroup, ty.vec4u()), BuiltinFn::kBufferView,
+                       Vector<TemplateParameter, 1>{ty.vec4u()}, p, 0_u);
         b.Return(foo);
     });
 
@@ -2876,8 +2882,8 @@
     auto* p = b.FunctionParam("p", ty.ptr(workgroup, ty.buffer(16)));
     foo->SetParams({p});
     b.Append(foo->Block(), [&] {
-        b.CallExplicit(ty.ptr(workgroup, ty.vec4u()), BuiltinFn::kBufferView, Vector{ty.vec4u()}, p,
-                       o);
+        b.CallExplicit(ty.ptr(workgroup, ty.vec4u()), BuiltinFn::kBufferView,
+                       Vector<TemplateParameter, 1>{ty.vec4u()}, p, o);
         b.Return(foo);
     });
 
diff --git a/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc
index 08c54e6..76ba087 100644
--- a/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc
+++ b/src/tint/lang/core/ir/transform/zero_init_workgroup_memory.cc
@@ -157,7 +157,7 @@
                         auto* arr_ty = ty.array(ele_ty, count);
                         store.buffer_view =
                             b.CallExplicit(ty.ptr(workgroup, arr_ty), core::BuiltinFn::kBufferView,
-                                           Vector{arr_ty}, store.var, 0_u);
+                                           Vector<TemplateParameter, 1>{arr_ty}, store.var, 0_u);
                     }
                 }
 
diff --git a/src/tint/lang/core/ir/validator_builtin_test.cc b/src/tint/lang/core/ir/validator_builtin_test.cc
index 593b451..5c183af 100644
--- a/src/tint/lang/core/ir/validator_builtin_test.cc
+++ b/src/tint/lang/core/ir/validator_builtin_test.cc
@@ -1596,8 +1596,8 @@
     f->SetParams({arr_param});
 
     b.Append(f->Block(), [&] {
-        b.CallExplicit(mat_ty, core::BuiltinFn::kSubgroupMatrixLoad, Vector{mat_ty}, arr_param, 8_u,
-                       true, 8_u);
+        b.CallExplicit(mat_ty, core::BuiltinFn::kSubgroupMatrixLoad,
+                       Vector<TemplateParameter, 1>{mat_ty}, arr_param, 8_u, true, 8_u);
         b.Return(f);
     });
 
@@ -1617,8 +1617,8 @@
     f->SetParams({arr_param});
 
     b.Append(f->Block(), [&] {
-        b.CallExplicit(mat_ty, core::BuiltinFn::kSubgroupMatrixLoad, Vector{mat_ty}, arr_param,
-                       -1_i, true, 8_u);
+        b.CallExplicit(mat_ty, core::BuiltinFn::kSubgroupMatrixLoad,
+                       Vector<TemplateParameter, 1>{mat_ty}, arr_param, -1_i, true, 8_u);
         b.Return(f);
     });
 
diff --git a/src/tint/lang/glsl/BUILD.bazel b/src/tint/lang/glsl/BUILD.bazel
index a026138..141dafb 100644
--- a/src/tint/lang/glsl/BUILD.bazel
+++ b/src/tint/lang/glsl/BUILD.bazel
@@ -50,14 +50,21 @@
     "//src/tint:gen/src/tint/lang/glsl/builtin_fn.h",
   ],
   deps = [
+    "//src/tint/lang/core",
+    "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/intrinsic",
     "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
+    "//src/tint/utils",
     "//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/rtti",
+    "//src/tint/utils/text",
     "//src/tint:generated_tint_headers",
     "//src/utils",
   ],
diff --git a/src/tint/lang/glsl/BUILD.cmake b/src/tint/lang/glsl/BUILD.cmake
index 368cd79..ff2a529 100644
--- a/src/tint/lang/glsl/BUILD.cmake
+++ b/src/tint/lang/glsl/BUILD.cmake
@@ -49,14 +49,21 @@
 )
 
 tint_target_add_dependencies(tint_lang_glsl lib
+  tint_lang_core
+  tint_lang_core_constant
+  tint_lang_core_intrinsic
   tint_lang_core_ir
   tint_lang_core_type
+  tint_utils
   tint_utils_containers
+  tint_utils_diagnostic
   tint_utils_ice
   tint_utils_macros
   tint_utils_math
   tint_utils_memory
+  tint_utils_reflection
   tint_utils_rtti
+  tint_utils_text
 )
 
 tint_target_add_external_dependencies(tint_lang_glsl lib
diff --git a/src/tint/lang/glsl/BUILD.gn b/src/tint/lang/glsl/BUILD.gn
index 7b02600..a191001 100644
--- a/src/tint/lang/glsl/BUILD.gn
+++ b/src/tint/lang/glsl/BUILD.gn
@@ -47,13 +47,20 @@
   deps = [
     "${dawn_root}/src/utils",
     "${tint_src_dir}:generate_sources",
+    "${tint_src_dir}/lang/core",
+    "${tint_src_dir}/lang/core/constant",
+    "${tint_src_dir}/lang/core/intrinsic",
     "${tint_src_dir}/lang/core/ir",
     "${tint_src_dir}/lang/core/type",
+    "${tint_src_dir}/utils",
     "${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/rtti",
+    "${tint_src_dir}/utils/text",
   ]
 }
diff --git a/src/tint/lang/glsl/ir/builtin_call_test.cc b/src/tint/lang/glsl/ir/builtin_call_test.cc
index 60b7085..0fbda54 100644
--- a/src/tint/lang/glsl/ir/builtin_call_test.cc
+++ b/src/tint/lang/glsl/ir/builtin_call_test.cc
@@ -58,7 +58,7 @@
 
 TEST_F(IR_GlslBuiltinCallTest, CloneWithExplicitParams) {
     auto* builtin = b.Call<BuiltinCall>(mod.Types().void_(), BuiltinFn::kBarrier);
-    builtin->SetExplicitTemplateParams(Vector{mod.Types().i32()});
+    builtin->SetExplicitTemplateParams(Vector<core::ir::TemplateParameter, 1>{mod.Types().i32()});
 
     auto* new_b = clone_ctx.Clone(builtin);
     EXPECT_NE(builtin->Result(), new_b->Result());
diff --git a/src/tint/lang/glsl/ir/member_builtin_call_test.cc b/src/tint/lang/glsl/ir/member_builtin_call_test.cc
index a636636..4a54f84 100644
--- a/src/tint/lang/glsl/ir/member_builtin_call_test.cc
+++ b/src/tint/lang/glsl/ir/member_builtin_call_test.cc
@@ -76,7 +76,7 @@
 
     auto* access = b.Access(ty.ptr<storage, array<u32>, read_write>(), var, 0_u);
     auto* builtin = b.MemberCall<MemberBuiltinCall>(mod.Types().i32(), BuiltinFn::kLength, access);
-    builtin->SetExplicitTemplateParams(Vector{mod.Types().i32()});
+    builtin->SetExplicitTemplateParams(Vector<core::ir::TemplateParameter, 1>{mod.Types().i32()});
 
     auto* new_b = clone_ctx.Clone(builtin);
     EXPECT_NE(builtin->Result(), new_b->Result());
diff --git a/src/tint/lang/glsl/writer/helpers/BUILD.bazel b/src/tint/lang/glsl/writer/helpers/BUILD.bazel
index da66128..76b0e30 100644
--- a/src/tint/lang/glsl/writer/helpers/BUILD.bazel
+++ b/src/tint/lang/glsl/writer/helpers/BUILD.bazel
@@ -52,6 +52,7 @@
     "//src/tint/api/common",
     "//src/tint/lang/core",
     "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/intrinsic",
     "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
     "//src/tint/lang/glsl/writer/common",
diff --git a/src/tint/lang/glsl/writer/helpers/BUILD.cmake b/src/tint/lang/glsl/writer/helpers/BUILD.cmake
index ac5124e..b654b99 100644
--- a/src/tint/lang/glsl/writer/helpers/BUILD.cmake
+++ b/src/tint/lang/glsl/writer/helpers/BUILD.cmake
@@ -49,6 +49,7 @@
   tint_api_common
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_intrinsic
   tint_lang_core_ir
   tint_lang_core_type
   tint_lang_glsl_writer_common
diff --git a/src/tint/lang/glsl/writer/helpers/BUILD.gn b/src/tint/lang/glsl/writer/helpers/BUILD.gn
index bbfbc39..0264874 100644
--- a/src/tint/lang/glsl/writer/helpers/BUILD.gn
+++ b/src/tint/lang/glsl/writer/helpers/BUILD.gn
@@ -49,6 +49,7 @@
       "${tint_src_dir}/api/common",
       "${tint_src_dir}/lang/core",
       "${tint_src_dir}/lang/core/constant",
+      "${tint_src_dir}/lang/core/intrinsic",
       "${tint_src_dir}/lang/core/ir",
       "${tint_src_dir}/lang/core/type",
       "${tint_src_dir}/lang/glsl/writer/common",
diff --git a/src/tint/lang/glsl/writer/writer_test.cc b/src/tint/lang/glsl/writer/writer_test.cc
index fb956ec..3ba99f8 100644
--- a/src/tint/lang/glsl/writer/writer_test.cc
+++ b/src/tint/lang/glsl/writer/writer_test.cc
@@ -312,10 +312,10 @@
     auto* ep = b.ComputeFunction("main");
     b.Append(ep->Block(), [&] {
         auto* view1 = b.CallExplicit(ty.ptr(storage, ty.f16()), core::BuiltinFn::kBufferView,
-                                     Vector{ty.f16()}, v, 0_u);
+                                     Vector<core::ir::TemplateParameter, 1>{ty.f16()}, v, 0_u);
         b.Load(view1);
         auto* view2 = b.CallExplicit(ty.ptr(storage, ty.u32()), core::BuiltinFn::kBufferView,
-                                     Vector{ty.u32()}, v, 0_u);
+                                     Vector<core::ir::TemplateParameter, 1>{ty.u32()}, v, 0_u);
         b.Load(view2);
         b.Return(ep);
     });
diff --git a/src/tint/lang/hlsl/BUILD.bazel b/src/tint/lang/hlsl/BUILD.bazel
index b3ca310..c573db5 100644
--- a/src/tint/lang/hlsl/BUILD.bazel
+++ b/src/tint/lang/hlsl/BUILD.bazel
@@ -50,14 +50,21 @@
     "//src/tint:gen/src/tint/lang/hlsl/builtin_fn.h",
   ],
   deps = [
+    "//src/tint/lang/core",
+    "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/intrinsic",
     "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
+    "//src/tint/utils",
     "//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/rtti",
+    "//src/tint/utils/text",
     "//src/tint:generated_tint_headers",
     "//src/utils",
   ],
diff --git a/src/tint/lang/hlsl/BUILD.cmake b/src/tint/lang/hlsl/BUILD.cmake
index 924859d..c05e0d2 100644
--- a/src/tint/lang/hlsl/BUILD.cmake
+++ b/src/tint/lang/hlsl/BUILD.cmake
@@ -50,14 +50,21 @@
 )
 
 tint_target_add_dependencies(tint_lang_hlsl lib
+  tint_lang_core
+  tint_lang_core_constant
+  tint_lang_core_intrinsic
   tint_lang_core_ir
   tint_lang_core_type
+  tint_utils
   tint_utils_containers
+  tint_utils_diagnostic
   tint_utils_ice
   tint_utils_macros
   tint_utils_math
   tint_utils_memory
+  tint_utils_reflection
   tint_utils_rtti
+  tint_utils_text
 )
 
 tint_target_add_external_dependencies(tint_lang_hlsl lib
diff --git a/src/tint/lang/hlsl/BUILD.gn b/src/tint/lang/hlsl/BUILD.gn
index e4f0d72..41efd6e 100644
--- a/src/tint/lang/hlsl/BUILD.gn
+++ b/src/tint/lang/hlsl/BUILD.gn
@@ -47,13 +47,20 @@
   deps = [
     "${dawn_root}/src/utils",
     "${tint_src_dir}:generate_sources",
+    "${tint_src_dir}/lang/core",
+    "${tint_src_dir}/lang/core/constant",
+    "${tint_src_dir}/lang/core/intrinsic",
     "${tint_src_dir}/lang/core/ir",
     "${tint_src_dir}/lang/core/type",
+    "${tint_src_dir}/utils",
     "${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/rtti",
+    "${tint_src_dir}/utils/text",
   ]
 }
diff --git a/src/tint/lang/hlsl/ir/builtin_call_test.cc b/src/tint/lang/hlsl/ir/builtin_call_test.cc
index bf111a5..620e168 100644
--- a/src/tint/lang/hlsl/ir/builtin_call_test.cc
+++ b/src/tint/lang/hlsl/ir/builtin_call_test.cc
@@ -61,7 +61,7 @@
 
 TEST_F(IR_HlslBuiltinCallTest, CloneWithExplicitParams) {
     auto* builtin = b.Call<BuiltinCall>(mod.Types().u32(), BuiltinFn::kF32Tof16, 0_f);
-    builtin->SetExplicitTemplateParams(Vector{mod.Types().i32()});
+    builtin->SetExplicitTemplateParams(Vector<core::ir::TemplateParameter, 1>{mod.Types().i32()});
 
     auto* new_b = clone_ctx.Clone(builtin);
     EXPECT_NE(builtin->Result(), new_b->Result());
diff --git a/src/tint/lang/hlsl/ir/member_builtin_call_test.cc b/src/tint/lang/hlsl/ir/member_builtin_call_test.cc
index b41693b..b0758cc 100644
--- a/src/tint/lang/hlsl/ir/member_builtin_call_test.cc
+++ b/src/tint/lang/hlsl/ir/member_builtin_call_test.cc
@@ -80,7 +80,7 @@
 
     auto* t = b.FunctionParam("t", buf);
     auto* builtin = b.MemberCall<MemberBuiltinCall>(mod.Types().u32(), BuiltinFn::kLoad, t, 2_u);
-    builtin->SetExplicitTemplateParams(Vector{mod.Types().i32()});
+    builtin->SetExplicitTemplateParams(Vector<core::ir::TemplateParameter, 1>{mod.Types().i32()});
 
     auto* new_b = clone_ctx.Clone(builtin);
     EXPECT_NE(builtin->Result(), new_b->Result());
diff --git a/src/tint/lang/hlsl/writer/printer/printer.cc b/src/tint/lang/hlsl/writer/printer/printer.cc
index 2e1ffbc..2bbdc50 100644
--- a/src/tint/lang/hlsl/writer/printer/printer.cc
+++ b/src/tint/lang/hlsl/writer/printer/printer.cc
@@ -911,7 +911,9 @@
         // enum value here.
         if (c->Func() == hlsl::BuiltinFn::kMultiply) {
             TINT_IR_ASSERT(ir_, c->ExplicitTemplateParams().Length() == 1u);
-            auto* explicit_type = c->ExplicitTemplateParams()[0];
+            TINT_IR_ASSERT(ir_, std::holds_alternative<const core::type::Type*>(
+                                    c->ExplicitTemplateParams()[0]));
+            auto* explicit_type = std::get<const core::type::Type*>(c->ExplicitTemplateParams()[0]);
             auto* left_type = c->Args()[0]->Type()->As<core::type::SubgroupMatrix>()->Type();
             if (explicit_type != left_type) {
                 out << "<" << SubgroupMatrixComponentTypeToEnum(explicit_type) << ">";
diff --git a/src/tint/lang/hlsl/writer/raise/builtin_polyfill.cc b/src/tint/lang/hlsl/writer/raise/builtin_polyfill.cc
index 111f402..4f05fc2 100644
--- a/src/tint/lang/hlsl/writer/raise/builtin_polyfill.cc
+++ b/src/tint/lang/hlsl/writer/raise/builtin_polyfill.cc
@@ -571,7 +571,8 @@
         } else if (dst_deepest->Is<core::type::F16>()) {
             fn = BuiltinFn::kAsfloat16;
         } else {
-            TINT_IR_ICE(ir) << "unexpected 16-bit bitcast destination type: " << dst_deepest;
+            TINT_IR_ICE(ir) << "unexpected 16-bit bitcast destination type: "
+                            << dst_deepest->FriendlyName();
         }
 
         b.InsertBefore(bitcast, [&] {
@@ -1736,8 +1737,9 @@
         auto args = call->Args();
         b.InsertBefore(call, [&] {
             auto* type = ty.Get<hlsl::type::Int8T4Packed>();
-            auto* conv = b.CallExplicit<hlsl::ir::BuiltinCall>(type, hlsl::BuiltinFn::kConvert,
-                                                               Vector{type}, args[0]);
+            auto* conv = b.CallExplicit<hlsl::ir::BuiltinCall>(
+                type, hlsl::BuiltinFn::kConvert, Vector<core::ir::TemplateParameter, 1>{type},
+                args[0]);
 
             b.CallWithResult<hlsl::ir::BuiltinCall>(call->DetachResult(),
                                                     hlsl::BuiltinFn::kUnpackS8S32, conv);
@@ -1761,8 +1763,9 @@
         auto args = call->Args();
         b.InsertBefore(call, [&] {
             auto* type = ty.Get<hlsl::type::Uint8T4Packed>();
-            auto* conv = b.CallExplicit<hlsl::ir::BuiltinCall>(type, hlsl::BuiltinFn::kConvert,
-                                                               Vector{type}, args[0]);
+            auto* conv = b.CallExplicit<hlsl::ir::BuiltinCall>(
+                type, hlsl::BuiltinFn::kConvert, Vector<core::ir::TemplateParameter, 1>{type},
+                args[0]);
 
             b.CallWithResult<hlsl::ir::BuiltinCall>(call->DetachResult(),
                                                     hlsl::BuiltinFn::kUnpackU8U32, conv);
@@ -1965,9 +1968,9 @@
             auto* sm_ty = result_ty->As<core::type::SubgroupMatrix>();
             TINT_IR_ASSERT(ir, sm_ty);
 
-            b.CallExplicitWithResult<hlsl::ir::BuiltinCall>(call->DetachResult(),
-                                                            hlsl::BuiltinFn::kMultiply,
-                                                            Vector{sm_ty->Type()}, left, right);
+            b.CallExplicitWithResult<hlsl::ir::BuiltinCall>(
+                call->DetachResult(), hlsl::BuiltinFn::kMultiply,
+                Vector<core::ir::TemplateParameter, 1>{sm_ty->Type()}, left, right);
         });
         call->Destroy();
     }
@@ -2090,9 +2093,9 @@
 
             auto* layout = ColMajorToMatrixLayout(col_major);
 
-            b.CallExplicitWithResult<hlsl::ir::BuiltinCall>(call->DetachResult(),
-                                                            hlsl::BuiltinFn::kLoad, Vector{sm_ty},
-                                                            ptr, offset, stride, layout);
+            b.CallExplicitWithResult<hlsl::ir::BuiltinCall>(
+                call->DetachResult(), hlsl::BuiltinFn::kLoad,
+                Vector<core::ir::TemplateParameter, 1>{sm_ty}, ptr, offset, stride, layout);
         });
         call->Destroy();
     }
diff --git a/src/tint/lang/hlsl/writer/raise/builtin_polyfill_test.cc b/src/tint/lang/hlsl/writer/raise/builtin_polyfill_test.cc
index d5a6c3b..184b81d 100644
--- a/src/tint/lang/hlsl/writer/raise/builtin_polyfill_test.cc
+++ b/src/tint/lang/hlsl/writer/raise/builtin_polyfill_test.cc
@@ -7659,7 +7659,7 @@
     func->SetParams({left, right});
     b.Append(func->Block(), [&] {
         auto* call = b.CallExplicit(result, core::BuiltinFn::kSubgroupMatrixMultiply,
-                                    Vector{ty.f32()}, left, right);
+                                    Vector<core::ir::TemplateParameter, 1>{ty.f32()}, left, right);
         b.Return(func, call);
     });
 
@@ -8162,8 +8162,9 @@
 
     auto* func = b.Function("foo", mat_ty);
     b.Append(func->Block(), [&] {
-        auto* load = b.CallExplicit(mat_ty, core::BuiltinFn::kSubgroupMatrixLoad, Vector{mat_ty},
-                                    wg_var, 0_u, b.Constant(false), 4_u);
+        auto* load = b.CallExplicit(mat_ty, core::BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<core::ir::TemplateParameter, 1>{mat_ty}, wg_var, 0_u,
+                                    b.Constant(false), 4_u);
         b.Return(func, load);
     });
 
diff --git a/src/tint/lang/hlsl/writer/raise/decompose_storage_access.cc b/src/tint/lang/hlsl/writer/raise/decompose_storage_access.cc
index 2df1fb3..f2b4d29 100644
--- a/src/tint/lang/hlsl/writer/raise/decompose_storage_access.cc
+++ b/src/tint/lang/hlsl/writer/raise/decompose_storage_access.cc
@@ -389,7 +389,8 @@
                 stride = b.Multiply(stride, u32(bytes_per_element))->Result();
             }
             auto* load = b.CallExplicit<hlsl::ir::BuiltinCall>(
-                sm, BuiltinFn::kLoad, Vector{sm}, var, OffsetToValue(offset), stride, layout);
+                sm, BuiltinFn::kLoad, Vector<core::ir::TemplateParameter, 1>{sm}, var,
+                OffsetToValue(offset), stride, layout);
             call->Result()->ReplaceAllUsesWith(load->Result());
         });
         call->Destroy();
diff --git a/src/tint/lang/hlsl/writer/raise/decompose_storage_access_test.cc b/src/tint/lang/hlsl/writer/raise/decompose_storage_access_test.cc
index f3517ca..1bde817 100644
--- a/src/tint/lang/hlsl/writer/raise/decompose_storage_access_test.cc
+++ b/src/tint/lang/hlsl/writer/raise/decompose_storage_access_test.cc
@@ -1699,8 +1699,9 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        auto* load = b.CallExplicit(sm_ty, core::BuiltinFn::kSubgroupMatrixLoad, Vector{sm_ty}, var,
-                                    0_u, b.Constant(false), 8_u);
+        auto* load = b.CallExplicit(sm_ty, core::BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<core::ir::TemplateParameter, 1>{sm_ty}, var, 0_u,
+                                    b.Constant(false), 8_u);
         b.Let("x", load);
         b.Return(func);
     });
@@ -1748,8 +1749,9 @@
 
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        auto* load = b.CallExplicit(sm_ty, core::BuiltinFn::kSubgroupMatrixLoad, Vector{sm_ty}, var,
-                                    0_u, b.Constant(true), 8_u);
+        auto* load = b.CallExplicit(sm_ty, core::BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<core::ir::TemplateParameter, 1>{sm_ty}, var, 0_u,
+                                    b.Constant(true), 8_u);
         b.Let("x", load);
         b.Return(func);
     });
@@ -1800,8 +1802,9 @@
     func->SetParams({stride_param});
 
     b.Append(func->Block(), [&] {
-        auto* load = b.CallExplicit(sm_ty, core::BuiltinFn::kSubgroupMatrixLoad, Vector{sm_ty}, var,
-                                    0_u, b.Constant(false), stride_param);
+        auto* load = b.CallExplicit(sm_ty, core::BuiltinFn::kSubgroupMatrixLoad,
+                                    Vector<core::ir::TemplateParameter, 1>{sm_ty}, var, 0_u,
+                                    b.Constant(false), stride_param);
         b.Let("x", load);
         b.Return(func);
     });
@@ -4906,7 +4909,7 @@
     auto* foo = b.Function("foo", ty.void_());
     b.Append(foo->Block(), [&] {
         auto* view = b.CallExplicit(ty.ptr(storage, ty.u32()), core::BuiltinFn::kBufferView,
-                                    Vector{ty.u32()}, v, 0_u);
+                                    Vector<core::ir::TemplateParameter, 1>{ty.u32()}, v, 0_u);
         b.Load(view);
         b.Return(foo);
     });
@@ -4953,7 +4956,7 @@
     auto* foo = b.Function("foo", ty.void_());
     b.Append(foo->Block(), [&] {
         auto* view = b.CallExplicit(ty.ptr(storage, ty.u32()), core::BuiltinFn::kBufferView,
-                                    Vector{ty.u32()}, v, 16_u);
+                                    Vector<core::ir::TemplateParameter, 1>{ty.u32()}, v, 16_u);
         b.Load(view);
         b.Return(foo);
     });
@@ -5002,7 +5005,7 @@
     foo->SetParams({offset});
     b.Append(foo->Block(), [&] {
         auto* view = b.CallExplicit(ty.ptr(storage, ty.u32()), core::BuiltinFn::kBufferView,
-                                    Vector{ty.u32()}, v, offset);
+                                    Vector<core::ir::TemplateParameter, 1>{ty.u32()}, v, offset);
         b.Load(view);
         b.Return(foo);
     });
@@ -5052,9 +5055,9 @@
     auto* offset = b.FunctionParam("offset", ty.u32());
     foo->SetParams({offset});
     b.Append(foo->Block(), [&] {
-        auto* view =
-            b.CallExplicit(ty.ptr(storage, ty.array(ty.u32(), 4)), core::BuiltinFn::kBufferView,
-                           Vector{ty.array(ty.u32(), 4)}, v, offset);
+        auto* view = b.CallExplicit(
+            ty.ptr(storage, ty.array(ty.u32(), 4)), core::BuiltinFn::kBufferView,
+            Vector<core::ir::TemplateParameter, 1>{ty.array(ty.u32(), 4)}, v, offset);
         auto* a = b.Access(ty.ptr(storage, ty.u32()), view, 2_u);
         b.Load(a);
         b.Return(foo);
@@ -5104,9 +5107,9 @@
 
     auto* foo = b.Function("foo", ty.void_());
     b.Append(foo->Block(), [&] {
-        auto* view = b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())),
-                                    core::BuiltinFn::kBufferArrayView,
-                                    Vector{ty.runtime_array(ty.u32())}, v, 0_u, 128_u);
+        auto* view = b.CallExplicit(
+            ty.ptr(storage, ty.runtime_array(ty.u32())), core::BuiltinFn::kBufferArrayView,
+            Vector<core::ir::TemplateParameter, 1>{ty.runtime_array(ty.u32())}, v, 0_u, 128_u);
         auto* a = b.Access(ty.ptr(storage, ty.u32()), view, 0_u);
         b.Load(a);
         b.Return(foo);
@@ -5154,9 +5157,9 @@
 
     auto* foo = b.Function("foo", ty.void_());
     b.Append(foo->Block(), [&] {
-        auto* view = b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())),
-                                    core::BuiltinFn::kBufferArrayView,
-                                    Vector{ty.runtime_array(ty.u32())}, v, 16_u, 128_u);
+        auto* view = b.CallExplicit(
+            ty.ptr(storage, ty.runtime_array(ty.u32())), core::BuiltinFn::kBufferArrayView,
+            Vector<core::ir::TemplateParameter, 1>{ty.runtime_array(ty.u32())}, v, 16_u, 128_u);
         auto* a = b.Access(ty.ptr(storage, ty.u32()), view, 0_u);
         b.Load(a);
         b.Return(foo);
@@ -5206,9 +5209,9 @@
     auto* offset = b.FunctionParam("offset", ty.u32());
     foo->SetParams({offset});
     b.Append(foo->Block(), [&] {
-        auto* view = b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())),
-                                    core::BuiltinFn::kBufferArrayView,
-                                    Vector{ty.runtime_array(ty.u32())}, v, offset, 128_u);
+        auto* view = b.CallExplicit(
+            ty.ptr(storage, ty.runtime_array(ty.u32())), core::BuiltinFn::kBufferArrayView,
+            Vector<core::ir::TemplateParameter, 1>{ty.runtime_array(ty.u32())}, v, offset, 128_u);
         auto* a = b.Access(ty.ptr(storage, ty.u32()), view, 0_u);
         b.Load(a);
         b.Return(foo);
@@ -5260,9 +5263,9 @@
     auto* offset = b.FunctionParam("offset", ty.u32());
     foo->SetParams({offset});
     b.Append(foo->Block(), [&] {
-        auto* view = b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())),
-                                    core::BuiltinFn::kBufferArrayView,
-                                    Vector{ty.runtime_array(ty.u32())}, v, offset, 128_u);
+        auto* view = b.CallExplicit(
+            ty.ptr(storage, ty.runtime_array(ty.u32())), core::BuiltinFn::kBufferArrayView,
+            Vector<core::ir::TemplateParameter, 1>{ty.runtime_array(ty.u32())}, v, offset, 128_u);
         auto* a = b.Access(ty.ptr(storage, ty.u32()), view, 16_u);
         b.Load(a);
         b.Return(foo);
@@ -5316,8 +5319,9 @@
     auto* length = b.FunctionParam("length", ty.u32());
     foo->SetParams({offset, length});
     b.Append(foo->Block(), [&] {
-        auto* view = b.CallExplicit(ty.ptr(storage, arr_ty), core::BuiltinFn::kBufferView,
-                                    Vector{arr_ty}, v, offset, length);
+        auto* view =
+            b.CallExplicit(ty.ptr(storage, arr_ty), core::BuiltinFn::kBufferView,
+                           Vector<core::ir::TemplateParameter, 1>{arr_ty}, v, offset, length);
         auto* len = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, view);
         b.Let("len", len);
         b.Return(foo);
@@ -5372,7 +5376,7 @@
     foo->SetParams({offset});
     b.Append(foo->Block(), [&] {
         auto* view = b.CallExplicit(ty.ptr(storage, arr_ty), core::BuiltinFn::kBufferView,
-                                    Vector{arr_ty}, v, offset);
+                                    Vector<core::ir::TemplateParameter, 1>{arr_ty}, v, offset);
         auto* len = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, view);
         b.Let("len", len);
         b.Return(foo);
@@ -5433,8 +5437,8 @@
     auto* offset = b.FunctionParam("offset", ty.u32());
     foo->SetParams({offset});
     b.Append(foo->Block(), [&] {
-        auto* view =
-            b.CallExplicit(ty.ptr(storage, S), core::BuiltinFn::kBufferView, Vector{S}, v, offset);
+        auto* view = b.CallExplicit(ty.ptr(storage, S), core::BuiltinFn::kBufferView,
+                                    Vector<core::ir::TemplateParameter, 1>{S}, v, offset);
         auto* a = b.Access(ty.ptr(storage, arr_ty), view, 1_u);
         auto* len = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, a);
         b.Let("len", len);
diff --git a/src/tint/lang/hlsl/writer/raise/replace_subgroup_matrix_init.cc b/src/tint/lang/hlsl/writer/raise/replace_subgroup_matrix_init.cc
index 9be409e..73dad98 100644
--- a/src/tint/lang/hlsl/writer/raise/replace_subgroup_matrix_init.cc
+++ b/src/tint/lang/hlsl/writer/raise/replace_subgroup_matrix_init.cc
@@ -164,8 +164,8 @@
     }
 
     core::ir::Call* Splat(const core::type::SubgroupMatrix* sm, core::ir::Value* value) {
-        return b.CallExplicit<hlsl::ir::BuiltinCall>(sm, hlsl::BuiltinFn::kSplat, Vector{sm},
-                                                     value);
+        return b.CallExplicit<hlsl::ir::BuiltinCall>(
+            sm, hlsl::BuiltinFn::kSplat, Vector<core::ir::TemplateParameter, 1>{sm}, value);
     }
 };
 
diff --git a/src/tint/lang/msl/BUILD.bazel b/src/tint/lang/msl/BUILD.bazel
index 1f42d90..2f02af3 100644
--- a/src/tint/lang/msl/BUILD.bazel
+++ b/src/tint/lang/msl/BUILD.bazel
@@ -51,14 +51,21 @@
     "//src/tint:gen/src/tint/lang/msl/builtin_fn.h",
   ],
   deps = [
+    "//src/tint/lang/core",
+    "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/intrinsic",
     "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
+    "//src/tint/utils",
     "//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/rtti",
+    "//src/tint/utils/text",
     "//src/tint:generated_tint_headers",
     "//src/utils",
   ],
diff --git a/src/tint/lang/msl/BUILD.cmake b/src/tint/lang/msl/BUILD.cmake
index 065e9d5..34b95d7 100644
--- a/src/tint/lang/msl/BUILD.cmake
+++ b/src/tint/lang/msl/BUILD.cmake
@@ -51,14 +51,21 @@
 )
 
 tint_target_add_dependencies(tint_lang_msl lib
+  tint_lang_core
+  tint_lang_core_constant
+  tint_lang_core_intrinsic
   tint_lang_core_ir
   tint_lang_core_type
+  tint_utils
   tint_utils_containers
+  tint_utils_diagnostic
   tint_utils_ice
   tint_utils_macros
   tint_utils_math
   tint_utils_memory
+  tint_utils_reflection
   tint_utils_rtti
+  tint_utils_text
 )
 
 tint_target_add_external_dependencies(tint_lang_msl lib
diff --git a/src/tint/lang/msl/BUILD.gn b/src/tint/lang/msl/BUILD.gn
index a0c3596..74f4456 100644
--- a/src/tint/lang/msl/BUILD.gn
+++ b/src/tint/lang/msl/BUILD.gn
@@ -48,13 +48,20 @@
   deps = [
     "${dawn_root}/src/utils",
     "${tint_src_dir}:generate_sources",
+    "${tint_src_dir}/lang/core",
+    "${tint_src_dir}/lang/core/constant",
+    "${tint_src_dir}/lang/core/intrinsic",
     "${tint_src_dir}/lang/core/ir",
     "${tint_src_dir}/lang/core/type",
+    "${tint_src_dir}/utils",
     "${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/rtti",
+    "${tint_src_dir}/utils/text",
   ]
 }
diff --git a/src/tint/lang/msl/ir/builtin_call_test.cc b/src/tint/lang/msl/ir/builtin_call_test.cc
index f480819..b4dadf9 100644
--- a/src/tint/lang/msl/ir/builtin_call_test.cc
+++ b/src/tint/lang/msl/ir/builtin_call_test.cc
@@ -64,7 +64,7 @@
 
 TEST_F(IR_MslBuiltinCallTest, CloneWithExplicitParams) {
     auto* builtin = b.Call<BuiltinCall>(mod.Types().void_(), BuiltinFn::kThreadgroupBarrier, 0_u);
-    builtin->SetExplicitTemplateParams(Vector{mod.Types().i32()});
+    builtin->SetExplicitTemplateParams(Vector<core::ir::TemplateParameter, 1>{mod.Types().i32()});
 
     auto* new_b = clone_ctx.Clone(builtin);
     EXPECT_NE(builtin->Result(), new_b->Result());
diff --git a/src/tint/lang/msl/ir/member_builtin_call_test.cc b/src/tint/lang/msl/ir/member_builtin_call_test.cc
index 15fd649..20d2358 100644
--- a/src/tint/lang/msl/ir/member_builtin_call_test.cc
+++ b/src/tint/lang/msl/ir/member_builtin_call_test.cc
@@ -76,7 +76,7 @@
     auto* coords = b.FunctionParam("coords", ty.vec2f());
     auto* builtin =
         b.MemberCall<MemberBuiltinCall>(mod.Types().void_(), BuiltinFn::kSample, t, s, coords);
-    builtin->SetExplicitTemplateParams(Vector{mod.Types().i32()});
+    builtin->SetExplicitTemplateParams(Vector<core::ir::TemplateParameter, 1>{mod.Types().i32()});
 
     auto* new_b = clone_ctx.Clone(builtin);
     EXPECT_NE(builtin->Result(), new_b->Result());
diff --git a/src/tint/lang/msl/writer/raise/builtin_polyfill.cc b/src/tint/lang/msl/writer/raise/builtin_polyfill.cc
index 56f4ad8..7eb5aa7 100644
--- a/src/tint/lang/msl/writer/raise/builtin_polyfill.cc
+++ b/src/tint/lang/msl/writer/raise/builtin_polyfill.cc
@@ -360,7 +360,7 @@
         b.InsertBefore(construct, [&] {
             b.CallExplicitWithResult<msl::ir::BuiltinCall>(
                 construct->DetachResult(), msl::BuiltinFn::kMakeFilledSimdgroupMatrix,
-                Vector{sm_ty}, value);
+                Vector<core::ir::TemplateParameter, 1>{sm_ty}, value);
         });
         construct->Destroy();
     }
@@ -1214,7 +1214,8 @@
                                             sm_ty->Columns(), sm_ty->Rows());
         return b
             .CallExplicit<msl::ir::BuiltinCall>(
-                right_ty, msl::BuiltinFn::kMakeDiagonalSimdgroupMatrix, Vector{right_ty}, scalar)
+                right_ty, msl::BuiltinFn::kMakeDiagonalSimdgroupMatrix,
+                Vector<core::ir::TemplateParameter, 1>{right_ty}, scalar)
             ->Result();
     }
 
@@ -1222,7 +1223,8 @@
                                                    core::ir::Value* scalar) {
         return b
             .CallExplicit<msl::ir::BuiltinCall>(
-                result_ty, msl::BuiltinFn::kMakeFilledSimdgroupMatrix, Vector{result_ty}, scalar)
+                result_ty, msl::BuiltinFn::kMakeFilledSimdgroupMatrix,
+                Vector<core::ir::TemplateParameter, 1>{result_ty}, scalar)
             ->Result();
     }
 
@@ -1231,7 +1233,8 @@
         auto* left_ty = ty.subgroup_matrix(core::SubgroupMatrixKind::kLeft, sm_ty->Type(),
                                            sm_ty->Columns(), sm_ty->Rows());
         return b
-            .CallExplicit<msl::ir::BuiltinCall>(left_ty, msl::BuiltinFn::kConvert, Vector{left_ty},
+            .CallExplicit<msl::ir::BuiltinCall>(left_ty, msl::BuiltinFn::kConvert,
+                                                Vector<core::ir::TemplateParameter, 1>{left_ty},
                                                 mat)
             ->Result();
     }
@@ -1268,7 +1271,8 @@
             auto* ld = b.Load(tmp);
 
             b.CallExplicitWithResult<msl::ir::BuiltinCall>(
-                builtin->DetachResult(), msl::BuiltinFn::kConvert, Vector{sm_ty}, ld);
+                builtin->DetachResult(), msl::BuiltinFn::kConvert,
+                Vector<core::ir::TemplateParameter, 1>{sm_ty}, ld);
         });
         builtin->Destroy();
     }
@@ -1301,7 +1305,8 @@
             auto* ld = b.Load(tmp);
 
             b.CallExplicitWithResult<msl::ir::BuiltinCall>(
-                builtin->DetachResult(), msl::BuiltinFn::kConvert, Vector{sm_ty}, ld);
+                builtin->DetachResult(), msl::BuiltinFn::kConvert,
+                Vector<core::ir::TemplateParameter, 1>{sm_ty}, ld);
         });
         builtin->Destroy();
     }
@@ -1333,7 +1338,8 @@
             auto* ld = b.Load(tmp);
 
             b.CallExplicitWithResult<msl::ir::BuiltinCall>(
-                builtin->DetachResult(), msl::BuiltinFn::kConvert, Vector{sm_ty}, ld);
+                builtin->DetachResult(), msl::BuiltinFn::kConvert,
+                Vector<core::ir::TemplateParameter, 1>{sm_ty}, ld);
         });
         builtin->Destroy();
     }
diff --git a/src/tint/lang/msl/writer/raise/builtin_polyfill_test.cc b/src/tint/lang/msl/writer/raise/builtin_polyfill_test.cc
index f10752d..4ce567f 100644
--- a/src/tint/lang/msl/writer/raise/builtin_polyfill_test.cc
+++ b/src/tint/lang/msl/writer/raise/builtin_polyfill_test.cc
@@ -3555,8 +3555,9 @@
     auto* func = b.Function("foo", mat);
     func->SetParams({p});
     b.Append(func->Block(), [&] {
-        auto* call = b.CallExplicit(mat, core::BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, p, 64_u,
-                                    false, 32_u);
+        auto* call =
+            b.CallExplicit(mat, core::BuiltinFn::kSubgroupMatrixLoad,
+                           Vector<core::ir::TemplateParameter, 1>{mat}, p, 64_u, false, 32_u);
         b.Return(func, call);
     });
 
@@ -3597,8 +3598,9 @@
     auto* func = b.Function("foo", mat);
     func->SetParams({p});
     b.Append(func->Block(), [&] {
-        auto* call = b.CallExplicit(mat, core::BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, p, 64_u,
-                                    false, 32_u);
+        auto* call =
+            b.CallExplicit(mat, core::BuiltinFn::kSubgroupMatrixLoad,
+                           Vector<core::ir::TemplateParameter, 1>{mat}, p, 64_u, false, 32_u);
         b.Return(func, call);
     });
 
@@ -3717,7 +3719,7 @@
     func->SetParams({left, right});
     b.Append(func->Block(), [&] {
         auto* call = b.CallExplicit(result, core::BuiltinFn::kSubgroupMatrixMultiply,
-                                    Vector{ty.f32()}, left, right);
+                                    Vector<core::ir::TemplateParameter, 1>{ty.f32()}, left, right);
         b.Return(func, call);
     });
 
@@ -3757,7 +3759,7 @@
     func->SetParams({left, right});
     b.Append(func->Block(), [&] {
         auto* call = b.CallExplicit(result, core::BuiltinFn::kSubgroupMatrixMultiply,
-                                    Vector{ty.f16()}, left, right);
+                                    Vector<core::ir::TemplateParameter, 1>{ty.f16()}, left, right);
         b.Return(func, call);
     });
 
diff --git a/src/tint/lang/msl/writer/raise/decompose_buffer.cc b/src/tint/lang/msl/writer/raise/decompose_buffer.cc
index 516de0b..c234094 100644
--- a/src/tint/lang/msl/writer/raise/decompose_buffer.cc
+++ b/src/tint/lang/msl/writer/raise/decompose_buffer.cc
@@ -174,7 +174,9 @@
                             b.InsertBefore(call, [&] {
                                 auto* cast = b.CallExplicit<msl::ir::BuiltinCall>(
                                     param->Type(), msl::BuiltinFn::kPointerOffset,
-                                    Vector{param->Type()->UnwrapPtr()}, arg, 0_u);
+                                    Vector<core::ir::TemplateParameter, 1>{
+                                        param->Type()->UnwrapPtr()},
+                                    arg, 0_u);
                                 call->SetArg(i, cast->Result());
                             });
                         }
diff --git a/src/tint/lang/msl/writer/raise/decompose_buffer_test.cc b/src/tint/lang/msl/writer/raise/decompose_buffer_test.cc
index 0dc47cb..ad5878e 100644
--- a/src/tint/lang/msl/writer/raise/decompose_buffer_test.cc
+++ b/src/tint/lang/msl/writer/raise/decompose_buffer_test.cc
@@ -51,7 +51,7 @@
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
         auto* view = b.CallExplicit(ty.ptr(storage, ty.u32()), core::BuiltinFn::kBufferView,
-                                    Vector{ty.u32()}, gv, 0_u);
+                                    Vector<core::ir::TemplateParameter, 1>{ty.u32()}, gv, 0_u);
         b.Load(view);
         b.Return(func);
     });
@@ -101,9 +101,9 @@
     auto* size = b.FunctionParam("size", ty.i32());
     func->SetParams({offset, size});
     b.Append(func->Block(), [&] {
-        auto* view = b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())),
-                                    core::BuiltinFn::kBufferArrayView,
-                                    Vector{ty.runtime_array(ty.u32())}, gv, offset, size);
+        auto* view = b.CallExplicit(
+            ty.ptr(storage, ty.runtime_array(ty.u32())), core::BuiltinFn::kBufferArrayView,
+            Vector<core::ir::TemplateParameter, 1>{ty.runtime_array(ty.u32())}, gv, offset, size);
         b.Load(b.Access(ty.ptr(storage, ty.u32()), view, 4_u));
         b.Return(func);
     });
@@ -154,11 +154,11 @@
     auto* foo = b.Function("foo", ty.void_());
     b.Append(foo->Block(), [&] {
         auto* c1 = b.CallExplicit(ty.ptr(storage, ty.u32()), core::BuiltinFn::kBufferView,
-                                  Vector{ty.u32()}, gv, 0_u);
+                                  Vector<core::ir::TemplateParameter, 1>{ty.u32()}, gv, 0_u);
         b.Load(c1);
-        auto* c2 = b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())),
-                                  core::BuiltinFn::kBufferArrayView,
-                                  Vector{ty.runtime_array(ty.u32())}, gv, 16_u, 32_u);
+        auto* c2 = b.CallExplicit(
+            ty.ptr(storage, ty.runtime_array(ty.u32())), core::BuiltinFn::kBufferArrayView,
+            Vector<core::ir::TemplateParameter, 1>{ty.runtime_array(ty.u32())}, gv, 16_u, 32_u);
         b.Load(b.Access(ty.ptr(storage, ty.u32()), c2, 1_u));
         b.Return(foo);
     });
@@ -492,12 +492,12 @@
     auto* bar_p2 = b.FunctionParam("bar_p2", ty.ptr(workgroup, ty.buffer(256)));
     bar->SetParams({bar_p1, bar_p2});
     b.Append(bar->Block(), [&] {
-        auto* v1 =
-            b.CallExplicit(ty.ptr(storage, ty.array(ty.u32(), 64)), core::BuiltinFn::kBufferView,
-                           Vector{ty.array(ty.u32(), 64)}, bar_p1, 32_u);
-        auto* v2 = b.CallExplicit(ty.ptr(workgroup, ty.runtime_array(ty.u32())),
-                                  core::BuiltinFn::kBufferArrayView,
-                                  Vector{ty.runtime_array(ty.u32())}, bar_p2, 4_u, 12_u);
+        auto* v1 = b.CallExplicit(
+            ty.ptr(storage, ty.array(ty.u32(), 64)), core::BuiltinFn::kBufferView,
+            Vector<core::ir::TemplateParameter, 1>{ty.array(ty.u32(), 64)}, bar_p1, 32_u);
+        auto* v2 = b.CallExplicit(
+            ty.ptr(workgroup, ty.runtime_array(ty.u32())), core::BuiltinFn::kBufferArrayView,
+            Vector<core::ir::TemplateParameter, 1>{ty.runtime_array(ty.u32())}, bar_p2, 4_u, 12_u);
         b.Call(ty.void_(), baz, v1, v2);
         b.Return(bar);
     });
@@ -615,13 +615,13 @@
 
     auto* foo = b.Function("foo", ty.void_());
     b.Append(foo->Block(), [&] {
-        auto* v1 = b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())),
-                                  core::BuiltinFn::kBufferArrayView,
-                                  Vector{ty.runtime_array(ty.u32())}, gv1, 16_u, 64_u);
+        auto* v1 = b.CallExplicit(
+            ty.ptr(storage, ty.runtime_array(ty.u32())), core::BuiltinFn::kBufferArrayView,
+            Vector<core::ir::TemplateParameter, 1>{ty.runtime_array(ty.u32())}, gv1, 16_u, 64_u);
         b.Call(ty.void_(), bar, v1);
-        auto* v2 = b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())),
-                                  core::BuiltinFn::kBufferView, Vector{ty.runtime_array(ty.u32())},
-                                  gv2, 32_u);
+        auto* v2 = b.CallExplicit(
+            ty.ptr(storage, ty.runtime_array(ty.u32())), core::BuiltinFn::kBufferView,
+            Vector<core::ir::TemplateParameter, 1>{ty.runtime_array(ty.u32())}, gv2, 32_u);
         b.Call(ty.void_(), bar, v2);
         b.Call(ty.void_(), bar, gv3);
         b.Return(foo);
@@ -705,15 +705,15 @@
 
     auto* foo = b.Function("foo", ty.void_());
     b.Append(foo->Block(), [&] {
-        auto* v1 = b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())),
-                                  core::BuiltinFn::kBufferArrayView,
-                                  Vector{ty.runtime_array(ty.u32())}, gv1, 16_u, 64_u);
+        auto* v1 = b.CallExplicit(
+            ty.ptr(storage, ty.runtime_array(ty.u32())), core::BuiltinFn::kBufferArrayView,
+            Vector<core::ir::TemplateParameter, 1>{ty.runtime_array(ty.u32())}, gv1, 16_u, 64_u);
         auto* l1 = b.Let("l1", v1);
         b.Call(ty.void_(), bar, l1);
         auto* l2 = b.Let("l2", gv2);
-        auto* v2 = b.CallExplicit(ty.ptr(storage, ty.runtime_array(ty.u32())),
-                                  core::BuiltinFn::kBufferView, Vector{ty.runtime_array(ty.u32())},
-                                  l2, 32_u);
+        auto* v2 = b.CallExplicit(
+            ty.ptr(storage, ty.runtime_array(ty.u32())), core::BuiltinFn::kBufferView,
+            Vector<core::ir::TemplateParameter, 1>{ty.runtime_array(ty.u32())}, l2, 32_u);
         b.Call(ty.void_(), bar, v2);
         b.Call(ty.void_(), bar, gv3);
         b.Return(foo);
diff --git a/src/tint/lang/msl/writer/raise/fix_type_layout.cc b/src/tint/lang/msl/writer/raise/fix_type_layout.cc
index bad1bc3..21d4a33 100644
--- a/src/tint/lang/msl/writer/raise/fix_type_layout.cc
+++ b/src/tint/lang/msl/writer/raise/fix_type_layout.cc
@@ -147,7 +147,8 @@
                         auto* new_ptr =
                             ty.ptr(ptr->AddressSpace(), packed_store_type, ptr->Access());
                         core_call->Result()->SetType(new_ptr);
-                        core_call->SetExplicitTemplateParams(Vector{packed_store_type});
+                        core_call->SetExplicitTemplateParams(
+                            Vector<core::ir::TemplateParameter, 1>{packed_store_type});
                         core_call->Result()->ForEachUseSorted([&](core::ir::Usage use) {
                             UpdateUsage(use, ptr->StoreType(), packed_store_type);
                         });
@@ -170,7 +171,8 @@
                             ty.ptr(ptr->AddressSpace(), packed_store_type, ptr->Access());
                         msl_call->Result()->SetType(new_ptr);
                         if (!msl_call->ExplicitTemplateParams().IsEmpty()) {
-                            msl_call->SetExplicitTemplateParams(Vector{packed_store_type});
+                            msl_call->SetExplicitTemplateParams(
+                                Vector<core::ir::TemplateParameter, 1>{packed_store_type});
                         }
                         msl_call->Result()->ForEachUseSorted([&](core::ir::Usage use) {
                             UpdateUsage(use, ptr->StoreType(), packed_store_type);
diff --git a/src/tint/lang/msl/writer/raise/fix_type_layout_test.cc b/src/tint/lang/msl/writer/raise/fix_type_layout_test.cc
index a43e3e7..996e8de 100644
--- a/src/tint/lang/msl/writer/raise/fix_type_layout_test.cc
+++ b/src/tint/lang/msl/writer/raise/fix_type_layout_test.cc
@@ -4371,8 +4371,8 @@
 
     auto* foo = b.Function("foo", ty.void_());
     b.Append(foo->Block(), [&] {
-        auto* p =
-            b.CallExplicit(ty.ptr(storage, S), core::BuiltinFn::kBufferView, Vector{S}, v, 0_u);
+        auto* p = b.CallExplicit(ty.ptr(storage, S), core::BuiltinFn::kBufferView,
+                                 Vector<core::ir::TemplateParameter, 1>{S}, v, 0_u);
         b.Load(p);
         b.Return(foo);
     });
@@ -4449,9 +4449,9 @@
 
     auto* foo = b.Function("foo", ty.void_());
     b.Append(foo->Block(), [&] {
-        auto* p =
-            b.CallExplicit(ty.ptr(storage, ty.runtime_array(S)), core::BuiltinFn::kBufferArrayView,
-                           Vector{ty.runtime_array(S)}, v, 0_u, 128_u);
+        auto* p = b.CallExplicit(
+            ty.ptr(storage, ty.runtime_array(S)), core::BuiltinFn::kBufferArrayView,
+            Vector<core::ir::TemplateParameter, 1>{ty.runtime_array(S)}, v, 0_u, 128_u);
         auto* a = b.Access(ty.ptr(storage, S), p, 0_u);
         b.Load(a);
         b.Return(foo);
@@ -4533,8 +4533,9 @@
 
     auto* foo = b.Function("foo", ty.void_());
     b.Append(foo->Block(), [&] {
-        auto* p = b.CallExplicit<ir::BuiltinCall>(ty.ptr(storage, S), BuiltinFn::kPointerOffset,
-                                                  Vector{S}, v, 0_u);
+        auto* p =
+            b.CallExplicit<ir::BuiltinCall>(ty.ptr(storage, S), BuiltinFn::kPointerOffset,
+                                            Vector<core::ir::TemplateParameter, 1>{S}, v, 0_u);
         b.Load(p);
         b.Return(foo);
     });
diff --git a/src/tint/lang/msl/writer/writer_test.cc b/src/tint/lang/msl/writer/writer_test.cc
index d3c3831..a64c196 100644
--- a/src/tint/lang/msl/writer/writer_test.cc
+++ b/src/tint/lang/msl/writer/writer_test.cc
@@ -580,7 +580,7 @@
     b.Append(entry->Block(), [&] {
         auto* call =
             b.CallExplicit(ty.ptr(workgroup, ty.vec4(ty.f32())), core::BuiltinFn::kBufferView,
-                           Vector{ty.vec4(ty.f32())}, v, 0_u);
+                           Vector<core::ir::TemplateParameter, 1>{ty.vec4(ty.f32())}, v, 0_u);
         b.StoreVectorElement(call, 0_u, 0_f);
         b.Return(entry);
     });
@@ -651,8 +651,8 @@
 
     auto* foo = b.Function("foo", ty.void_());
     b.Append(foo->Block(), [&] {
-        auto* view =
-            b.CallExplicit(ty.ptr(workgroup, S), core::BuiltinFn::kBufferView, Vector{S}, var, 0_u);
+        auto* view = b.CallExplicit(ty.ptr(workgroup, S), core::BuiltinFn::kBufferView,
+                                    Vector<core::ir::TemplateParameter, 1>{S}, var, 0_u);
         b.Let("p", view);
         b.Return(foo);
     });
diff --git a/src/tint/lang/spirv/BUILD.bazel b/src/tint/lang/spirv/BUILD.bazel
index d17fc32..72b26f5 100644
--- a/src/tint/lang/spirv/BUILD.bazel
+++ b/src/tint/lang/spirv/BUILD.bazel
@@ -50,14 +50,21 @@
     "//src/tint:gen/src/tint/lang/spirv/builtin_fn.h",
   ],
   deps = [
+    "//src/tint/lang/core",
+    "//src/tint/lang/core/constant",
+    "//src/tint/lang/core/intrinsic",
     "//src/tint/lang/core/ir",
     "//src/tint/lang/core/type",
+    "//src/tint/utils",
     "//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/rtti",
+    "//src/tint/utils/text",
     "//src/tint:generated_tint_headers",
     "//src/utils",
   ],
diff --git a/src/tint/lang/spirv/BUILD.cmake b/src/tint/lang/spirv/BUILD.cmake
index ad7c732..413f427 100644
--- a/src/tint/lang/spirv/BUILD.cmake
+++ b/src/tint/lang/spirv/BUILD.cmake
@@ -51,14 +51,21 @@
 )
 
 tint_target_add_dependencies(tint_lang_spirv lib
+  tint_lang_core
+  tint_lang_core_constant
+  tint_lang_core_intrinsic
   tint_lang_core_ir
   tint_lang_core_type
+  tint_utils
   tint_utils_containers
+  tint_utils_diagnostic
   tint_utils_ice
   tint_utils_macros
   tint_utils_math
   tint_utils_memory
+  tint_utils_reflection
   tint_utils_rtti
+  tint_utils_text
 )
 
 tint_target_add_external_dependencies(tint_lang_spirv lib
diff --git a/src/tint/lang/spirv/BUILD.gn b/src/tint/lang/spirv/BUILD.gn
index 1ac3d78..05516d4 100644
--- a/src/tint/lang/spirv/BUILD.gn
+++ b/src/tint/lang/spirv/BUILD.gn
@@ -47,13 +47,20 @@
   deps = [
     "${dawn_root}/src/utils",
     "${tint_src_dir}:generate_sources",
+    "${tint_src_dir}/lang/core",
+    "${tint_src_dir}/lang/core/constant",
+    "${tint_src_dir}/lang/core/intrinsic",
     "${tint_src_dir}/lang/core/ir",
     "${tint_src_dir}/lang/core/type",
+    "${tint_src_dir}/utils",
     "${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/rtti",
+    "${tint_src_dir}/utils/text",
   ]
 }
diff --git a/src/tint/lang/spirv/ir/builtin_call_test.cc b/src/tint/lang/spirv/ir/builtin_call_test.cc
index b194382..59ae27a 100644
--- a/src/tint/lang/spirv/ir/builtin_call_test.cc
+++ b/src/tint/lang/spirv/ir/builtin_call_test.cc
@@ -62,7 +62,7 @@
 TEST_F(IR_SpirvBuiltinCallTest, CloneWithExplicitParams) {
     auto* builtin = b.Call<BuiltinCall>(mod.Types().f32(), BuiltinFn::kArrayLength, 1_u, 2_u);
     builtin->SetExplicitTemplateParams(
-        Vector<const core::type::Type*, 2>{mod.Types().f32(), mod.Types().i32()});
+        Vector<core::ir::TemplateParameter, 2>{mod.Types().f32(), mod.Types().i32()});
 
     auto* new_b = clone_ctx.Clone(builtin);
 
@@ -84,8 +84,8 @@
     auto new_explicit = new_b->ExplicitTemplateParams();
     ASSERT_EQ(2u, new_explicit.Length());
 
-    EXPECT_EQ(mod.Types().f32(), new_explicit[0]);
-    EXPECT_EQ(mod.Types().i32(), new_explicit[1]);
+    EXPECT_EQ(mod.Types().f32(), std::get<const core::type::Type*>(new_explicit[0]));
+    EXPECT_EQ(mod.Types().i32(), std::get<const core::type::Type*>(new_explicit[1]));
 }
 
 TEST_F(IR_SpirvBuiltinCallTest, CloneNoArgs) {
diff --git a/src/tint/lang/spirv/reader/lower/builtins_test.cc b/src/tint/lang/spirv/reader/lower/builtins_test.cc
index ca2dd7f..2c90802 100644
--- a/src/tint/lang/spirv/reader/lower/builtins_test.cc
+++ b/src/tint/lang/spirv/reader/lower/builtins_test.cc
@@ -744,7 +744,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kSign,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Constant(10_u));
         b.Return(ep);
     });
@@ -777,7 +777,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kSign,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Constant(10_i));
         b.Return(ep);
     });
@@ -810,7 +810,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kSign,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Constant(10_u));
         b.Return(ep);
     });
@@ -844,7 +844,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kSign,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Constant(10_i));
         b.Return(ep);
     });
@@ -876,7 +876,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kSign,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat(ty.vec2u(), (10_u)));
         b.Return(ep);
     });
@@ -909,7 +909,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kSign,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -942,7 +942,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kSign,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat(ty.vec2u(), 10_u));
         b.Return(ep);
     });
@@ -976,7 +976,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kSign,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -1022,10 +1022,10 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.u32()}, 10_u);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 10_u);
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat(ty.vec2u(), 10_u));
         b.Return(ep);
     });
@@ -1069,10 +1069,10 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.i32()}, 10_u);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 10_u);
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat(ty.vec2u(), 10_u));
         b.Return(ep);
     });
@@ -1114,10 +1114,10 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.i32()}, 10_i);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 10_i);
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -1157,10 +1157,10 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.u32()}, 10_i);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 10_i);
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -1211,10 +1211,10 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.u32()}, 10_u);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 10_u);
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat(ty.vec2u(), 10_u));
         b.Return(ep);
     });
@@ -1254,10 +1254,10 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.i32()}, 10_u);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 10_u);
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat(ty.vec2u(), 10_u));
         b.Return(ep);
     });
@@ -1299,10 +1299,10 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.i32()}, 10_i);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 10_i);
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -1346,10 +1346,10 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.u32()}, 10_i);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 10_i);
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -1400,9 +1400,9 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.u32(), params.fn, Vector<const core::type::Type*, 1>{ty.u32()}, 10_u, 15_u);
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 10_u, 15_u);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2u(), params.fn, Vector<const core::type::Type*, 1>{ty.u32()},
+            ty.vec2u(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()},
             b.Splat(ty.vec2u(), 10_u), b.Splat(ty.vec2u(), 15_u));
         b.Return(ep);
     });
@@ -1449,9 +1449,9 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.i32(), params.fn, Vector<const core::type::Type*, 1>{ty.i32()}, 10_i, 15_i);
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 10_i, 15_i);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2i(), params.fn, Vector<const core::type::Type*, 1>{ty.i32()},
+            ty.vec2i(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()},
             b.Splat(ty.vec2i(), 10_i), b.Splat(ty.vec2i(), 15_i));
         b.Return(ep);
     });
@@ -1492,9 +1492,9 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.u32(), params.fn, Vector<const core::type::Type*, 1>{ty.u32()}, 10_i, 10_u);
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 10_i, 10_u);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2u(), params.fn, Vector<const core::type::Type*, 1>{ty.u32()},
+            ty.vec2u(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()},
             b.Splat(ty.vec2i(), 10_i), b.Splat(ty.vec2u(), 10_u));
         b.Return(ep);
     });
@@ -1539,9 +1539,9 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.i32(), params.fn, Vector<const core::type::Type*, 1>{ty.i32()}, 10_u, 10_i);
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 10_u, 10_i);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2i(), params.fn, Vector<const core::type::Type*, 1>{ty.i32()},
+            ty.vec2i(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()},
             b.Splat(ty.vec2u(), 10_u), b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -1593,9 +1593,9 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.u32(), params.fn, Vector<const core::type::Type*, 1>{ty.u32()}, 10_u, 15_u);
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 10_u, 15_u);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2u(), params.fn, Vector<const core::type::Type*, 1>{ty.u32()},
+            ty.vec2u(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()},
             b.Splat(ty.vec2u(), 10_u), b.Splat(ty.vec2u(), 15_u));
         b.Return(ep);
     });
@@ -1636,9 +1636,9 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.i32(), params.fn, Vector<const core::type::Type*, 1>{ty.i32()}, 10_i, 15_i);
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 10_i, 15_i);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2i(), params.fn, Vector<const core::type::Type*, 1>{ty.i32()},
+            ty.vec2i(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()},
             b.Splat(ty.vec2i(), 10_i), b.Splat(ty.vec2i(), 15_i));
         b.Return(ep);
     });
@@ -1685,9 +1685,9 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.u32(), params.fn, Vector<const core::type::Type*, 1>{ty.u32()}, 10_i, 10_u);
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 10_i, 10_u);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2u(), params.fn, Vector<const core::type::Type*, 1>{ty.u32()},
+            ty.vec2u(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()},
             b.Splat(ty.vec2i(), 10_i), b.Splat(ty.vec2u(), 10_u));
         b.Return(ep);
     });
@@ -1730,9 +1730,9 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.i32(), params.fn, Vector<const core::type::Type*, 1>{ty.i32()}, 10_u, 10_i);
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 10_u, 10_i);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2i(), params.fn, Vector<const core::type::Type*, 1>{ty.i32()},
+            ty.vec2i(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()},
             b.Splat(ty.vec2u(), 10_u), b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -1781,10 +1781,10 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kSClamp,
-                                               Vector<const core::type::Type*, 1>{ty.u32()}, 10_u,
-                                               15_u, 10_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               10_u, 15_u, 10_u);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2u(), spirv::BuiltinFn::kSClamp, Vector<const core::type::Type*, 1>{ty.u32()},
+            ty.vec2u(), spirv::BuiltinFn::kSClamp, Vector<core::ir::TemplateParameter, 1>{ty.u32()},
             b.Splat(ty.vec2u(), 10_u), b.Splat(ty.vec2u(), 15_u), b.Splat(ty.vec2u(), 10_u));
         b.Return(ep);
     });
@@ -1827,10 +1827,10 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kSClamp,
-                                               Vector<const core::type::Type*, 1>{ty.i32()}, 10_i,
-                                               15_i, 10_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               10_i, 15_i, 10_i);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2i(), spirv::BuiltinFn::kSClamp, Vector<const core::type::Type*, 1>{ty.i32()},
+            ty.vec2i(), spirv::BuiltinFn::kSClamp, Vector<core::ir::TemplateParameter, 1>{ty.i32()},
             b.Splat(ty.vec2i(), 10_i), b.Splat(ty.vec2i(), 15_i), b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -1865,10 +1865,10 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kSClamp,
-                                               Vector<const core::type::Type*, 1>{ty.u32()}, 10_i,
-                                               10_u, 10_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               10_i, 10_u, 10_i);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2u(), spirv::BuiltinFn::kSClamp, Vector<const core::type::Type*, 1>{ty.u32()},
+            ty.vec2u(), spirv::BuiltinFn::kSClamp, Vector<core::ir::TemplateParameter, 1>{ty.u32()},
             b.Splat(ty.vec2i(), 10_i), b.Splat(ty.vec2u(), 10_u), b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -1907,10 +1907,10 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kSClamp,
-                                               Vector<const core::type::Type*, 1>{ty.i32()}, 10_u,
-                                               10_i, 10_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               10_u, 10_i, 10_u);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2i(), spirv::BuiltinFn::kSClamp, Vector<const core::type::Type*, 1>{ty.i32()},
+            ty.vec2i(), spirv::BuiltinFn::kSClamp, Vector<core::ir::TemplateParameter, 1>{ty.i32()},
             b.Splat(ty.vec2u(), 10_u), b.Splat(ty.vec2i(), 10_i), b.Splat(ty.vec2u(), 10_u));
         b.Return(ep);
     });
@@ -1949,10 +1949,10 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kUClamp,
-                                               Vector<const core::type::Type*, 1>{ty.u32()}, 10_u,
-                                               15_u, 10_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               10_u, 15_u, 10_u);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2u(), spirv::BuiltinFn::kUClamp, Vector<const core::type::Type*, 1>{ty.u32()},
+            ty.vec2u(), spirv::BuiltinFn::kUClamp, Vector<core::ir::TemplateParameter, 1>{ty.u32()},
             b.Splat(ty.vec2u(), 10_u), b.Splat(ty.vec2u(), 15_u), b.Splat(ty.vec2u(), 10_u));
         b.Return(ep);
     });
@@ -1987,10 +1987,10 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kUClamp,
-                                               Vector<const core::type::Type*, 1>{ty.i32()}, 10_i,
-                                               15_i, 10_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               10_i, 15_i, 10_i);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2i(), spirv::BuiltinFn::kUClamp, Vector<const core::type::Type*, 1>{ty.i32()},
+            ty.vec2i(), spirv::BuiltinFn::kUClamp, Vector<core::ir::TemplateParameter, 1>{ty.i32()},
             b.Splat(ty.vec2i(), 10_i), b.Splat(ty.vec2i(), 15_i), b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -2033,10 +2033,10 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kUClamp,
-                                               Vector<const core::type::Type*, 1>{ty.u32()}, 10_i,
-                                               10_u, 10_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               10_i, 10_u, 10_i);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2u(), spirv::BuiltinFn::kUClamp, Vector<const core::type::Type*, 1>{ty.u32()},
+            ty.vec2u(), spirv::BuiltinFn::kUClamp, Vector<core::ir::TemplateParameter, 1>{ty.u32()},
             b.Splat(ty.vec2i(), 10_i), b.Splat(ty.vec2u(), 10_u), b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -2075,10 +2075,10 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kUClamp,
-                                               Vector<const core::type::Type*, 1>{ty.i32()}, 10_u,
-                                               10_i, 10_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               10_u, 10_i, 10_u);
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec2i(), spirv::BuiltinFn::kUClamp, Vector<const core::type::Type*, 1>{ty.i32()},
+            ty.vec2i(), spirv::BuiltinFn::kUClamp, Vector<core::ir::TemplateParameter, 1>{ty.i32()},
             b.Splat(ty.vec2u(), 10_u), b.Splat(ty.vec2i(), 10_i), b.Splat(ty.vec2u(), 10_u));
         b.Return(ep);
     });
@@ -2117,9 +2117,10 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kFindILsb,
-                                               Vector<const core::type::Type*, 1>{ty.i32()}, 10_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               10_i);
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kFindILsb,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -2154,9 +2155,10 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kFindILsb,
-                                               Vector<const core::type::Type*, 1>{ty.u32()}, 10_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               10_u);
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kFindILsb,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat(ty.vec2u(), 10_u));
         b.Return(ep);
     });
@@ -2191,9 +2193,10 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kFindILsb,
-                                               Vector<const core::type::Type*, 1>{ty.u32()}, 10_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               10_i);
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kFindILsb,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -2230,9 +2233,10 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kFindILsb,
-                                               Vector<const core::type::Type*, 1>{ty.i32()}, 10_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               10_u);
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kFindILsb,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat(ty.vec2u(), 10_u));
         b.Return(ep);
     });
@@ -2885,7 +2889,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kBitCount,
-                                               Vector<const core::type::Type*, 1>{ty.u32()}, 10_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               10_u);
         b.Return(ep);
     });
 
@@ -2917,7 +2922,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kBitCount,
-                                               Vector<const core::type::Type*, 1>{ty.i32()}, 10_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               10_u);
         b.Return(ep);
     });
 
@@ -2950,7 +2956,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kBitCount,
-                                               Vector<const core::type::Type*, 1>{ty.u32()}, 10_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               10_i);
         b.Return(ep);
     });
 
@@ -2983,7 +2990,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kBitCount,
-                                               Vector<const core::type::Type*, 1>{ty.i32()}, 10_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               10_i);
         b.Return(ep);
     });
 
@@ -3015,7 +3023,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kBitCount,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat(ty.vec2u(), 10_u));
         b.Return(ep);
     });
@@ -3048,7 +3056,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kBitCount,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat(ty.vec2u(), 10_u));
         b.Return(ep);
     });
@@ -3082,7 +3090,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kBitCount,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -3116,7 +3124,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kBitCount,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat(ty.vec2i(), 10_i));
         b.Return(ep);
     });
@@ -4139,7 +4147,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.i32(), params.fn, Vector<const core::type::Type*, 1>{ty.i32()}, 50_i, 10_u);
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 50_i, 10_u);
         b.Return(ep);
     });
 
@@ -4176,7 +4184,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.i32(), params.fn, Vector<const core::type::Type*, 1>{ty.i32()}, 10_u, 50_i);
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 10_u, 50_i);
         b.Return(ep);
     });
 
@@ -4214,7 +4222,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.i32(), params.fn, Vector<const core::type::Type*, 1>{ty.i32()}, 10_u, 20_u);
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 10_u, 20_u);
         b.Return(ep);
     });
 
@@ -4251,7 +4259,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.u32(), params.fn, Vector<const core::type::Type*, 1>{ty.u32()}, 50_i, 10_u);
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 50_i, 10_u);
         b.Return(ep);
     });
 
@@ -4289,7 +4297,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.u32(), params.fn, Vector<const core::type::Type*, 1>{ty.u32()}, 10_u, 50_i);
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 10_u, 50_i);
         b.Return(ep);
     });
 
@@ -4326,7 +4334,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.u32(), params.fn, Vector<const core::type::Type*, 1>{ty.u32()}, 50_i, 60_i);
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 50_i, 60_i);
         b.Return(ep);
     });
 
@@ -4363,7 +4371,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat<vec2<i32>>(50_i), b.Splat<vec2<u32>>(10_u));
         b.Return(ep);
     });
@@ -4402,7 +4410,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat<vec2<u32>>(10_u), b.Splat<vec2<i32>>(50_i));
         b.Return(ep);
     });
@@ -4442,7 +4450,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat<vec2<u32>>(10_u), b.Splat<vec2<u32>>(20_u));
         b.Return(ep);
     });
@@ -4481,7 +4489,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat<vec2<i32>>(50_i), b.Splat<vec2<u32>>(10_u));
         b.Return(ep);
     });
@@ -4521,7 +4529,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat<vec2<u32>>(10_u), b.Splat<vec2<i32>>(50_i));
         b.Return(ep);
     });
@@ -4560,7 +4568,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat<vec2<i32>>(50_i), b.Splat<vec2<i32>>(60_i));
         b.Return(ep);
     });
@@ -4614,7 +4622,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.i32(), params.fn, Vector<const core::type::Type*, 1>{ty.i32()}, 50_i, 10_u);
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 50_i, 10_u);
         b.Return(ep);
     });
 
@@ -4651,7 +4659,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.i32(), params.fn, Vector<const core::type::Type*, 1>{ty.i32()}, 10_u, 50_i);
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 10_u, 50_i);
         b.Return(ep);
     });
 
@@ -4688,7 +4696,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.i32(), params.fn, Vector<const core::type::Type*, 1>{ty.i32()}, 10_u, 20_u);
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 10_u, 20_u);
         b.Return(ep);
     });
 
@@ -4726,7 +4734,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.u32(), params.fn, Vector<const core::type::Type*, 1>{ty.u32()}, 50_i, 10_u);
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 50_i, 10_u);
         b.Return(ep);
     });
 
@@ -4764,7 +4772,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.u32(), params.fn, Vector<const core::type::Type*, 1>{ty.u32()}, 10_u, 50_i);
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 10_u, 50_i);
         b.Return(ep);
     });
 
@@ -4802,7 +4810,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.u32(), params.fn, Vector<const core::type::Type*, 1>{ty.u32()}, 50_i, 60_i);
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 50_i, 60_i);
         b.Return(ep);
     });
 
@@ -4839,7 +4847,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat<vec2<i32>>(50_i), b.Splat<vec2<u32>>(10_u));
         b.Return(ep);
     });
@@ -4878,7 +4886,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat<vec2<u32>>(10_u), b.Splat<vec2<i32>>(50_i));
         b.Return(ep);
     });
@@ -4917,7 +4925,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.i32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat<vec2<u32>>(10_u), b.Splat<vec2<u32>>(20_u));
         b.Return(ep);
     });
@@ -4957,7 +4965,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat<vec2<i32>>(50_i), b.Splat<vec2<u32>>(10_u));
         b.Return(ep);
     });
@@ -4997,7 +5005,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat<vec2<u32>>(10_u), b.Splat<vec2<i32>>(50_i));
         b.Return(ep);
     });
@@ -5037,7 +5045,7 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn,
-                                               Vector<const core::type::Type*, 1>{ty.u32()},
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat<vec2<i32>>(50_i), b.Splat<vec2<i32>>(60_i));
         b.Return(ep);
     });
@@ -5080,7 +5088,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kConvertFToS,
-                                               Vector{ty.i32()}, 10_f);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               10_f);
         b.Return(ep);
     });
 
@@ -5111,7 +5120,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kConvertFToS,
-                                               Vector{ty.u32()}, 10_f);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               10_f);
         b.Return(ep);
     });
 
@@ -5143,7 +5153,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kConvertFToS,
-                                               Vector{ty.i32()}, b.Splat<vec2<f32>>(10_f));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               b.Splat<vec2<f32>>(10_f));
         b.Return(ep);
     });
 
@@ -5174,7 +5185,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kConvertFToS,
-                                               Vector{ty.u32()}, b.Splat<vec2<f32>>(10_f));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               b.Splat<vec2<f32>>(10_f));
         b.Return(ep);
     });
 
@@ -5206,7 +5218,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.f32(), spirv::BuiltinFn::kConvertSToF,
-                                               Vector{ty.f32()}, 10_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.f32()},
+                                               10_i);
         b.Return(ep);
     });
 
@@ -5237,7 +5250,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.f32(), spirv::BuiltinFn::kConvertSToF,
-                                               Vector{ty.f32()}, 10_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.f32()},
+                                               10_u);
         b.Return(ep);
     });
 
@@ -5269,7 +5283,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2f(), spirv::BuiltinFn::kConvertSToF,
-                                               Vector{ty.f32()}, b.Splat<vec2<i32>>(10_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.f32()},
+                                               b.Splat<vec2<i32>>(10_i));
         b.Return(ep);
     });
 
@@ -5300,7 +5315,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2f(), spirv::BuiltinFn::kConvertSToF,
-                                               Vector{ty.f32()}, b.Splat<vec2<u32>>(10_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.f32()},
+                                               b.Splat<vec2<u32>>(10_u));
         b.Return(ep);
     });
 
@@ -5332,7 +5348,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.f32(), spirv::BuiltinFn::kConvertUToF,
-                                               Vector{ty.f32()}, 10_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.f32()},
+                                               10_i);
         b.Return(ep);
     });
 
@@ -5364,7 +5381,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.f32(), spirv::BuiltinFn::kConvertUToF,
-                                               Vector{ty.f32()}, 10_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.f32()},
+                                               10_u);
         b.Return(ep);
     });
 
@@ -5395,7 +5413,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2f(), spirv::BuiltinFn::kConvertUToF,
-                                               Vector{ty.f32()}, b.Splat<vec2<i32>>(10_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.f32()},
+                                               b.Splat<vec2<i32>>(10_i));
         b.Return(ep);
     });
 
@@ -5427,7 +5446,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2f(), spirv::BuiltinFn::kConvertUToF,
-                                               Vector{ty.f32()}, b.Splat<vec2<u32>>(10_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.f32()},
+                                               b.Splat<vec2<u32>>(10_u));
         b.Return(ep);
     });
 
@@ -5460,7 +5480,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), params.fn, Vector{ty.i32()}, 1_i, 2_i);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 1_i, 2_i);
         b.Return(ep);
     });
 
@@ -5493,7 +5514,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), params.fn, Vector{ty.i32()}, 1_i, 8_u);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 1_i, 8_u);
         b.Return(ep);
     });
 
@@ -5527,7 +5549,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), params.fn, Vector{ty.i32()}, 8_u, 1_i);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 8_u, 1_i);
         b.Return(ep);
     });
 
@@ -5562,7 +5585,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), params.fn, Vector{ty.i32()}, 8_u, 9_u);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.i32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.i32()}, 8_u, 9_u);
         b.Return(ep);
     });
 
@@ -5596,7 +5620,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), params.fn, Vector{ty.u32()}, 8_u, 9_u);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 8_u, 9_u);
         b.Return(ep);
     });
 
@@ -5629,7 +5654,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), params.fn, Vector{ty.u32()}, 8_u, 1_i);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 8_u, 1_i);
         b.Return(ep);
     });
 
@@ -5663,7 +5689,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), params.fn, Vector{ty.u32()}, 1_i, 8_u);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 1_i, 8_u);
         b.Return(ep);
     });
 
@@ -5698,7 +5725,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), params.fn, Vector{ty.u32()}, 1_i, 2_i);
+        b.CallExplicit<spirv::ir::BuiltinCall>(
+            ty.u32(), params.fn, Vector<core::ir::TemplateParameter, 1>{ty.u32()}, 1_i, 2_i);
         b.Return(ep);
     });
 
@@ -5732,7 +5760,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn, Vector{ty.i32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat<vec2<i32>>(1_i), b.Splat<vec2<i32>>(2_i));
         b.Return(ep);
     });
@@ -5766,7 +5795,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn, Vector{ty.i32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat<vec2<i32>>(1_i), b.Splat<vec2<u32>>(8_u));
         b.Return(ep);
     });
@@ -5801,7 +5831,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn, Vector{ty.i32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat<vec2<u32>>(8_u), b.Splat<vec2<i32>>(1_i));
         b.Return(ep);
     });
@@ -5837,7 +5868,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn, Vector{ty.i32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), params.fn,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat<vec2<u32>>(8_u), b.Splat<vec2<u32>>(9_u));
         b.Return(ep);
     });
@@ -5872,7 +5904,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn, Vector{ty.u32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat<vec2<u32>>(8_u), b.Splat<vec2<u32>>(9_u));
         b.Return(ep);
     });
@@ -5906,7 +5939,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn, Vector{ty.u32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat<vec2<u32>>(8_u), b.Splat<vec2<i32>>(1_i));
         b.Return(ep);
     });
@@ -5941,7 +5975,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn, Vector{ty.u32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat<vec2<i32>>(1_i), b.Splat<vec2<u32>>(8_u));
         b.Return(ep);
     });
@@ -5977,7 +6012,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn, Vector{ty.u32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), params.fn,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat<vec2<i32>>(1_i), b.Splat<vec2<i32>>(2_i));
         b.Return(ep);
     });
@@ -6868,7 +6904,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.u32()}, 8_u, 9_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               8_u, 9_u);
         b.Return(ep);
     });
 
@@ -6900,7 +6937,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.u32()}, 8_u, 1_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               8_u, 1_i);
         b.Return(ep);
     });
 
@@ -6933,7 +6971,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.u32()}, 1_i, 9_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               1_i, 9_u);
         b.Return(ep);
     });
 
@@ -6966,7 +7005,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.u32()}, 1_i, 2_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               1_i, 2_i);
         b.Return(ep);
     });
 
@@ -7000,7 +7040,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.i32()}, 8_u, 9_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               8_u, 9_u);
         b.Return(ep);
     });
 
@@ -7033,7 +7074,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.i32()}, 8_u, 1_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               8_u, 1_i);
         b.Return(ep);
     });
 
@@ -7067,7 +7109,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.i32()}, 1_i, 9_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               1_i, 9_u);
         b.Return(ep);
     });
 
@@ -7099,7 +7142,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.i32()}, 1_i, 2_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               1_i, 2_i);
         b.Return(ep);
     });
 
@@ -7132,8 +7176,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.u32()}, b.Splat<vec2<u32>>(8_u),
-                                               b.Splat<vec2<u32>>(9_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               b.Splat<vec2<u32>>(8_u), b.Splat<vec2<u32>>(9_u));
         b.Return(ep);
     });
 
@@ -7165,8 +7209,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.u32()}, b.Splat<vec2<u32>>(8_u),
-                                               b.Splat<vec2<i32>>(1_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               b.Splat<vec2<u32>>(8_u), b.Splat<vec2<i32>>(1_i));
         b.Return(ep);
     });
 
@@ -7199,8 +7243,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.u32()}, b.Splat<vec2<i32>>(1_i),
-                                               b.Splat<vec2<u32>>(9_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               b.Splat<vec2<i32>>(1_i), b.Splat<vec2<u32>>(9_u));
         b.Return(ep);
     });
 
@@ -7233,8 +7277,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.u32()}, b.Splat<vec2<i32>>(1_i),
-                                               b.Splat<vec2<i32>>(2_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               b.Splat<vec2<i32>>(1_i), b.Splat<vec2<i32>>(2_i));
         b.Return(ep);
     });
 
@@ -7268,8 +7312,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.i32()}, b.Splat<vec2<u32>>(8_u),
-                                               b.Splat<vec2<u32>>(9_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               b.Splat<vec2<u32>>(8_u), b.Splat<vec2<u32>>(9_u));
         b.Return(ep);
     });
 
@@ -7302,8 +7346,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.i32()}, b.Splat<vec2<u32>>(8_u),
-                                               b.Splat<vec2<i32>>(1_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               b.Splat<vec2<u32>>(8_u), b.Splat<vec2<i32>>(1_i));
         b.Return(ep);
     });
 
@@ -7337,8 +7381,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.i32()}, b.Splat<vec2<i32>>(1_i),
-                                               b.Splat<vec2<u32>>(9_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               b.Splat<vec2<i32>>(1_i), b.Splat<vec2<u32>>(9_u));
         b.Return(ep);
     });
 
@@ -7370,8 +7414,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kShiftLeftLogical,
-                                               Vector{ty.i32()}, b.Splat<vec2<i32>>(1_i),
-                                               b.Splat<vec2<i32>>(2_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               b.Splat<vec2<i32>>(1_i), b.Splat<vec2<i32>>(2_i));
         b.Return(ep);
     });
 
@@ -7404,7 +7448,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.u32()}, 8_u, 9_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               8_u, 9_u);
         b.Return(ep);
     });
 
@@ -7436,7 +7481,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.u32()}, 8_u, 1_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               8_u, 1_i);
         b.Return(ep);
     });
 
@@ -7469,7 +7515,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.u32()}, 1_i, 9_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               1_i, 9_u);
         b.Return(ep);
     });
 
@@ -7502,7 +7549,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.u32()}, 1_i, 2_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               1_i, 2_i);
         b.Return(ep);
     });
 
@@ -7536,7 +7584,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.i32()}, 8_u, 9_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               8_u, 9_u);
         b.Return(ep);
     });
 
@@ -7569,7 +7618,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.i32()}, 8_u, 1_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               8_u, 1_i);
         b.Return(ep);
     });
 
@@ -7603,7 +7653,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.i32()}, 1_i, 9_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               1_i, 9_u);
         b.Return(ep);
     });
 
@@ -7637,7 +7688,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.i32()}, 1_i, 2_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               1_i, 2_i);
         b.Return(ep);
     });
 
@@ -7672,8 +7724,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.u32()}, b.Splat<vec2<u32>>(8_u),
-                                               b.Splat<vec2<u32>>(9_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               b.Splat<vec2<u32>>(8_u), b.Splat<vec2<u32>>(9_u));
         b.Return(ep);
     });
 
@@ -7705,8 +7757,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.u32()}, b.Splat<vec2<u32>>(8_u),
-                                               b.Splat<vec2<i32>>(1_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               b.Splat<vec2<u32>>(8_u), b.Splat<vec2<i32>>(1_i));
         b.Return(ep);
     });
 
@@ -7739,8 +7791,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.u32()}, b.Splat<vec2<i32>>(1_i),
-                                               b.Splat<vec2<u32>>(9_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               b.Splat<vec2<i32>>(1_i), b.Splat<vec2<u32>>(9_u));
         b.Return(ep);
     });
 
@@ -7773,8 +7825,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.u32()}, b.Splat<vec2<i32>>(1_i),
-                                               b.Splat<vec2<i32>>(2_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               b.Splat<vec2<i32>>(1_i), b.Splat<vec2<i32>>(2_i));
         b.Return(ep);
     });
 
@@ -7808,8 +7860,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.i32()}, b.Splat<vec2<u32>>(8_u),
-                                               b.Splat<vec2<u32>>(9_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               b.Splat<vec2<u32>>(8_u), b.Splat<vec2<u32>>(9_u));
         b.Return(ep);
     });
 
@@ -7842,8 +7894,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.i32()}, b.Splat<vec2<u32>>(8_u),
-                                               b.Splat<vec2<i32>>(1_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               b.Splat<vec2<u32>>(8_u), b.Splat<vec2<i32>>(1_i));
         b.Return(ep);
     });
 
@@ -7877,8 +7929,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.i32()}, b.Splat<vec2<i32>>(1_i),
-                                               b.Splat<vec2<u32>>(9_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               b.Splat<vec2<i32>>(1_i), b.Splat<vec2<u32>>(9_u));
         b.Return(ep);
     });
 
@@ -7912,8 +7964,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kShiftRightLogical,
-                                               Vector{ty.i32()}, b.Splat<vec2<i32>>(1_i),
-                                               b.Splat<vec2<i32>>(2_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               b.Splat<vec2<i32>>(1_i), b.Splat<vec2<i32>>(2_i));
         b.Return(ep);
     });
 
@@ -7948,7 +8000,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.u32()}, 8_u, 9_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               8_u, 9_u);
         b.Return(ep);
     });
 
@@ -7982,7 +8035,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.u32()}, 8_u, 1_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               8_u, 1_i);
         b.Return(ep);
     });
 
@@ -8017,7 +8071,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.u32()}, 1_i, 9_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               1_i, 9_u);
         b.Return(ep);
     });
 
@@ -8050,7 +8105,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.u32()}, 1_i, 2_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               1_i, 2_i);
         b.Return(ep);
     });
 
@@ -8084,7 +8140,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.i32()}, 8_u, 9_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               8_u, 9_u);
         b.Return(ep);
     });
 
@@ -8117,7 +8174,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.i32()}, 8_u, 1_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               8_u, 1_i);
         b.Return(ep);
     });
 
@@ -8151,7 +8209,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.i32()}, 1_i, 9_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               1_i, 9_u);
         b.Return(ep);
     });
 
@@ -8183,7 +8242,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.i32()}, 1_i, 2_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               1_i, 2_i);
         b.Return(ep);
     });
 
@@ -8216,8 +8276,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.u32()}, b.Splat<vec2<u32>>(8_u),
-                                               b.Splat<vec2<u32>>(9_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               b.Splat<vec2<u32>>(8_u), b.Splat<vec2<u32>>(9_u));
         b.Return(ep);
     });
 
@@ -8251,8 +8311,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.u32()}, b.Splat<vec2<u32>>(8_u),
-                                               b.Splat<vec2<i32>>(1_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               b.Splat<vec2<u32>>(8_u), b.Splat<vec2<i32>>(1_i));
         b.Return(ep);
     });
 
@@ -8287,8 +8347,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.u32()}, b.Splat<vec2<i32>>(1_i),
-                                               b.Splat<vec2<u32>>(9_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               b.Splat<vec2<i32>>(1_i), b.Splat<vec2<u32>>(9_u));
         b.Return(ep);
     });
 
@@ -8321,8 +8381,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.u32()}, b.Splat<vec2<i32>>(1_i),
-                                               b.Splat<vec2<i32>>(2_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               b.Splat<vec2<i32>>(1_i), b.Splat<vec2<i32>>(2_i));
         b.Return(ep);
     });
 
@@ -8356,8 +8416,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.i32()}, b.Splat<vec2<u32>>(8_u),
-                                               b.Splat<vec2<u32>>(9_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               b.Splat<vec2<u32>>(8_u), b.Splat<vec2<u32>>(9_u));
         b.Return(ep);
     });
 
@@ -8390,8 +8450,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.i32()}, b.Splat<vec2<u32>>(8_u),
-                                               b.Splat<vec2<i32>>(1_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               b.Splat<vec2<u32>>(8_u), b.Splat<vec2<i32>>(1_i));
         b.Return(ep);
     });
 
@@ -8425,8 +8485,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.i32()}, b.Splat<vec2<i32>>(1_i),
-                                               b.Splat<vec2<u32>>(9_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               b.Splat<vec2<i32>>(1_i), b.Splat<vec2<u32>>(9_u));
         b.Return(ep);
     });
 
@@ -8458,8 +8518,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kShiftRightArithmetic,
-                                               Vector{ty.i32()}, b.Splat<vec2<i32>>(1_i),
-                                               b.Splat<vec2<i32>>(2_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               b.Splat<vec2<i32>>(1_i), b.Splat<vec2<i32>>(2_i));
         b.Return(ep);
     });
 
@@ -8493,12 +8553,14 @@
     mod.properties.Add(core::ir::Property::kAllowOverrides);
 
     b.Append(b.ir.root_block, [&] {
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kNot, Vector{ty.i32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kNot,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                1_i);
     });
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kNot, Vector{ty.i32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kNot,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                1_i);
         b.Return(ep);
     });
@@ -8538,7 +8600,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kNot, Vector{ty.i32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kNot,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                1_i);
         b.Return(ep);
     });
@@ -8570,7 +8633,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kNot, Vector{ty.u32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kNot,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                1_i);
         b.Return(ep);
     });
@@ -8603,7 +8667,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kNot, Vector{ty.i32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kNot,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                8_u);
         b.Return(ep);
     });
@@ -8636,7 +8701,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kNot, Vector{ty.i32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kNot,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat<vec2<i32>>(1_i));
         b.Return(ep);
     });
@@ -8668,7 +8734,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kNot, Vector{ty.u32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kNot,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat<vec2<i32>>(1_i));
         b.Return(ep);
     });
@@ -8701,7 +8768,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kNot, Vector{ty.i32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kNot,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
                                                b.Splat<vec2<u32>>(8_u));
         b.Return(ep);
     });
@@ -8734,7 +8802,8 @@
     auto* ep = b.ComputeFunction("foo");
 
     b.Append(ep->Block(), [&] {  //
-        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kNot, Vector{ty.u32()},
+        b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kNot,
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
                                                b.Splat<vec2<u32>>(8_u));
         b.Return(ep);
     });
@@ -8767,7 +8836,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kSNegate,
-                                               Vector{ty.i32()}, 1_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               1_i);
         b.Return(ep);
     });
 
@@ -8799,7 +8869,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kSNegate,
-                                               Vector{ty.u32()}, 1_i);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               1_i);
         b.Return(ep);
     });
 
@@ -8832,7 +8903,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.i32(), spirv::BuiltinFn::kSNegate,
-                                               Vector{ty.i32()}, 8_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               8_u);
         b.Return(ep);
     });
 
@@ -8865,7 +8937,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.u32(), spirv::BuiltinFn::kSNegate,
-                                               Vector{ty.u32()}, 8_u);
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               8_u);
         b.Return(ep);
     });
 
@@ -8899,7 +8972,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kSNegate,
-                                               Vector{ty.i32()}, b.Splat<vec2<i32>>(1_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               b.Splat<vec2<i32>>(1_i));
         b.Return(ep);
     });
 
@@ -8931,7 +9005,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kSNegate,
-                                               Vector{ty.u32()}, b.Splat<vec2<i32>>(1_i));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               b.Splat<vec2<i32>>(1_i));
         b.Return(ep);
     });
 
@@ -8964,7 +9039,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2i(), spirv::BuiltinFn::kSNegate,
-                                               Vector{ty.i32()}, b.Splat<vec2<u32>>(8_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.i32()},
+                                               b.Splat<vec2<u32>>(8_u));
         b.Return(ep);
     });
 
@@ -8997,7 +9073,8 @@
 
     b.Append(ep->Block(), [&] {  //
         b.CallExplicit<spirv::ir::BuiltinCall>(ty.vec2u(), spirv::BuiltinFn::kSNegate,
-                                               Vector{ty.u32()}, b.Splat<vec2<u32>>(8_u));
+                                               Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+                                               b.Splat<vec2<u32>>(8_u));
         b.Return(ep);
     });
 
diff --git a/src/tint/lang/spirv/reader/parser/parser.cc b/src/tint/lang/spirv/reader/parser/parser.cc
index 20109dd..beb861d 100644
--- a/src/tint/lang/spirv/reader/parser/parser.cc
+++ b/src/tint/lang/spirv/reader/parser/parser.cc
@@ -3170,7 +3170,9 @@
         auto* si = Value(inst.GetSingleWordInOperand(0));
         Emit(b_.CallExplicit<spirv::ir::BuiltinCall>(
                  Type(inst.type_id()), spirv::BuiltinFn::kOpImage,
-                 Vector{si->Type()->As<spirv::type::SampledImage>()->Image()}, Args(inst, 2)),
+                 Vector<core::ir::TemplateParameter, 1>{
+                     si->Type()->As<spirv::type::SampledImage>()->Image()},
+                 Args(inst, 2)),
              inst.result_id());
     }
 
@@ -3180,9 +3182,9 @@
         TINT_ASSERT(img_type);
         TINT_ASSERT(img_type->GetMultisampled() != type::Multisampled::kMultisampled)
             << "Creating an OpTypeSampledImage from a multisampled image is not supported";
-        Emit(b_.CallExplicit<spirv::ir::BuiltinCall>(Type(inst.type_id()),
-                                                     spirv::BuiltinFn::kOpSampledImage,
-                                                     Vector{tex->Type()}, Args(inst, 2)),
+        Emit(b_.CallExplicit<spirv::ir::BuiltinCall>(
+                 Type(inst.type_id()), spirv::BuiltinFn::kOpSampledImage,
+                 Vector<core::ir::TemplateParameter, 1>{tex->Type()}, Args(inst, 2)),
              inst.result_id());
     }
 
@@ -3328,7 +3330,8 @@
         auto* image = Value(inst.GetSingleWordInOperand(0));
 
         auto* ty = Type(inst.type_id());
-        Emit(b_.CallExplicit<spirv::ir::BuiltinCall>(ty, fn, Vector{ty->DeepestElement()}, image),
+        Emit(b_.CallExplicit<spirv::ir::BuiltinCall>(
+                 ty, fn, Vector<core::ir::TemplateParameter, 1>{ty->DeepestElement()}, image),
              inst.result_id());
     }
 
@@ -3337,8 +3340,9 @@
         auto* level = Value(inst.GetSingleWordInOperand(1));
 
         auto* ty = Type(inst.type_id());
-        Emit(b_.CallExplicit<spirv::ir::BuiltinCall>(ty, spirv::BuiltinFn::kImageQuerySizeLod,
-                                                     Vector{ty->DeepestElement()}, image, level),
+        Emit(b_.CallExplicit<spirv::ir::BuiltinCall>(
+                 ty, spirv::BuiltinFn::kImageQuerySizeLod,
+                 Vector<core::ir::TemplateParameter, 1>{ty->DeepestElement()}, image, level),
              inst.result_id());
     }
 
@@ -3897,9 +3901,10 @@
     void EmitSpirvExplicitBuiltinCall(const spvtools::opt::Instruction& inst,
                                       spirv::BuiltinFn fn,
                                       uint32_t first_operand_idx = 2) {
-        Emit(b_.CallExplicit<spirv::ir::BuiltinCall>(Type(inst.type_id()), fn,
-                                                     Vector{Type(inst.type_id())->DeepestElement()},
-                                                     Args(inst, first_operand_idx)),
+        Emit(b_.CallExplicit<spirv::ir::BuiltinCall>(
+                 Type(inst.type_id()), fn,
+                 Vector<core::ir::TemplateParameter, 1>{Type(inst.type_id())->DeepestElement()},
+                 Args(inst, first_operand_idx)),
              inst.result_id());
     }
 
@@ -3913,9 +3918,9 @@
 
     void EmitBitCount(const spvtools::opt::Instruction& inst) {
         auto* res_ty = Type(inst.type_id());
-        Emit(b_.CallExplicit<spirv::ir::BuiltinCall>(res_ty, spirv::BuiltinFn::kBitCount,
-                                                     Vector{res_ty->DeepestElement()},
-                                                     Args(inst, 2)),
+        Emit(b_.CallExplicit<spirv::ir::BuiltinCall>(
+                 res_ty, spirv::BuiltinFn::kBitCount,
+                 Vector<core::ir::TemplateParameter, 1>{res_ty->DeepestElement()}, Args(inst, 2)),
              inst.result_id());
     }
 
@@ -4144,8 +4149,9 @@
         return spirv::BuiltinFn::kNone;
     }
 
-    Vector<const core::type::Type*, 1> GlslStd450ExplicitParams(uint32_t ext_opcode,
-                                                                const core::type::Type* result_ty) {
+    Vector<core::ir::TemplateParameter, 1> GlslStd450ExplicitParams(
+        uint32_t ext_opcode,
+        const core::type::Type* result_ty) {
         if (ext_opcode == GLSLstd450SSign || ext_opcode == GLSLstd450SAbs ||
             ext_opcode == GLSLstd450SMax || ext_opcode == GLSLstd450SMin ||
             ext_opcode == GLSLstd450SClamp || ext_opcode == GLSLstd450UMax ||
diff --git a/src/tint/lang/spirv/writer/BUILD.cmake b/src/tint/lang/spirv/writer/BUILD.cmake
index 971227c..cee26ed 100644
--- a/src/tint/lang/spirv/writer/BUILD.cmake
+++ b/src/tint/lang/spirv/writer/BUILD.cmake
@@ -161,6 +161,7 @@
   tint_cmd_fuzz_common
   tint_lang_core
   tint_lang_core_constant
+  tint_lang_core_intrinsic
   tint_lang_core_ir
   tint_lang_core_type
   tint_lang_spirv_validate
diff --git a/src/tint/lang/spirv/writer/BUILD.gn b/src/tint/lang/spirv/writer/BUILD.gn
index 6d51ea9..622ff98 100644
--- a/src/tint/lang/spirv/writer/BUILD.gn
+++ b/src/tint/lang/spirv/writer/BUILD.gn
@@ -147,6 +147,7 @@
       "${tint_src_dir}/cmd/fuzz/common",
       "${tint_src_dir}/lang/core",
       "${tint_src_dir}/lang/core/constant",
+      "${tint_src_dir}/lang/core/intrinsic",
       "${tint_src_dir}/lang/core/ir",
       "${tint_src_dir}/lang/core/type",
       "${tint_src_dir}/lang/spirv/validate",
diff --git a/src/tint/lang/spirv/writer/analysis/relaxed_precision_decorations_test.cc b/src/tint/lang/spirv/writer/analysis/relaxed_precision_decorations_test.cc
index 0b4c108..e32d404 100644
--- a/src/tint/lang/spirv/writer/analysis/relaxed_precision_decorations_test.cc
+++ b/src/tint/lang/spirv/writer/analysis/relaxed_precision_decorations_test.cc
@@ -658,8 +658,8 @@
         auto* loaded_image = b.Load(image);
         auto* loaded_sampler = b.Load(sampler);
         auto* sampled_image = b.CallExplicit<ir::BuiltinCall>(
-            ty.Get<type::SampledImage>(image_type), BuiltinFn::kOpSampledImage, Vector{image_type},
-            loaded_image, loaded_sampler);
+            ty.Get<type::SampledImage>(image_type), BuiltinFn::kOpSampledImage,
+            Vector<core::ir::TemplateParameter, 1>{image_type}, loaded_image, loaded_sampler);
 
         sample = b.Call<ir::BuiltinCall>(ty.vec4f(), BuiltinFn::kImageSampleImplicitLod,
                                          sampled_image, coords, Literal(0u))
@@ -712,8 +712,8 @@
         auto* loaded_image = b.Load(image);
         auto* loaded_sampler = b.Load(sampler);
         auto* sampled_image = b.CallExplicit<ir::BuiltinCall>(
-            ty.Get<type::SampledImage>(image_type), BuiltinFn::kOpSampledImage, Vector{image_type},
-            loaded_image, loaded_sampler);
+            ty.Get<type::SampledImage>(image_type), BuiltinFn::kOpSampledImage,
+            Vector<core::ir::TemplateParameter, 1>{image_type}, loaded_image, loaded_sampler);
 
         sample = b.Call<ir::BuiltinCall>(ty.vec4f(), BuiltinFn::kImageSampleImplicitLod,
                                          sampled_image, coords, Literal(0u))
diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
index 7d6c803..eaae821 100644
--- a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
+++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
@@ -353,12 +353,14 @@
             b.InsertBefore(construct, [&] {
                 if (sm_ty->Type()->Is<core::type::I8>()) {
                     value = b.CallExplicit<spirv::ir::BuiltinCall>(
-                                 ty.i8(), spirv::BuiltinFn::kSConvert, Vector{ty.i8()},
+                                 ty.i8(), spirv::BuiltinFn::kSConvert,
+                                 Vector<core::ir::TemplateParameter, 1>{ty.i8()},
                                  b.Clamp(value, -128_i, 127_i))
                                 ->Result();
                 } else if (sm_ty->Type()->Is<core::type::U8>()) {
                     value = b.CallExplicit<spirv::ir::BuiltinCall>(
-                                 ty.u8(), spirv::BuiltinFn::kUConvert, Vector{ty.u8()},
+                                 ty.u8(), spirv::BuiltinFn::kUConvert,
+                                 Vector<core::ir::TemplateParameter, 1>{ty.u8()},
                                  b.Clamp(value, 0_u, 255_u))
                                 ->Result();
                 }
@@ -777,7 +779,7 @@
         // Use OpSampledImage to create an OpTypeSampledImage object.
         auto* sampled_image = b.CallExplicit<spirv::ir::BuiltinCall>(
             ty.Get<type::SampledImage>(texture_ty), spirv::BuiltinFn::kOpSampledImage,
-            Vector{texture_ty}, Vector{texture, sampler});
+            Vector<core::ir::TemplateParameter, 1>{texture_ty}, Vector{texture, sampler});
         sampled_image->InsertBefore(builtin);
 
         // Append the array index to the coordinates if provided.
@@ -836,7 +838,7 @@
                 // Get texture dimensions. The return type depends on if it was an array texture.
                 auto* dim = b.CallExplicit<spirv::ir::BuiltinCall>(
                     array_idx ? ty.vec3u() : ty.vec2u(), spirv::BuiltinFn::kImageQuerySizeLod,
-                    Vector{ty.u32()}, texture, b.Constant(0_i));
+                    Vector<core::ir::TemplateParameter, 1>{ty.u32()}, texture, b.Constant(0_i));
 
                 auto* dim2u = b.Swizzle(ty.vec2u(), dim, {0, 1});
                 auto* fdim = b.Convert(ty.vec2f(), dim2u);
@@ -975,7 +977,7 @@
         // Use OpSampledImage to create an OpTypeSampledImage object.
         auto* sampled_image = b.CallExplicit<spirv::ir::BuiltinCall>(
             ty.Get<type::SampledImage>(texture_ty), spirv::BuiltinFn::kOpSampledImage,
-            Vector{texture_ty}, Vector{texture, sampler});
+            Vector<core::ir::TemplateParameter, 1>{texture_ty}, Vector{texture, sampler});
         sampled_image->InsertBefore(builtin);
 
         // Append the array index to the coordinates if provided.
@@ -1163,7 +1165,8 @@
 
         // Call the function.
         core::ir::Instruction* result = b.CallExplicit<spirv::ir::BuiltinCall>(
-            result_ty, function, Vector{ty.u32()}, std::move(function_args));
+            result_ty, function, Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+            std::move(function_args));
         result->InsertBefore(builtin);
 
         // Swizzle the first two components from the result for arrayed textures.
@@ -1184,9 +1187,9 @@
         b.InsertBefore(builtin, [&] {
             // Call the function.
             auto* res_ty = builtin->Result()->Type();
-            b.CallExplicitWithResult<spirv::ir::BuiltinCall>(builtin->DetachResult(),
-                                                             spirv::BuiltinFn::kImageQueryLevels,
-                                                             Vector{res_ty}, Vector{args[0]});
+            b.CallExplicitWithResult<spirv::ir::BuiltinCall>(
+                builtin->DetachResult(), spirv::BuiltinFn::kImageQueryLevels,
+                Vector<core::ir::TemplateParameter, 1>{res_ty}, Vector{args[0]});
         });
         builtin->Destroy();
     }
@@ -1199,9 +1202,9 @@
         b.InsertBefore(builtin, [&] {
             // Call the function.
             auto* res_ty = builtin->Result()->Type();
-            b.CallExplicitWithResult<spirv::ir::BuiltinCall>(builtin->DetachResult(),
-                                                             spirv::BuiltinFn::kImageQuerySamples,
-                                                             Vector{res_ty}, Vector{args[0]});
+            b.CallExplicitWithResult<spirv::ir::BuiltinCall>(
+                builtin->DetachResult(), spirv::BuiltinFn::kImageQuerySamples,
+                Vector<core::ir::TemplateParameter, 1>{res_ty}, Vector{args[0]});
         });
         builtin->Destroy();
     }
@@ -1227,7 +1230,8 @@
 
         // Call the function.
         auto* texture_call = b.CallExplicit<spirv::ir::BuiltinCall>(
-            ty.vec3u(), function, Vector{ty.u32()}, std::move(function_args));
+            ty.vec3u(), function, Vector<core::ir::TemplateParameter, 1>{ty.u32()},
+            std::move(function_args));
         texture_call->InsertBefore(builtin);
 
         // Extract the third component to get the number of array layers.
@@ -1387,7 +1391,7 @@
             auto* call = b.CallWithResult<spirv::ir::BuiltinCall>(
                 builtin->DetachResult(), spirv::BuiltinFn::kCooperativeMatrixLoad, src, layout,
                 applied_stride, memory_operand);
-            call->SetExplicitTemplateParams(Vector{result_ty});
+            call->SetExplicitTemplateParams(Vector<core::ir::TemplateParameter, 1>{result_ty});
         });
         builtin->Destroy();
     }
@@ -1505,12 +1509,14 @@
             auto* sm_ty = mat->Type()->As<core::type::SubgroupMatrix>();
             if (sm_ty->Type()->Is<core::type::I8>()) {
                 scalar = b.CallExplicit<spirv::ir::BuiltinCall>(
-                              ty.i8(), spirv::BuiltinFn::kSConvert, Vector{ty.i8()},
+                              ty.i8(), spirv::BuiltinFn::kSConvert,
+                              Vector<core::ir::TemplateParameter, 1>{ty.i8()},
                               b.Clamp(scalar, -128_i, 127_i))
                              ->Result();
             } else if (sm_ty->Type()->Is<core::type::U8>()) {
                 scalar = b.CallExplicit<spirv::ir::BuiltinCall>(
-                              ty.u8(), spirv::BuiltinFn::kUConvert, Vector{ty.u8()},
+                              ty.u8(), spirv::BuiltinFn::kUConvert,
+                              Vector<core::ir::TemplateParameter, 1>{ty.u8()},
                               b.Clamp(scalar, 0_u, 255_u))
                              ->Result();
             }
diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc b/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc
index 5004c46..a3d514f 100644
--- a/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc
+++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc
@@ -4354,8 +4354,9 @@
     auto* func = b.Function("foo", mat);
     func->SetParams({p});
     b.Append(func->Block(), [&] {
-        auto* call = b.CallExplicit(mat, core::BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, p, 64_u,
-                                    true, 32_u);
+        auto* call =
+            b.CallExplicit(mat, core::BuiltinFn::kSubgroupMatrixLoad,
+                           Vector<core::ir::TemplateParameter, 1>{mat}, p, 64_u, true, 32_u);
         b.Return(func, call);
     });
 
@@ -4391,8 +4392,9 @@
     auto* func = b.Function("foo", mat);
     func->SetParams({p});
     b.Append(func->Block(), [&] {
-        auto* call = b.CallExplicit(mat, core::BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, p, 64_u,
-                                    false, 32_u);
+        auto* call =
+            b.CallExplicit(mat, core::BuiltinFn::kSubgroupMatrixLoad,
+                           Vector<core::ir::TemplateParameter, 1>{mat}, p, 64_u, false, 32_u);
         b.Return(func, call);
     });
 
@@ -4428,8 +4430,9 @@
     auto* func = b.Function("foo", mat);
     func->SetParams({p});
     b.Append(func->Block(), [&] {
-        auto* call = b.CallExplicit(mat, core::BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, p, 64_u,
-                                    true, 32_u);
+        auto* call =
+            b.CallExplicit(mat, core::BuiltinFn::kSubgroupMatrixLoad,
+                           Vector<core::ir::TemplateParameter, 1>{mat}, p, 64_u, true, 32_u);
         b.Return(func, call);
     });
 
@@ -4467,8 +4470,9 @@
     auto* func = b.Function("foo", mat);
     func->SetParams({p});
     b.Append(func->Block(), [&] {
-        auto* call = b.CallExplicit(mat, core::BuiltinFn::kSubgroupMatrixLoad, Vector{mat}, p, 64_u,
-                                    false, 32_u);
+        auto* call =
+            b.CallExplicit(mat, core::BuiltinFn::kSubgroupMatrixLoad,
+                           Vector<core::ir::TemplateParameter, 1>{mat}, p, 64_u, false, 32_u);
         b.Return(func, call);
     });
 
@@ -4656,7 +4660,7 @@
     func->SetParams({left, right});
     b.Append(func->Block(), [&] {
         auto* call = b.CallExplicit(result, core::BuiltinFn::kSubgroupMatrixMultiply,
-                                    Vector{ty.f32()}, left, right);
+                                    Vector<core::ir::TemplateParameter, 1>{ty.f32()}, left, right);
         b.Return(func, call);
     });
 
@@ -4694,7 +4698,7 @@
     func->SetParams({left, right});
     b.Append(func->Block(), [&] {
         auto* call = b.CallExplicit(result, core::BuiltinFn::kSubgroupMatrixMultiply,
-                                    Vector{ty.u32()}, left, right);
+                                    Vector<core::ir::TemplateParameter, 1>{ty.u32()}, left, right);
         b.Return(func, call);
     });
 
@@ -4732,7 +4736,7 @@
     func->SetParams({left, right});
     b.Append(func->Block(), [&] {
         auto* call = b.CallExplicit(result, core::BuiltinFn::kSubgroupMatrixMultiply,
-                                    Vector{ty.i32()}, left, right);
+                                    Vector<core::ir::TemplateParameter, 1>{ty.i32()}, left, right);
         b.Return(func, call);
     });
 
@@ -4770,7 +4774,7 @@
     func->SetParams({left, right});
     b.Append(func->Block(), [&] {
         auto* call = b.CallExplicit(result, core::BuiltinFn::kSubgroupMatrixMultiply,
-                                    Vector{ty.i32()}, left, right);
+                                    Vector<core::ir::TemplateParameter, 1>{ty.i32()}, left, right);
         b.Return(func, call);
     });
 
@@ -4808,7 +4812,7 @@
     func->SetParams({left, right});
     b.Append(func->Block(), [&] {
         auto* call = b.CallExplicit(result, core::BuiltinFn::kSubgroupMatrixMultiply,
-                                    Vector{ty.i32()}, left, right);
+                                    Vector<core::ir::TemplateParameter, 1>{ty.i32()}, left, right);
         b.Return(func, call);
     });
 
@@ -4846,7 +4850,7 @@
     func->SetParams({left, right});
     b.Append(func->Block(), [&] {
         auto* call = b.CallExplicit(result, core::BuiltinFn::kSubgroupMatrixMultiply,
-                                    Vector{ty.u32()}, left, right);
+                                    Vector<core::ir::TemplateParameter, 1>{ty.u32()}, left, right);
         b.Return(func, call);
     });
 
diff --git a/src/tint/lang/wgsl/intrinsic/table_test.cc b/src/tint/lang/wgsl/intrinsic/table_test.cc
index a168939..f3cef65 100644
--- a/src/tint/lang/wgsl/intrinsic/table_test.cc
+++ b/src/tint/lang/wgsl/intrinsic/table_test.cc
@@ -836,8 +836,8 @@
 TEST_F(WgslIntrinsicTableTest, MatchTypeInitializerExplicit) {
     auto* i32 = create<core::type::I32>();
     auto* vec3i = create<core::type::Vector>(i32, 3u);
-    auto result = table.Lookup(CtorConv::kVec3, Vector{i32}, Vector{i32, i32, i32},
-                               core::EvaluationStage::kConstant);
+    auto result = table.Lookup(CtorConv::kVec3, Vector<core::intrinsic::TemplateParameter, 1>{i32},
+                               Vector{i32, i32, i32}, core::EvaluationStage::kConstant);
     ASSERT_EQ(result, Success);
     EXPECT_EQ(result->return_type, vec3i);
     EXPECT_TRUE(result->info->flags.Contains(OverloadFlag::kIsConstructor));
@@ -908,8 +908,8 @@
 TEST_F(WgslIntrinsicTableTest, MismatchTypeInitializerExplicit) {
     auto* i32 = create<core::type::I32>();
     auto* f32 = create<core::type::F32>();
-    auto result = table.Lookup(CtorConv::kVec3, Vector{i32}, Vector{i32, f32, i32},
-                               core::EvaluationStage::kConstant);
+    auto result = table.Lookup(CtorConv::kVec3, Vector<core::intrinsic::TemplateParameter, 1>{i32},
+                               Vector{i32, f32, i32}, core::EvaluationStage::kConstant);
     ASSERT_NE(result, Success);
     EXPECT_EQ(result.Failure().Plain(),
               R"(no matching constructor for 'vec3<i32>(i32, f32, i32)'
@@ -1031,8 +1031,8 @@
     auto* vec3i = create<core::type::Vector>(i32, 3u);
     auto* f32 = create<core::type::F32>();
     auto* vec3f = create<core::type::Vector>(f32, 3u);
-    auto result =
-        table.Lookup(CtorConv::kVec3, Vector{i32}, Vector{vec3f}, core::EvaluationStage::kConstant);
+    auto result = table.Lookup(CtorConv::kVec3, Vector<core::intrinsic::TemplateParameter, 1>{i32},
+                               Vector{vec3f}, core::EvaluationStage::kConstant);
     ASSERT_EQ(result, Success);
     EXPECT_EQ(result->return_type, vec3i);
     EXPECT_FALSE(result->info->flags.Contains(OverloadFlag::kIsConstructor));
@@ -1044,8 +1044,8 @@
     auto* arr = create<core::type::Array>(create<core::type::U32>(),
                                           create<core::type::RuntimeArrayCount>(), 4u);
     auto* f32 = create<core::type::F32>();
-    auto result =
-        table.Lookup(CtorConv::kVec3, Vector{f32}, Vector{arr}, core::EvaluationStage::kConstant);
+    auto result = table.Lookup(CtorConv::kVec3, Vector<core::intrinsic::TemplateParameter, 1>{f32},
+                               Vector{arr}, core::EvaluationStage::kConstant);
     ASSERT_NE(result, Success);
     EXPECT_EQ(result.Failure().Plain(),
               R"(no matching constructor for 'vec3<f32>(array<u32>)'
@@ -1103,8 +1103,8 @@
     auto* vec3_ai = create<core::type::Vector>(ai, 3u);
     auto* f32 = create<core::type::F32>();
     auto* vec3f = create<core::type::Vector>(f32, 3u);
-    auto result = table.Lookup(CtorConv::kVec3, Vector{af}, Vector{vec3_ai},
-                               core::EvaluationStage::kConstant);
+    auto result = table.Lookup(CtorConv::kVec3, Vector<core::intrinsic::TemplateParameter, 1>{af},
+                               Vector{vec3_ai}, core::EvaluationStage::kConstant);
     ASSERT_EQ(result, Success);
     EXPECT_NE(result->const_eval_fn, nullptr);
     // NOTE: Conversions are explicit, so there's no way to have it return abstracts
@@ -1120,8 +1120,8 @@
     auto* vec3_ai = create<core::type::Vector>(ai, 3u);
     auto* vec3f = create<core::type::Vector>(create<core::type::F32>(), 3u);
     auto* vec3i = create<core::type::Vector>(create<core::type::I32>(), 3u);
-    auto result =
-        table.Lookup(CtorConv::kVec3, Vector{af}, Vector{vec3_ai}, core::EvaluationStage::kRuntime);
+    auto result = table.Lookup(CtorConv::kVec3, Vector<core::intrinsic::TemplateParameter, 1>{af},
+                               Vector{vec3_ai}, core::EvaluationStage::kRuntime);
     ASSERT_EQ(result, Success);
     EXPECT_NE(result->const_eval_fn, nullptr);
     EXPECT_EQ(result->return_type, vec3f);
diff --git a/src/tint/lang/wgsl/ir/builtin_call_test.cc b/src/tint/lang/wgsl/ir/builtin_call_test.cc
index 2804d5b..219a511 100644
--- a/src/tint/lang/wgsl/ir/builtin_call_test.cc
+++ b/src/tint/lang/wgsl/ir/builtin_call_test.cc
@@ -55,7 +55,7 @@
 
 TEST_F(IR_WgslBuiltinCallTest, CloneWithExplicitParams) {
     auto* builtin = b.Call<BuiltinCall>(mod.Types().void_(), BuiltinFn::kAbs, 1_i);
-    builtin->SetExplicitTemplateParams(Vector{mod.Types().i32()});
+    builtin->SetExplicitTemplateParams(Vector<core::ir::TemplateParameter, 1>{mod.Types().i32()});
 
     auto* new_b = clone_ctx.Clone(builtin);
     EXPECT_NE(builtin->Result(), new_b->Result());
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 53a9206..1843ac6 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
@@ -1106,7 +1106,7 @@
                 new_args[2] = nullptr;
                 new_args[3] = args[2];
 
-                Vector<const core::type::Type*, 1> templates;
+                Vector<core::ir::TemplateParameter, 1> templates;
 
                 // Keep the type template.
                 auto* res_type_sem = impl.program_.Sem().Get(tmpl->arguments[0]);
@@ -1208,7 +1208,7 @@
                         if (b->Overload().num_explicit_templates > 0) {
                             auto* tmpl = expr->target->identifier->As<ast::TemplatedIdentifier>();
                             TINT_ASSERT(tmpl);
-                            Vector<const core::type::Type*, 1> explicit_types;
+                            Vector<core::ir::TemplateParameter, 1> explicit_types;
                             for (uint32_t i = 0; i < b->Overload().num_explicit_templates; i++) {
                                 auto* tmpl_sem = impl.program_.Sem().Get(tmpl->arguments[i]);
                                 auto* tmpl_ty = tmpl_sem->As<sem::TypeExpression>();
diff --git a/src/tint/lang/wgsl/resolver/resolver.cc b/src/tint/lang/wgsl/resolver/resolver.cc
index 8ee4aba..4c4a834 100644
--- a/src/tint/lang/wgsl/resolver/resolver.cc
+++ b/src/tint/lang/wgsl/resolver/resolver.cc
@@ -1917,8 +1917,9 @@
 
     // ctor_or_conv is a helper for building either a sem::ValueConstructor or
     // sem::ValueConversion call for a CtorConvIntrinsic with an optional template argument type.
-    auto ctor_or_conv = [&](CtorConvIntrinsic ty,
-                            VectorRef<const core::type::Type*> template_args) -> sem::Call* {
+    auto ctor_or_conv =
+        [&](CtorConvIntrinsic ty,
+            VectorRef<core::intrinsic::TemplateParameter> template_args) -> sem::Call* {
         auto arg_tys = tint::Transform(args, [&](auto* arg) { return arg->Type(); });
 
         auto match = intrinsic_table_.Lookup(ty, template_args, arg_tys, args_stage);
@@ -2021,11 +2022,12 @@
             [&](const core::type::F32*) { return ctor_or_conv(CtorConvIntrinsic::kF32, Empty); },
             [&](const core::type::Bool*) { return ctor_or_conv(CtorConvIntrinsic::kBool, Empty); },
             [&](const core::type::Vector* v) {
-                return ctor_or_conv(wgsl::intrinsic::VectorCtorConv(v->Width()), Vector{v->Type()});
+                return ctor_or_conv(wgsl::intrinsic::VectorCtorConv(v->Width()),
+                                    Vector<core::intrinsic::TemplateParameter, 1>{v->Type()});
             },
             [&](const core::type::Matrix* m) {
                 return ctor_or_conv(wgsl::intrinsic::MatrixCtorConv(m->Columns(), m->Rows()),
-                                    Vector{m->Type()});
+                                    Vector<core::intrinsic::TemplateParameter, 1>{m->Type()});
             },
             [&](const sem::Array* arr) -> sem::Call* {
                 auto* call_target = array_ctors_.GetOrAdd(
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
index 2fc26cc..b004ac6 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
@@ -737,8 +737,16 @@
                 const ast::CallExpression* expr = nullptr;
                 if (!c->ExplicitTemplateParams().IsEmpty()) {
                     Vector<const ast::Expression*, 4> tmpl_args;
-                    for (auto* e : c->ExplicitTemplateParams()) {
-                        tmpl_args.Push(Type(e).expr);
+                    for (auto& e : c->ExplicitTemplateParams()) {
+                        if (std::holds_alternative<const core::type::Type*>(e)) {
+                            tmpl_args.Push(Type(std::get<const core::type::Type*>(e)).expr);
+                        } else if (std::holds_alternative<core::Majorness>(e)) {
+                            StringStream str;
+                            str << std::get<core::Majorness>(e);
+                            tmpl_args.Push(b.Expr(str.str()));
+                        } else {
+                            TINT_UNREACHABLE() << "Unhandled template parameter kind";
+                        }
                     }
                     expr = b.Call(b.Ident(c->Func(), std::move(tmpl_args)), std::move(args));
                 } else {
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 387598c..dcef922 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
@@ -3566,7 +3566,8 @@
         from->SetOverrideId(OverrideId{10});
 
         o = b.Override("o", b.CallExplicit<wgsl::ir::BuiltinCall>(
-                                ty.i32(), wgsl::BuiltinFn::kBitcast, Vector{ty.i32()}, from));
+                                ty.i32(), wgsl::BuiltinFn::kBitcast,
+                                Vector<core::ir::TemplateParameter, 1>{ty.i32()}, from));
     });
 
     auto* fn = b.Function("f", ty.i32());
diff --git a/src/tint/lang/wgsl/writer/raise/raise.cc b/src/tint/lang/wgsl/writer/raise/raise.cc
index f138f84..a5fbf66 100644
--- a/src/tint/lang/wgsl/writer/raise/raise.cc
+++ b/src/tint/lang/wgsl/writer/raise/raise.cc
@@ -223,7 +223,7 @@
     auto* replacement = b.CallWithResult<wgsl::ir::BuiltinCall>(
         call->DetachResult(), Convert(call->Func()), std::move(args));
     if (!call->ExplicitTemplateParams().IsEmpty()) {
-        Vector<const core::type::Type*, 4> tmpl_args;
+        Vector<core::ir::TemplateParameter, 4> tmpl_args;
         for (auto p : call->ExplicitTemplateParams()) {
             tmpl_args.Push(p);
         }
diff --git a/src/tint/utils/protos/ir/ir.proto b/src/tint/utils/protos/ir/ir.proto
index d444267..2251c0e 100644
--- a/src/tint/utils/protos/ir/ir.proto
+++ b/src/tint/utils/protos/ir/ir.proto
@@ -241,6 +241,13 @@
     optional string name = 2;
 }
 
+message TemplateParameter {
+    oneof kind {
+        uint32 type = 1;  // Module.types
+        Majorness majorness = 2;
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // ConstantValues
 ////////////////////////////////////////////////////////////////////////////////
@@ -382,7 +389,9 @@
 
 message InstructionBuiltinCall {
     BuiltinFn builtin = 1;
-    repeated uint32 explicit_template_params = 2;  // Module.types
+    reserved 2;
+    reserved "explicit_template_params";
+    repeated TemplateParameter explicit_template_parameters = 3;
 }
 
 message InstructionLoad {}
@@ -494,6 +503,11 @@
     read_write = 2;
 }
 
+enum Majorness {
+    row_major = 0;
+    col_major = 1;
+}
+
 enum UnaryOp {
     complement = 0;
     negation = 1;