Move sem::BuiltinType to builtin::Function.

This CL moves `sem::BuiltinType` to `builtin::Function`. This makes it
available for use in the IR. The `Function` name better maps to the
usage in that it contains the builtin functions.

Bug: tint:1834
Change-Id: Ic1a26525d7845d79eb6239bdeb2b73e05f586c24
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/122606
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 3b801f4..4c02044 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -651,8 +651,6 @@
     "sem/builtin.h",
     "sem/builtin_enum_expression.cc",
     "sem/builtin_enum_expression.h",
-    "sem/builtin_type.cc",
-    "sem/builtin_type.h",
     "sem/call.cc",
     "sem/call.h",
     "sem/call_target.cc",
@@ -736,6 +734,8 @@
     "builtin/diagnostic_severity.h",
     "builtin/extension.cc",
     "builtin/extension.h",
+    "builtin/function.cc",
+    "builtin/function.h",
     "builtin/interpolation_sampling.cc",
     "builtin/interpolation_sampling.h",
     "builtin/interpolation_type.cc",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 4ea36bb..bbaaa9f 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -564,12 +564,12 @@
 tint_generated(builtin/diagnostic_rule BENCH TEST)
 tint_generated(builtin/diagnostic_severity BENCH TEST)
 tint_generated(builtin/extension BENCH TEST)
+tint_generated(builtin/function)
 tint_generated(builtin/interpolation_sampling BENCH TEST)
 tint_generated(builtin/interpolation_type BENCH TEST)
 tint_generated(builtin/texel_format BENCH TEST)
 
 tint_generated(resolver/ctor_conv_intrinsic)
-tint_generated(sem/builtin_type)
 tint_generated(sem/parameter_usage)
 
 if(UNIX)
diff --git a/src/tint/builtin/function.cc b/src/tint/builtin/function.cc
new file mode 100644
index 0000000..88e86b6
--- /dev/null
+++ b/src/tint/builtin/function.cc
@@ -0,0 +1,614 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/function.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/function.h"
+
+namespace tint::builtin {
+
+Function ParseFunction(const std::string& name) {
+    if (name == "abs") {
+        return Function::kAbs;
+    }
+    if (name == "acos") {
+        return Function::kAcos;
+    }
+    if (name == "acosh") {
+        return Function::kAcosh;
+    }
+    if (name == "all") {
+        return Function::kAll;
+    }
+    if (name == "any") {
+        return Function::kAny;
+    }
+    if (name == "arrayLength") {
+        return Function::kArrayLength;
+    }
+    if (name == "asin") {
+        return Function::kAsin;
+    }
+    if (name == "asinh") {
+        return Function::kAsinh;
+    }
+    if (name == "atan") {
+        return Function::kAtan;
+    }
+    if (name == "atan2") {
+        return Function::kAtan2;
+    }
+    if (name == "atanh") {
+        return Function::kAtanh;
+    }
+    if (name == "ceil") {
+        return Function::kCeil;
+    }
+    if (name == "clamp") {
+        return Function::kClamp;
+    }
+    if (name == "cos") {
+        return Function::kCos;
+    }
+    if (name == "cosh") {
+        return Function::kCosh;
+    }
+    if (name == "countLeadingZeros") {
+        return Function::kCountLeadingZeros;
+    }
+    if (name == "countOneBits") {
+        return Function::kCountOneBits;
+    }
+    if (name == "countTrailingZeros") {
+        return Function::kCountTrailingZeros;
+    }
+    if (name == "cross") {
+        return Function::kCross;
+    }
+    if (name == "degrees") {
+        return Function::kDegrees;
+    }
+    if (name == "determinant") {
+        return Function::kDeterminant;
+    }
+    if (name == "distance") {
+        return Function::kDistance;
+    }
+    if (name == "dot") {
+        return Function::kDot;
+    }
+    if (name == "dot4I8Packed") {
+        return Function::kDot4I8Packed;
+    }
+    if (name == "dot4U8Packed") {
+        return Function::kDot4U8Packed;
+    }
+    if (name == "dpdx") {
+        return Function::kDpdx;
+    }
+    if (name == "dpdxCoarse") {
+        return Function::kDpdxCoarse;
+    }
+    if (name == "dpdxFine") {
+        return Function::kDpdxFine;
+    }
+    if (name == "dpdy") {
+        return Function::kDpdy;
+    }
+    if (name == "dpdyCoarse") {
+        return Function::kDpdyCoarse;
+    }
+    if (name == "dpdyFine") {
+        return Function::kDpdyFine;
+    }
+    if (name == "exp") {
+        return Function::kExp;
+    }
+    if (name == "exp2") {
+        return Function::kExp2;
+    }
+    if (name == "extractBits") {
+        return Function::kExtractBits;
+    }
+    if (name == "faceForward") {
+        return Function::kFaceForward;
+    }
+    if (name == "firstLeadingBit") {
+        return Function::kFirstLeadingBit;
+    }
+    if (name == "firstTrailingBit") {
+        return Function::kFirstTrailingBit;
+    }
+    if (name == "floor") {
+        return Function::kFloor;
+    }
+    if (name == "fma") {
+        return Function::kFma;
+    }
+    if (name == "fract") {
+        return Function::kFract;
+    }
+    if (name == "frexp") {
+        return Function::kFrexp;
+    }
+    if (name == "fwidth") {
+        return Function::kFwidth;
+    }
+    if (name == "fwidthCoarse") {
+        return Function::kFwidthCoarse;
+    }
+    if (name == "fwidthFine") {
+        return Function::kFwidthFine;
+    }
+    if (name == "insertBits") {
+        return Function::kInsertBits;
+    }
+    if (name == "inverseSqrt") {
+        return Function::kInverseSqrt;
+    }
+    if (name == "ldexp") {
+        return Function::kLdexp;
+    }
+    if (name == "length") {
+        return Function::kLength;
+    }
+    if (name == "log") {
+        return Function::kLog;
+    }
+    if (name == "log2") {
+        return Function::kLog2;
+    }
+    if (name == "max") {
+        return Function::kMax;
+    }
+    if (name == "min") {
+        return Function::kMin;
+    }
+    if (name == "mix") {
+        return Function::kMix;
+    }
+    if (name == "modf") {
+        return Function::kModf;
+    }
+    if (name == "normalize") {
+        return Function::kNormalize;
+    }
+    if (name == "pack2x16float") {
+        return Function::kPack2X16Float;
+    }
+    if (name == "pack2x16snorm") {
+        return Function::kPack2X16Snorm;
+    }
+    if (name == "pack2x16unorm") {
+        return Function::kPack2X16Unorm;
+    }
+    if (name == "pack4x8snorm") {
+        return Function::kPack4X8Snorm;
+    }
+    if (name == "pack4x8unorm") {
+        return Function::kPack4X8Unorm;
+    }
+    if (name == "pow") {
+        return Function::kPow;
+    }
+    if (name == "quantizeToF16") {
+        return Function::kQuantizeToF16;
+    }
+    if (name == "radians") {
+        return Function::kRadians;
+    }
+    if (name == "reflect") {
+        return Function::kReflect;
+    }
+    if (name == "refract") {
+        return Function::kRefract;
+    }
+    if (name == "reverseBits") {
+        return Function::kReverseBits;
+    }
+    if (name == "round") {
+        return Function::kRound;
+    }
+    if (name == "saturate") {
+        return Function::kSaturate;
+    }
+    if (name == "select") {
+        return Function::kSelect;
+    }
+    if (name == "sign") {
+        return Function::kSign;
+    }
+    if (name == "sin") {
+        return Function::kSin;
+    }
+    if (name == "sinh") {
+        return Function::kSinh;
+    }
+    if (name == "smoothstep") {
+        return Function::kSmoothstep;
+    }
+    if (name == "sqrt") {
+        return Function::kSqrt;
+    }
+    if (name == "step") {
+        return Function::kStep;
+    }
+    if (name == "storageBarrier") {
+        return Function::kStorageBarrier;
+    }
+    if (name == "tan") {
+        return Function::kTan;
+    }
+    if (name == "tanh") {
+        return Function::kTanh;
+    }
+    if (name == "transpose") {
+        return Function::kTranspose;
+    }
+    if (name == "trunc") {
+        return Function::kTrunc;
+    }
+    if (name == "unpack2x16float") {
+        return Function::kUnpack2X16Float;
+    }
+    if (name == "unpack2x16snorm") {
+        return Function::kUnpack2X16Snorm;
+    }
+    if (name == "unpack2x16unorm") {
+        return Function::kUnpack2X16Unorm;
+    }
+    if (name == "unpack4x8snorm") {
+        return Function::kUnpack4X8Snorm;
+    }
+    if (name == "unpack4x8unorm") {
+        return Function::kUnpack4X8Unorm;
+    }
+    if (name == "workgroupBarrier") {
+        return Function::kWorkgroupBarrier;
+    }
+    if (name == "workgroupUniformLoad") {
+        return Function::kWorkgroupUniformLoad;
+    }
+    if (name == "textureDimensions") {
+        return Function::kTextureDimensions;
+    }
+    if (name == "textureGather") {
+        return Function::kTextureGather;
+    }
+    if (name == "textureGatherCompare") {
+        return Function::kTextureGatherCompare;
+    }
+    if (name == "textureNumLayers") {
+        return Function::kTextureNumLayers;
+    }
+    if (name == "textureNumLevels") {
+        return Function::kTextureNumLevels;
+    }
+    if (name == "textureNumSamples") {
+        return Function::kTextureNumSamples;
+    }
+    if (name == "textureSample") {
+        return Function::kTextureSample;
+    }
+    if (name == "textureSampleBias") {
+        return Function::kTextureSampleBias;
+    }
+    if (name == "textureSampleCompare") {
+        return Function::kTextureSampleCompare;
+    }
+    if (name == "textureSampleCompareLevel") {
+        return Function::kTextureSampleCompareLevel;
+    }
+    if (name == "textureSampleGrad") {
+        return Function::kTextureSampleGrad;
+    }
+    if (name == "textureSampleLevel") {
+        return Function::kTextureSampleLevel;
+    }
+    if (name == "textureSampleBaseClampToEdge") {
+        return Function::kTextureSampleBaseClampToEdge;
+    }
+    if (name == "textureStore") {
+        return Function::kTextureStore;
+    }
+    if (name == "textureLoad") {
+        return Function::kTextureLoad;
+    }
+    if (name == "atomicLoad") {
+        return Function::kAtomicLoad;
+    }
+    if (name == "atomicStore") {
+        return Function::kAtomicStore;
+    }
+    if (name == "atomicAdd") {
+        return Function::kAtomicAdd;
+    }
+    if (name == "atomicSub") {
+        return Function::kAtomicSub;
+    }
+    if (name == "atomicMax") {
+        return Function::kAtomicMax;
+    }
+    if (name == "atomicMin") {
+        return Function::kAtomicMin;
+    }
+    if (name == "atomicAnd") {
+        return Function::kAtomicAnd;
+    }
+    if (name == "atomicOr") {
+        return Function::kAtomicOr;
+    }
+    if (name == "atomicXor") {
+        return Function::kAtomicXor;
+    }
+    if (name == "atomicExchange") {
+        return Function::kAtomicExchange;
+    }
+    if (name == "atomicCompareExchangeWeak") {
+        return Function::kAtomicCompareExchangeWeak;
+    }
+    if (name == "_tint_materialize") {
+        return Function::kTintMaterialize;
+    }
+    return Function::kNone;
+}
+
+const char* str(Function i) {
+    switch (i) {
+        case Function::kNone:
+            return "<none>";
+        case Function::kAbs:
+            return "abs";
+        case Function::kAcos:
+            return "acos";
+        case Function::kAcosh:
+            return "acosh";
+        case Function::kAll:
+            return "all";
+        case Function::kAny:
+            return "any";
+        case Function::kArrayLength:
+            return "arrayLength";
+        case Function::kAsin:
+            return "asin";
+        case Function::kAsinh:
+            return "asinh";
+        case Function::kAtan:
+            return "atan";
+        case Function::kAtan2:
+            return "atan2";
+        case Function::kAtanh:
+            return "atanh";
+        case Function::kCeil:
+            return "ceil";
+        case Function::kClamp:
+            return "clamp";
+        case Function::kCos:
+            return "cos";
+        case Function::kCosh:
+            return "cosh";
+        case Function::kCountLeadingZeros:
+            return "countLeadingZeros";
+        case Function::kCountOneBits:
+            return "countOneBits";
+        case Function::kCountTrailingZeros:
+            return "countTrailingZeros";
+        case Function::kCross:
+            return "cross";
+        case Function::kDegrees:
+            return "degrees";
+        case Function::kDeterminant:
+            return "determinant";
+        case Function::kDistance:
+            return "distance";
+        case Function::kDot:
+            return "dot";
+        case Function::kDot4I8Packed:
+            return "dot4I8Packed";
+        case Function::kDot4U8Packed:
+            return "dot4U8Packed";
+        case Function::kDpdx:
+            return "dpdx";
+        case Function::kDpdxCoarse:
+            return "dpdxCoarse";
+        case Function::kDpdxFine:
+            return "dpdxFine";
+        case Function::kDpdy:
+            return "dpdy";
+        case Function::kDpdyCoarse:
+            return "dpdyCoarse";
+        case Function::kDpdyFine:
+            return "dpdyFine";
+        case Function::kExp:
+            return "exp";
+        case Function::kExp2:
+            return "exp2";
+        case Function::kExtractBits:
+            return "extractBits";
+        case Function::kFaceForward:
+            return "faceForward";
+        case Function::kFirstLeadingBit:
+            return "firstLeadingBit";
+        case Function::kFirstTrailingBit:
+            return "firstTrailingBit";
+        case Function::kFloor:
+            return "floor";
+        case Function::kFma:
+            return "fma";
+        case Function::kFract:
+            return "fract";
+        case Function::kFrexp:
+            return "frexp";
+        case Function::kFwidth:
+            return "fwidth";
+        case Function::kFwidthCoarse:
+            return "fwidthCoarse";
+        case Function::kFwidthFine:
+            return "fwidthFine";
+        case Function::kInsertBits:
+            return "insertBits";
+        case Function::kInverseSqrt:
+            return "inverseSqrt";
+        case Function::kLdexp:
+            return "ldexp";
+        case Function::kLength:
+            return "length";
+        case Function::kLog:
+            return "log";
+        case Function::kLog2:
+            return "log2";
+        case Function::kMax:
+            return "max";
+        case Function::kMin:
+            return "min";
+        case Function::kMix:
+            return "mix";
+        case Function::kModf:
+            return "modf";
+        case Function::kNormalize:
+            return "normalize";
+        case Function::kPack2X16Float:
+            return "pack2x16float";
+        case Function::kPack2X16Snorm:
+            return "pack2x16snorm";
+        case Function::kPack2X16Unorm:
+            return "pack2x16unorm";
+        case Function::kPack4X8Snorm:
+            return "pack4x8snorm";
+        case Function::kPack4X8Unorm:
+            return "pack4x8unorm";
+        case Function::kPow:
+            return "pow";
+        case Function::kQuantizeToF16:
+            return "quantizeToF16";
+        case Function::kRadians:
+            return "radians";
+        case Function::kReflect:
+            return "reflect";
+        case Function::kRefract:
+            return "refract";
+        case Function::kReverseBits:
+            return "reverseBits";
+        case Function::kRound:
+            return "round";
+        case Function::kSaturate:
+            return "saturate";
+        case Function::kSelect:
+            return "select";
+        case Function::kSign:
+            return "sign";
+        case Function::kSin:
+            return "sin";
+        case Function::kSinh:
+            return "sinh";
+        case Function::kSmoothstep:
+            return "smoothstep";
+        case Function::kSqrt:
+            return "sqrt";
+        case Function::kStep:
+            return "step";
+        case Function::kStorageBarrier:
+            return "storageBarrier";
+        case Function::kTan:
+            return "tan";
+        case Function::kTanh:
+            return "tanh";
+        case Function::kTranspose:
+            return "transpose";
+        case Function::kTrunc:
+            return "trunc";
+        case Function::kUnpack2X16Float:
+            return "unpack2x16float";
+        case Function::kUnpack2X16Snorm:
+            return "unpack2x16snorm";
+        case Function::kUnpack2X16Unorm:
+            return "unpack2x16unorm";
+        case Function::kUnpack4X8Snorm:
+            return "unpack4x8snorm";
+        case Function::kUnpack4X8Unorm:
+            return "unpack4x8unorm";
+        case Function::kWorkgroupBarrier:
+            return "workgroupBarrier";
+        case Function::kWorkgroupUniformLoad:
+            return "workgroupUniformLoad";
+        case Function::kTextureDimensions:
+            return "textureDimensions";
+        case Function::kTextureGather:
+            return "textureGather";
+        case Function::kTextureGatherCompare:
+            return "textureGatherCompare";
+        case Function::kTextureNumLayers:
+            return "textureNumLayers";
+        case Function::kTextureNumLevels:
+            return "textureNumLevels";
+        case Function::kTextureNumSamples:
+            return "textureNumSamples";
+        case Function::kTextureSample:
+            return "textureSample";
+        case Function::kTextureSampleBias:
+            return "textureSampleBias";
+        case Function::kTextureSampleCompare:
+            return "textureSampleCompare";
+        case Function::kTextureSampleCompareLevel:
+            return "textureSampleCompareLevel";
+        case Function::kTextureSampleGrad:
+            return "textureSampleGrad";
+        case Function::kTextureSampleLevel:
+            return "textureSampleLevel";
+        case Function::kTextureSampleBaseClampToEdge:
+            return "textureSampleBaseClampToEdge";
+        case Function::kTextureStore:
+            return "textureStore";
+        case Function::kTextureLoad:
+            return "textureLoad";
+        case Function::kAtomicLoad:
+            return "atomicLoad";
+        case Function::kAtomicStore:
+            return "atomicStore";
+        case Function::kAtomicAdd:
+            return "atomicAdd";
+        case Function::kAtomicSub:
+            return "atomicSub";
+        case Function::kAtomicMax:
+            return "atomicMax";
+        case Function::kAtomicMin:
+            return "atomicMin";
+        case Function::kAtomicAnd:
+            return "atomicAnd";
+        case Function::kAtomicOr:
+            return "atomicOr";
+        case Function::kAtomicXor:
+            return "atomicXor";
+        case Function::kAtomicExchange:
+            return "atomicExchange";
+        case Function::kAtomicCompareExchangeWeak:
+            return "atomicCompareExchangeWeak";
+        case Function::kTintMaterialize:
+            return "_tint_materialize";
+    }
+    return "<unknown>";
+}
+
+utils::StringStream& operator<<(utils::StringStream& out, Function i) {
+    out << str(i);
+    return out;
+}
+
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/function.cc.tmpl b/src/tint/builtin/function.cc.tmpl
new file mode 100644
index 0000000..e2729dc
--- /dev/null
+++ b/src/tint/builtin/function.cc.tmpl
@@ -0,0 +1,44 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate function.cc
+
+To update the generated file, run:
+    ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+#include "src/tint/builtin/function.h"
+
+namespace tint::builtin {
+
+Function ParseFunction(const std::string& name) {
+{{- range Sem.Builtins  }}
+    if (name == "{{.Name}}") {
+        return Function::k{{PascalCase .Name}};
+    }
+{{- end  }}
+    return Function::kNone;
+}
+
+const char* str(Function i) {
+    switch (i) {
+        case Function::kNone:
+            return "<none>";
+{{- range Sem.Builtins  }}
+        case Function::k{{PascalCase .Name}}:
+            return "{{.Name}}";
+{{- end  }}
+    }
+    return "<unknown>";
+}
+
+utils::StringStream& operator<<(utils::StringStream& out, Function i) {
+    out << str(i);
+    return out;
+}
+
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/function.h b/src/tint/builtin/function.h
new file mode 100644
index 0000000..3ccb341
--- /dev/null
+++ b/src/tint/builtin/function.h
@@ -0,0 +1,405 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/function.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_TINT_BUILTIN_FUNCTION_H_
+#define SRC_TINT_BUILTIN_FUNCTION_H_
+
+#include <string>
+
+#include "src/tint/utils/string_stream.h"
+
+// \cond DO_NOT_DOCUMENT
+namespace tint::builtin {
+
+/// Enumerator of all builtin functions
+enum class Function {
+    kNone = -1,
+    kAbs,
+    kAcos,
+    kAcosh,
+    kAll,
+    kAny,
+    kArrayLength,
+    kAsin,
+    kAsinh,
+    kAtan,
+    kAtan2,
+    kAtanh,
+    kCeil,
+    kClamp,
+    kCos,
+    kCosh,
+    kCountLeadingZeros,
+    kCountOneBits,
+    kCountTrailingZeros,
+    kCross,
+    kDegrees,
+    kDeterminant,
+    kDistance,
+    kDot,
+    kDot4I8Packed,
+    kDot4U8Packed,
+    kDpdx,
+    kDpdxCoarse,
+    kDpdxFine,
+    kDpdy,
+    kDpdyCoarse,
+    kDpdyFine,
+    kExp,
+    kExp2,
+    kExtractBits,
+    kFaceForward,
+    kFirstLeadingBit,
+    kFirstTrailingBit,
+    kFloor,
+    kFma,
+    kFract,
+    kFrexp,
+    kFwidth,
+    kFwidthCoarse,
+    kFwidthFine,
+    kInsertBits,
+    kInverseSqrt,
+    kLdexp,
+    kLength,
+    kLog,
+    kLog2,
+    kMax,
+    kMin,
+    kMix,
+    kModf,
+    kNormalize,
+    kPack2X16Float,
+    kPack2X16Snorm,
+    kPack2X16Unorm,
+    kPack4X8Snorm,
+    kPack4X8Unorm,
+    kPow,
+    kQuantizeToF16,
+    kRadians,
+    kReflect,
+    kRefract,
+    kReverseBits,
+    kRound,
+    kSaturate,
+    kSelect,
+    kSign,
+    kSin,
+    kSinh,
+    kSmoothstep,
+    kSqrt,
+    kStep,
+    kStorageBarrier,
+    kTan,
+    kTanh,
+    kTranspose,
+    kTrunc,
+    kUnpack2X16Float,
+    kUnpack2X16Snorm,
+    kUnpack2X16Unorm,
+    kUnpack4X8Snorm,
+    kUnpack4X8Unorm,
+    kWorkgroupBarrier,
+    kWorkgroupUniformLoad,
+    kTextureDimensions,
+    kTextureGather,
+    kTextureGatherCompare,
+    kTextureNumLayers,
+    kTextureNumLevels,
+    kTextureNumSamples,
+    kTextureSample,
+    kTextureSampleBias,
+    kTextureSampleCompare,
+    kTextureSampleCompareLevel,
+    kTextureSampleGrad,
+    kTextureSampleLevel,
+    kTextureSampleBaseClampToEdge,
+    kTextureStore,
+    kTextureLoad,
+    kAtomicLoad,
+    kAtomicStore,
+    kAtomicAdd,
+    kAtomicSub,
+    kAtomicMax,
+    kAtomicMin,
+    kAtomicAnd,
+    kAtomicOr,
+    kAtomicXor,
+    kAtomicExchange,
+    kAtomicCompareExchangeWeak,
+    kTintMaterialize,
+};
+
+/// Matches the Function by name
+/// @param name the builtin name to parse
+/// @returns the parsed Function, or Function::kNone if `name` did not
+/// match any builtin function.
+Function ParseFunction(const std::string& name);
+
+/// @returns the name of the builtin function type. The spelling, including
+/// case, matches the name in the WGSL spec.
+const char* str(Function i);
+
+/// Emits the name of the builtin function type. The spelling, including case,
+/// matches the name in the WGSL spec.
+utils::StringStream& operator<<(utils::StringStream& out, Function i);
+
+/// All builtin functions
+constexpr Function kFunctions[] = {
+    Function::kAbs,
+    Function::kAcos,
+    Function::kAcosh,
+    Function::kAll,
+    Function::kAny,
+    Function::kArrayLength,
+    Function::kAsin,
+    Function::kAsinh,
+    Function::kAtan,
+    Function::kAtan2,
+    Function::kAtanh,
+    Function::kCeil,
+    Function::kClamp,
+    Function::kCos,
+    Function::kCosh,
+    Function::kCountLeadingZeros,
+    Function::kCountOneBits,
+    Function::kCountTrailingZeros,
+    Function::kCross,
+    Function::kDegrees,
+    Function::kDeterminant,
+    Function::kDistance,
+    Function::kDot,
+    Function::kDot4I8Packed,
+    Function::kDot4U8Packed,
+    Function::kDpdx,
+    Function::kDpdxCoarse,
+    Function::kDpdxFine,
+    Function::kDpdy,
+    Function::kDpdyCoarse,
+    Function::kDpdyFine,
+    Function::kExp,
+    Function::kExp2,
+    Function::kExtractBits,
+    Function::kFaceForward,
+    Function::kFirstLeadingBit,
+    Function::kFirstTrailingBit,
+    Function::kFloor,
+    Function::kFma,
+    Function::kFract,
+    Function::kFrexp,
+    Function::kFwidth,
+    Function::kFwidthCoarse,
+    Function::kFwidthFine,
+    Function::kInsertBits,
+    Function::kInverseSqrt,
+    Function::kLdexp,
+    Function::kLength,
+    Function::kLog,
+    Function::kLog2,
+    Function::kMax,
+    Function::kMin,
+    Function::kMix,
+    Function::kModf,
+    Function::kNormalize,
+    Function::kPack2X16Float,
+    Function::kPack2X16Snorm,
+    Function::kPack2X16Unorm,
+    Function::kPack4X8Snorm,
+    Function::kPack4X8Unorm,
+    Function::kPow,
+    Function::kQuantizeToF16,
+    Function::kRadians,
+    Function::kReflect,
+    Function::kRefract,
+    Function::kReverseBits,
+    Function::kRound,
+    Function::kSaturate,
+    Function::kSelect,
+    Function::kSign,
+    Function::kSin,
+    Function::kSinh,
+    Function::kSmoothstep,
+    Function::kSqrt,
+    Function::kStep,
+    Function::kStorageBarrier,
+    Function::kTan,
+    Function::kTanh,
+    Function::kTranspose,
+    Function::kTrunc,
+    Function::kUnpack2X16Float,
+    Function::kUnpack2X16Snorm,
+    Function::kUnpack2X16Unorm,
+    Function::kUnpack4X8Snorm,
+    Function::kUnpack4X8Unorm,
+    Function::kWorkgroupBarrier,
+    Function::kWorkgroupUniformLoad,
+    Function::kTextureDimensions,
+    Function::kTextureGather,
+    Function::kTextureGatherCompare,
+    Function::kTextureNumLayers,
+    Function::kTextureNumLevels,
+    Function::kTextureNumSamples,
+    Function::kTextureSample,
+    Function::kTextureSampleBias,
+    Function::kTextureSampleCompare,
+    Function::kTextureSampleCompareLevel,
+    Function::kTextureSampleGrad,
+    Function::kTextureSampleLevel,
+    Function::kTextureSampleBaseClampToEdge,
+    Function::kTextureStore,
+    Function::kTextureLoad,
+    Function::kAtomicLoad,
+    Function::kAtomicStore,
+    Function::kAtomicAdd,
+    Function::kAtomicSub,
+    Function::kAtomicMax,
+    Function::kAtomicMin,
+    Function::kAtomicAnd,
+    Function::kAtomicOr,
+    Function::kAtomicXor,
+    Function::kAtomicExchange,
+    Function::kAtomicCompareExchangeWeak,
+    Function::kTintMaterialize,
+};
+
+/// All builtin function names
+constexpr const char* kFunctionStrings[] = {
+    "abs",
+    "acos",
+    "acosh",
+    "all",
+    "any",
+    "arrayLength",
+    "asin",
+    "asinh",
+    "atan",
+    "atan2",
+    "atanh",
+    "ceil",
+    "clamp",
+    "cos",
+    "cosh",
+    "countLeadingZeros",
+    "countOneBits",
+    "countTrailingZeros",
+    "cross",
+    "degrees",
+    "determinant",
+    "distance",
+    "dot",
+    "dot4I8Packed",
+    "dot4U8Packed",
+    "dpdx",
+    "dpdxCoarse",
+    "dpdxFine",
+    "dpdy",
+    "dpdyCoarse",
+    "dpdyFine",
+    "exp",
+    "exp2",
+    "extractBits",
+    "faceForward",
+    "firstLeadingBit",
+    "firstTrailingBit",
+    "floor",
+    "fma",
+    "fract",
+    "frexp",
+    "fwidth",
+    "fwidthCoarse",
+    "fwidthFine",
+    "insertBits",
+    "inverseSqrt",
+    "ldexp",
+    "length",
+    "log",
+    "log2",
+    "max",
+    "min",
+    "mix",
+    "modf",
+    "normalize",
+    "pack2x16float",
+    "pack2x16snorm",
+    "pack2x16unorm",
+    "pack4x8snorm",
+    "pack4x8unorm",
+    "pow",
+    "quantizeToF16",
+    "radians",
+    "reflect",
+    "refract",
+    "reverseBits",
+    "round",
+    "saturate",
+    "select",
+    "sign",
+    "sin",
+    "sinh",
+    "smoothstep",
+    "sqrt",
+    "step",
+    "storageBarrier",
+    "tan",
+    "tanh",
+    "transpose",
+    "trunc",
+    "unpack2x16float",
+    "unpack2x16snorm",
+    "unpack2x16unorm",
+    "unpack4x8snorm",
+    "unpack4x8unorm",
+    "workgroupBarrier",
+    "workgroupUniformLoad",
+    "textureDimensions",
+    "textureGather",
+    "textureGatherCompare",
+    "textureNumLayers",
+    "textureNumLevels",
+    "textureNumSamples",
+    "textureSample",
+    "textureSampleBias",
+    "textureSampleCompare",
+    "textureSampleCompareLevel",
+    "textureSampleGrad",
+    "textureSampleLevel",
+    "textureSampleBaseClampToEdge",
+    "textureStore",
+    "textureLoad",
+    "atomicLoad",
+    "atomicStore",
+    "atomicAdd",
+    "atomicSub",
+    "atomicMax",
+    "atomicMin",
+    "atomicAnd",
+    "atomicOr",
+    "atomicXor",
+    "atomicExchange",
+    "atomicCompareExchangeWeak",
+    "_tint_materialize",
+};
+
+}  // namespace tint::builtin
+// \endcond
+
+#endif  // SRC_TINT_BUILTIN_FUNCTION_H_
diff --git a/src/tint/builtin/function.h.tmpl b/src/tint/builtin/function.h.tmpl
new file mode 100644
index 0000000..d9109bf
--- /dev/null
+++ b/src/tint/builtin/function.h.tmpl
@@ -0,0 +1,63 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate function.h
+
+To update the generated file, run:
+    ./tools/run gen
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+#ifndef SRC_TINT_BUILTIN_FUNCTION_H_
+#define SRC_TINT_BUILTIN_FUNCTION_H_
+
+#include <string>
+
+#include "src/tint/utils/string_stream.h"
+
+// \cond DO_NOT_DOCUMENT
+namespace tint::builtin {
+
+/// Enumerator of all builtin functions
+enum class Function {
+    kNone = -1,
+{{- range Sem.Builtins }}
+    k{{PascalCase .Name}},
+{{- end }}
+};
+
+/// Matches the Function by name
+/// @param name the builtin name to parse
+/// @returns the parsed Function, or Function::kNone if `name` did not
+/// match any builtin function.
+Function ParseFunction(const std::string& name);
+
+/// @returns the name of the builtin function type. The spelling, including
+/// case, matches the name in the WGSL spec.
+const char* str(Function i);
+
+/// Emits the name of the builtin function type. The spelling, including case,
+/// matches the name in the WGSL spec.
+utils::StringStream& operator<<(utils::StringStream& out, Function i);
+
+/// All builtin functions
+constexpr Function kFunctions[] = {
+{{- range Sem.Builtins }}
+    Function::k{{PascalCase .Name}},
+{{- end }}
+};
+
+/// All builtin function names
+constexpr const char* kFunctionStrings[] = {
+{{- range Sem.Builtins }}
+    "{{.Name}}",
+{{- end }}
+};
+
+}  // namespace tint::builtin
+// \endcond
+
+#endif  // SRC_TINT_BUILTIN_FUNCTION_H_
diff --git a/src/tint/reader/spirv/function.cc b/src/tint/reader/spirv/function.cc
index 49d4e83..873ffe6 100644
--- a/src/tint/reader/spirv/function.cc
+++ b/src/tint/reader/spirv/function.cc
@@ -32,7 +32,7 @@
 #include "src/tint/ast/unary_op_expression.h"
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/builtin/builtin_value.h"
-#include "src/tint/sem/builtin_type.h"
+#include "src/tint/builtin/function.h"
 #include "src/tint/transform/spirv_atomic.h"
 #include "src/tint/type/depth_texture.h"
 #include "src/tint/type/sampled_texture.h"
@@ -452,42 +452,42 @@
 }
 
 // Returns the WGSL standard library function builtin for the
-// given instruction, or sem::BuiltinType::kNone
-sem::BuiltinType GetBuiltin(spv::Op opcode) {
+// given instruction, or builtin::Function::kNone
+builtin::Function GetBuiltin(spv::Op opcode) {
     switch (opcode) {
         case spv::Op::OpBitCount:
-            return sem::BuiltinType::kCountOneBits;
+            return builtin::Function::kCountOneBits;
         case spv::Op::OpBitFieldInsert:
-            return sem::BuiltinType::kInsertBits;
+            return builtin::Function::kInsertBits;
         case spv::Op::OpBitFieldSExtract:
         case spv::Op::OpBitFieldUExtract:
-            return sem::BuiltinType::kExtractBits;
+            return builtin::Function::kExtractBits;
         case spv::Op::OpBitReverse:
-            return sem::BuiltinType::kReverseBits;
+            return builtin::Function::kReverseBits;
         case spv::Op::OpDot:
-            return sem::BuiltinType::kDot;
+            return builtin::Function::kDot;
         case spv::Op::OpDPdx:
-            return sem::BuiltinType::kDpdx;
+            return builtin::Function::kDpdx;
         case spv::Op::OpDPdy:
-            return sem::BuiltinType::kDpdy;
+            return builtin::Function::kDpdy;
         case spv::Op::OpFwidth:
-            return sem::BuiltinType::kFwidth;
+            return builtin::Function::kFwidth;
         case spv::Op::OpDPdxFine:
-            return sem::BuiltinType::kDpdxFine;
+            return builtin::Function::kDpdxFine;
         case spv::Op::OpDPdyFine:
-            return sem::BuiltinType::kDpdyFine;
+            return builtin::Function::kDpdyFine;
         case spv::Op::OpFwidthFine:
-            return sem::BuiltinType::kFwidthFine;
+            return builtin::Function::kFwidthFine;
         case spv::Op::OpDPdxCoarse:
-            return sem::BuiltinType::kDpdxCoarse;
+            return builtin::Function::kDpdxCoarse;
         case spv::Op::OpDPdyCoarse:
-            return sem::BuiltinType::kDpdyCoarse;
+            return builtin::Function::kDpdyCoarse;
         case spv::Op::OpFwidthCoarse:
-            return sem::BuiltinType::kFwidthCoarse;
+            return builtin::Function::kFwidthCoarse;
         default:
             break;
     }
-    return sem::BuiltinType::kNone;
+    return builtin::Function::kNone;
 }
 
 // @param opcode a SPIR-V opcode
@@ -3816,7 +3816,7 @@
     }
 
     const auto builtin = GetBuiltin(op);
-    if (builtin != sem::BuiltinType::kNone) {
+    if (builtin != builtin::Function::kNone) {
         return MakeBuiltinCall(inst);
     }
 
@@ -5250,7 +5250,7 @@
 
 TypedExpression FunctionEmitter::MakeBuiltinCall(const spvtools::opt::Instruction& inst) {
     const auto builtin = GetBuiltin(opcode(inst));
-    auto* name = sem::str(builtin);
+    auto* name = builtin::str(builtin);
     auto* ident = create<ast::Identifier>(Source{}, builder_.Symbols().Register(name));
 
     ExpressionList params;
@@ -5741,7 +5741,7 @@
 }
 
 bool FunctionEmitter::EmitAtomicOp(const spvtools::opt::Instruction& inst) {
-    auto emit_atomic = [&](sem::BuiltinType builtin, std::initializer_list<TypedExpression> args) {
+    auto emit_atomic = [&](builtin::Function builtin, std::initializer_list<TypedExpression> args) {
         // Split args into params and expressions
         ParameterList params;
         params.Reserve(args.size());
@@ -5763,7 +5763,7 @@
 
         // Emit stub, will be removed by transform::SpirvAtomic
         auto* stub = builder_.Func(
-            Source{}, builder_.Symbols().New(std::string("stub_") + sem::str(builtin)),
+            Source{}, builder_.Symbols().New(std::string("stub_") + builtin::str(builtin)),
             std::move(params), ret_type,
             /* body */ nullptr,
             utils::Vector{
@@ -5800,39 +5800,39 @@
 
     switch (opcode(inst)) {
         case spv::Op::OpAtomicLoad:
-            return emit_atomic(sem::BuiltinType::kAtomicLoad, {oper(/*ptr*/ 0)});
+            return emit_atomic(builtin::Function::kAtomicLoad, {oper(/*ptr*/ 0)});
         case spv::Op::OpAtomicStore:
-            return emit_atomic(sem::BuiltinType::kAtomicStore,
+            return emit_atomic(builtin::Function::kAtomicStore,
                                {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicExchange:
-            return emit_atomic(sem::BuiltinType::kAtomicExchange,
+            return emit_atomic(builtin::Function::kAtomicExchange,
                                {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicCompareExchange:
         case spv::Op::OpAtomicCompareExchangeWeak:
-            return emit_atomic(sem::BuiltinType::kAtomicCompareExchangeWeak,
+            return emit_atomic(builtin::Function::kAtomicCompareExchangeWeak,
                                {oper(/*ptr*/ 0), /*value*/ oper(5), /*comparator*/ oper(4)});
         case spv::Op::OpAtomicIIncrement:
-            return emit_atomic(sem::BuiltinType::kAtomicAdd, {oper(/*ptr*/ 0), lit(1)});
+            return emit_atomic(builtin::Function::kAtomicAdd, {oper(/*ptr*/ 0), lit(1)});
         case spv::Op::OpAtomicIDecrement:
-            return emit_atomic(sem::BuiltinType::kAtomicSub, {oper(/*ptr*/ 0), lit(1)});
+            return emit_atomic(builtin::Function::kAtomicSub, {oper(/*ptr*/ 0), lit(1)});
         case spv::Op::OpAtomicIAdd:
-            return emit_atomic(sem::BuiltinType::kAtomicAdd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(builtin::Function::kAtomicAdd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicISub:
-            return emit_atomic(sem::BuiltinType::kAtomicSub, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(builtin::Function::kAtomicSub, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicSMin:
-            return emit_atomic(sem::BuiltinType::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(builtin::Function::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicUMin:
-            return emit_atomic(sem::BuiltinType::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(builtin::Function::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicSMax:
-            return emit_atomic(sem::BuiltinType::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(builtin::Function::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicUMax:
-            return emit_atomic(sem::BuiltinType::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(builtin::Function::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicAnd:
-            return emit_atomic(sem::BuiltinType::kAtomicAnd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(builtin::Function::kAtomicAnd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicOr:
-            return emit_atomic(sem::BuiltinType::kAtomicOr, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(builtin::Function::kAtomicOr, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicXor:
-            return emit_atomic(sem::BuiltinType::kAtomicXor, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(builtin::Function::kAtomicXor, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicFlagTestAndSet:
         case spv::Op::OpAtomicFlagClear:
         case spv::Op::OpAtomicFMinEXT:
diff --git a/src/tint/reader/spirv/parser_impl_barrier_test.cc b/src/tint/reader/spirv/parser_impl_barrier_test.cc
index a594098..ef8e5af 100644
--- a/src/tint/reader/spirv/parser_impl_barrier_test.cc
+++ b/src/tint/reader/spirv/parser_impl_barrier_test.cc
@@ -73,7 +73,7 @@
     ASSERT_NE(sem_call, nullptr);
     auto* builtin = sem_call->Target()->As<sem::Builtin>();
     ASSERT_NE(builtin, nullptr);
-    EXPECT_EQ(builtin->Type(), sem::BuiltinType::kWorkgroupBarrier);
+    EXPECT_EQ(builtin->Type(), builtin::Function::kWorkgroupBarrier);
 }
 
 TEST_F(SpvParserTest, StorageBarrier) {
@@ -106,7 +106,7 @@
     ASSERT_NE(sem_call, nullptr);
     auto* builtin = sem_call->Target()->As<sem::Builtin>();
     ASSERT_NE(builtin, nullptr);
-    EXPECT_EQ(builtin->Type(), sem::BuiltinType::kStorageBarrier);
+    EXPECT_EQ(builtin->Type(), builtin::Function::kStorageBarrier);
 }
 
 TEST_F(SpvParserTest, ErrBarrierInvalidExecution) {
diff --git a/src/tint/resolver/builtin_test.cc b/src/tint/resolver/builtin_test.cc
index 4e9e4bd..80df98f 100644
--- a/src/tint/resolver/builtin_test.cc
+++ b/src/tint/resolver/builtin_test.cc
@@ -50,13 +50,11 @@
 
 using ExpressionList = utils::Vector<const ast::Expression*, 8>;
 
-using BuiltinType = sem::BuiltinType;
-
 using ResolverBuiltinTest = ResolverTest;
 
 struct BuiltinData {
     const char* name;
-    BuiltinType builtin;
+    builtin::Function builtin;
 };
 
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
@@ -253,7 +251,7 @@
 struct BuiltinDataWithParamNum {
     uint32_t args_number;
     const char* name;
-    BuiltinType builtin;
+    builtin::Function builtin;
 };
 
 inline std::ostream& operator<<(std::ostream& out, BuiltinDataWithParamNum data) {
@@ -680,55 +678,55 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverTest,
     ResolverBuiltinTest_FloatBuiltin_IdenticalType,
-    testing::Values(BuiltinDataWithParamNum{1, "abs", BuiltinType::kAbs},
-                    BuiltinDataWithParamNum{1, "acos", BuiltinType::kAcos},
-                    BuiltinDataWithParamNum{1, "acosh", BuiltinType::kAcos},
-                    BuiltinDataWithParamNum{1, "asin", BuiltinType::kAsin},
-                    BuiltinDataWithParamNum{1, "asinh", BuiltinType::kAsin},
-                    BuiltinDataWithParamNum{1, "atan", BuiltinType::kAtan},
-                    BuiltinDataWithParamNum{1, "atanh", BuiltinType::kAtan},
-                    BuiltinDataWithParamNum{2, "atan2", BuiltinType::kAtan2},
-                    BuiltinDataWithParamNum{1, "ceil", BuiltinType::kCeil},
-                    BuiltinDataWithParamNum{3, "clamp", BuiltinType::kClamp},
-                    BuiltinDataWithParamNum{1, "cos", BuiltinType::kCos},
-                    BuiltinDataWithParamNum{1, "cosh", BuiltinType::kCosh},
+    testing::Values(BuiltinDataWithParamNum{1, "abs", builtin::Function::kAbs},
+                    BuiltinDataWithParamNum{1, "acos", builtin::Function::kAcos},
+                    BuiltinDataWithParamNum{1, "acosh", builtin::Function::kAcos},
+                    BuiltinDataWithParamNum{1, "asin", builtin::Function::kAsin},
+                    BuiltinDataWithParamNum{1, "asinh", builtin::Function::kAsin},
+                    BuiltinDataWithParamNum{1, "atan", builtin::Function::kAtan},
+                    BuiltinDataWithParamNum{1, "atanh", builtin::Function::kAtan},
+                    BuiltinDataWithParamNum{2, "atan2", builtin::Function::kAtan2},
+                    BuiltinDataWithParamNum{1, "ceil", builtin::Function::kCeil},
+                    BuiltinDataWithParamNum{3, "clamp", builtin::Function::kClamp},
+                    BuiltinDataWithParamNum{1, "cos", builtin::Function::kCos},
+                    BuiltinDataWithParamNum{1, "cosh", builtin::Function::kCosh},
                     // cross: (vec3<T>, vec3<T>) -> vec3<T>
-                    BuiltinDataWithParamNum{1, "degrees", BuiltinType::kDegrees},
+                    BuiltinDataWithParamNum{1, "degrees", builtin::Function::kDegrees},
                     // distance: (T, T) -> T, (vecN<T>, vecN<T>) -> T
-                    BuiltinDataWithParamNum{1, "exp", BuiltinType::kExp},
-                    BuiltinDataWithParamNum{1, "exp2", BuiltinType::kExp2},
+                    BuiltinDataWithParamNum{1, "exp", builtin::Function::kExp},
+                    BuiltinDataWithParamNum{1, "exp2", builtin::Function::kExp2},
                     // faceForward: (vecN<T>, vecN<T>, vecN<T>) -> vecN<T>
-                    BuiltinDataWithParamNum{1, "floor", BuiltinType::kFloor},
-                    BuiltinDataWithParamNum{3, "fma", BuiltinType::kFma},
-                    BuiltinDataWithParamNum{1, "fract", BuiltinType::kFract},
+                    BuiltinDataWithParamNum{1, "floor", builtin::Function::kFloor},
+                    BuiltinDataWithParamNum{3, "fma", builtin::Function::kFma},
+                    BuiltinDataWithParamNum{1, "fract", builtin::Function::kFract},
                     // frexp
-                    BuiltinDataWithParamNum{1, "inverseSqrt", BuiltinType::kInverseSqrt},
+                    BuiltinDataWithParamNum{1, "inverseSqrt", builtin::Function::kInverseSqrt},
                     // ldexp: (T, i32) -> T, (vecN<T>, vecN<i32>) -> vecN<T>
                     // length: (vecN<T>) -> T
-                    BuiltinDataWithParamNum{1, "log", BuiltinType::kLog},
-                    BuiltinDataWithParamNum{1, "log2", BuiltinType::kLog2},
-                    BuiltinDataWithParamNum{2, "max", BuiltinType::kMax},
-                    BuiltinDataWithParamNum{2, "min", BuiltinType::kMin},
+                    BuiltinDataWithParamNum{1, "log", builtin::Function::kLog},
+                    BuiltinDataWithParamNum{1, "log2", builtin::Function::kLog2},
+                    BuiltinDataWithParamNum{2, "max", builtin::Function::kMax},
+                    BuiltinDataWithParamNum{2, "min", builtin::Function::kMin},
                     // Note that `mix(vecN<f32>, vecN<f32>, f32) -> vecN<f32>` is not tested here.
-                    BuiltinDataWithParamNum{3, "mix", BuiltinType::kMix},
+                    BuiltinDataWithParamNum{3, "mix", builtin::Function::kMix},
                     // modf
                     // normalize: (vecN<T>) -> vecN<T>
-                    BuiltinDataWithParamNum{2, "pow", BuiltinType::kPow},
+                    BuiltinDataWithParamNum{2, "pow", builtin::Function::kPow},
                     // quantizeToF16 is not implemented yet.
-                    BuiltinDataWithParamNum{1, "radians", BuiltinType::kRadians},
+                    BuiltinDataWithParamNum{1, "radians", builtin::Function::kRadians},
                     // reflect: (vecN<T>, vecN<T>) -> vecN<T>
                     // refract: (vecN<T>, vecN<T>, T) -> vecN<T>
-                    BuiltinDataWithParamNum{1, "round", BuiltinType::kRound},
+                    BuiltinDataWithParamNum{1, "round", builtin::Function::kRound},
                     // saturate not implemented yet.
-                    BuiltinDataWithParamNum{1, "sign", BuiltinType::kSign},
-                    BuiltinDataWithParamNum{1, "sin", BuiltinType::kSin},
-                    BuiltinDataWithParamNum{1, "sinh", BuiltinType::kSinh},
-                    BuiltinDataWithParamNum{3, "smoothstep", BuiltinType::kSmoothstep},
-                    BuiltinDataWithParamNum{1, "sqrt", BuiltinType::kSqrt},
-                    BuiltinDataWithParamNum{2, "step", BuiltinType::kStep},
-                    BuiltinDataWithParamNum{1, "tan", BuiltinType::kTan},
-                    BuiltinDataWithParamNum{1, "tanh", BuiltinType::kTanh},
-                    BuiltinDataWithParamNum{1, "trunc", BuiltinType::kTrunc}));
+                    BuiltinDataWithParamNum{1, "sign", builtin::Function::kSign},
+                    BuiltinDataWithParamNum{1, "sin", builtin::Function::kSin},
+                    BuiltinDataWithParamNum{1, "sinh", builtin::Function::kSinh},
+                    BuiltinDataWithParamNum{3, "smoothstep", builtin::Function::kSmoothstep},
+                    BuiltinDataWithParamNum{1, "sqrt", builtin::Function::kSqrt},
+                    BuiltinDataWithParamNum{2, "step", builtin::Function::kStep},
+                    BuiltinDataWithParamNum{1, "tan", builtin::Function::kTan},
+                    BuiltinDataWithParamNum{1, "tanh", builtin::Function::kTanh},
+                    BuiltinDataWithParamNum{1, "trunc", builtin::Function::kTrunc}));
 
 using ResolverBuiltinFloatTest = ResolverTest;
 
@@ -1409,7 +1407,7 @@
 struct BuiltinDataWithParamNum {
     uint32_t args_number;
     const char* name;
-    BuiltinType builtin;
+    builtin::Function builtin;
 };
 
 inline std::ostream& operator<<(std::ostream& out, BuiltinDataWithParamNum data) {
@@ -1805,18 +1803,18 @@
     ResolverTest,
     ResolverBuiltinTest_IntegerBuiltin_IdenticalType,
     testing::Values(
-        BuiltinDataWithParamNum{1, "abs", BuiltinType::kAbs},
-        BuiltinDataWithParamNum{3, "clamp", BuiltinType::kClamp},
-        BuiltinDataWithParamNum{1, "countLeadingZeros", BuiltinType::kCountLeadingZeros},
-        BuiltinDataWithParamNum{1, "countOneBits", BuiltinType::kCountOneBits},
-        BuiltinDataWithParamNum{1, "countTrailingZeros", BuiltinType::kCountTrailingZeros},
+        BuiltinDataWithParamNum{1, "abs", builtin::Function::kAbs},
+        BuiltinDataWithParamNum{3, "clamp", builtin::Function::kClamp},
+        BuiltinDataWithParamNum{1, "countLeadingZeros", builtin::Function::kCountLeadingZeros},
+        BuiltinDataWithParamNum{1, "countOneBits", builtin::Function::kCountOneBits},
+        BuiltinDataWithParamNum{1, "countTrailingZeros", builtin::Function::kCountTrailingZeros},
         // extractBits: (T, u32, u32) -> T
-        BuiltinDataWithParamNum{1, "firstLeadingBit", BuiltinType::kFirstLeadingBit},
-        BuiltinDataWithParamNum{1, "firstTrailingBit", BuiltinType::kFirstTrailingBit},
+        BuiltinDataWithParamNum{1, "firstLeadingBit", builtin::Function::kFirstLeadingBit},
+        BuiltinDataWithParamNum{1, "firstTrailingBit", builtin::Function::kFirstTrailingBit},
         // insertBits: (T, T, u32, u32) -> T
-        BuiltinDataWithParamNum{2, "max", BuiltinType::kMax},
-        BuiltinDataWithParamNum{2, "min", BuiltinType::kMin},
-        BuiltinDataWithParamNum{1, "reverseBits", BuiltinType::kReverseBits}));
+        BuiltinDataWithParamNum{2, "max", builtin::Function::kMax},
+        BuiltinDataWithParamNum{2, "min", builtin::Function::kMin},
+        BuiltinDataWithParamNum{1, "reverseBits", builtin::Function::kReverseBits}));
 
 }  // namespace integer_builtin_tests
 
@@ -2555,8 +2553,8 @@
 TEST_P(ResolverBuiltinTest_DataPacking, InferType) {
     auto param = GetParam();
 
-    bool pack4 =
-        param.builtin == BuiltinType::kPack4X8Snorm || param.builtin == BuiltinType::kPack4X8Unorm;
+    bool pack4 = param.builtin == builtin::Function::kPack4X8Snorm ||
+                 param.builtin == builtin::Function::kPack4X8Unorm;
 
     auto* call = pack4 ? Call(param.name, vec4<f32>(1_f, 2_f, 3_f, 4_f))
                        : Call(param.name, vec2<f32>(1_f, 2_f));
@@ -2570,8 +2568,8 @@
 TEST_P(ResolverBuiltinTest_DataPacking, Error_IncorrectParamType) {
     auto param = GetParam();
 
-    bool pack4 =
-        param.builtin == BuiltinType::kPack4X8Snorm || param.builtin == BuiltinType::kPack4X8Unorm;
+    bool pack4 = param.builtin == builtin::Function::kPack4X8Snorm ||
+                 param.builtin == builtin::Function::kPack4X8Unorm;
 
     auto* call = pack4 ? Call(param.name, vec4<i32>(1_i, 2_i, 3_i, 4_i))
                        : Call(param.name, vec2<i32>(1_i, 2_i));
@@ -2596,8 +2594,8 @@
 TEST_P(ResolverBuiltinTest_DataPacking, Error_TooManyParams) {
     auto param = GetParam();
 
-    bool pack4 =
-        param.builtin == BuiltinType::kPack4X8Snorm || param.builtin == BuiltinType::kPack4X8Unorm;
+    bool pack4 = param.builtin == builtin::Function::kPack4X8Snorm ||
+                 param.builtin == builtin::Function::kPack4X8Unorm;
 
     auto* call = pack4 ? Call(param.name, vec4<f32>(1_f, 2_f, 3_f, 4_f), 1_f)
                        : Call(param.name, vec2<f32>(1_f, 2_f), 1_f);
@@ -2608,14 +2606,14 @@
     EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
 }
 
-INSTANTIATE_TEST_SUITE_P(ResolverTest,
-                         ResolverBuiltinTest_DataPacking,
-                         testing::Values(BuiltinData{"pack4x8snorm", BuiltinType::kPack4X8Snorm},
-                                         BuiltinData{"pack4x8unorm", BuiltinType::kPack4X8Unorm},
-                                         BuiltinData{"pack2x16snorm", BuiltinType::kPack2X16Snorm},
-                                         BuiltinData{"pack2x16unorm", BuiltinType::kPack2X16Unorm},
-                                         BuiltinData{"pack2x16float",
-                                                     BuiltinType::kPack2X16Float}));
+INSTANTIATE_TEST_SUITE_P(
+    ResolverTest,
+    ResolverBuiltinTest_DataPacking,
+    testing::Values(BuiltinData{"pack4x8snorm", builtin::Function::kPack4X8Snorm},
+                    BuiltinData{"pack4x8unorm", builtin::Function::kPack4X8Unorm},
+                    BuiltinData{"pack2x16snorm", builtin::Function::kPack2X16Snorm},
+                    BuiltinData{"pack2x16unorm", builtin::Function::kPack2X16Unorm},
+                    BuiltinData{"pack2x16float", builtin::Function::kPack2X16Float}));
 
 }  // namespace data_packing_builtin_tests
 
@@ -2626,8 +2624,8 @@
 TEST_P(ResolverBuiltinTest_DataUnpacking, InferType) {
     auto param = GetParam();
 
-    bool pack4 = param.builtin == BuiltinType::kUnpack4X8Snorm ||
-                 param.builtin == BuiltinType::kUnpack4X8Unorm;
+    bool pack4 = param.builtin == builtin::Function::kUnpack4X8Snorm ||
+                 param.builtin == builtin::Function::kUnpack4X8Unorm;
 
     auto* call = Call(param.name, 1_u);
     WrapInFunction(call);
@@ -2645,11 +2643,11 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverTest,
     ResolverBuiltinTest_DataUnpacking,
-    testing::Values(BuiltinData{"unpack4x8snorm", BuiltinType::kUnpack4X8Snorm},
-                    BuiltinData{"unpack4x8unorm", BuiltinType::kUnpack4X8Unorm},
-                    BuiltinData{"unpack2x16snorm", BuiltinType::kUnpack2X16Snorm},
-                    BuiltinData{"unpack2x16unorm", BuiltinType::kUnpack2X16Unorm},
-                    BuiltinData{"unpack2x16float", BuiltinType::kUnpack2X16Float}));
+    testing::Values(BuiltinData{"unpack4x8snorm", builtin::Function::kUnpack4X8Snorm},
+                    BuiltinData{"unpack4x8unorm", builtin::Function::kUnpack4X8Unorm},
+                    BuiltinData{"unpack2x16snorm", builtin::Function::kUnpack2X16Snorm},
+                    BuiltinData{"unpack2x16unorm", builtin::Function::kUnpack2X16Unorm},
+                    BuiltinData{"unpack2x16float", builtin::Function::kUnpack2X16Float}));
 
 }  // namespace data_unpacking_builtin_tests
 
@@ -2682,8 +2680,8 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverTest,
     ResolverBuiltinTest_Barrier,
-    testing::Values(BuiltinData{"storageBarrier", BuiltinType::kStorageBarrier},
-                    BuiltinData{"workgroupBarrier", BuiltinType::kWorkgroupBarrier}));
+    testing::Values(BuiltinData{"storageBarrier", builtin::Function::kStorageBarrier},
+                    BuiltinData{"workgroupBarrier", builtin::Function::kWorkgroupBarrier}));
 
 }  // namespace synchronization_builtin_tests
 
diff --git a/src/tint/resolver/const_eval_builtin_test.cc b/src/tint/resolver/const_eval_builtin_test.cc
index bd32779..2cef1d1 100644
--- a/src/tint/resolver/const_eval_builtin_test.cc
+++ b/src/tint/resolver/const_eval_builtin_test.cc
@@ -139,7 +139,7 @@
     return Case{std::move(args), std::move(err)};
 }
 
-using ResolverConstEvalBuiltinTest = ResolverTestWithParam<std::tuple<sem::BuiltinType, Case>>;
+using ResolverConstEvalBuiltinTest = ResolverTestWithParam<std::tuple<builtin::Function, Case>>;
 
 TEST_P(ResolverConstEvalBuiltinTest, Test) {
     Enable(builtin::Extension::kF16);
@@ -152,7 +152,7 @@
         args.Push(a.Expr(*this));
     }
 
-    auto* expr = Call(Source{{12, 34}}, sem::str(builtin), std::move(args));
+    auto* expr = Call(Source{{12, 34}}, builtin::str(builtin), std::move(args));
     GlobalConst("C", expr);
 
     if (c.expected) {
@@ -187,7 +187,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     MixedAbstractArgs,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kAtan2),
+    testing::Combine(testing::Values(builtin::Function::kAtan2),
                      testing::ValuesIn(std::vector{
                          C({0_a, -0.0_a}, kPi<AFloat>),
                          C({1.0_a, 0_a}, kPiOver2<AFloat>),
@@ -222,7 +222,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Abs,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kAbs),
+    testing::Combine(testing::Values(builtin::Function::kAbs),
                      testing::ValuesIn(Concat(AbsCases<AInt>(),  //
                                               AbsCases<i32>(),
                                               AbsCases<u32>(),
@@ -257,7 +257,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     All,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kAll), testing::ValuesIn(AllCases())));
+    testing::Combine(testing::Values(builtin::Function::kAll), testing::ValuesIn(AllCases())));
 
 static std::vector<Case> AnyCases() {
     return {
@@ -286,7 +286,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Any,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kAny), testing::ValuesIn(AnyCases())));
+    testing::Combine(testing::Values(builtin::Function::kAny), testing::ValuesIn(AnyCases())));
 
 template <typename T>
 std::vector<Case> Atan2Cases() {
@@ -315,7 +315,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Atan2,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kAtan2),
+    testing::Combine(testing::Values(builtin::Function::kAtan2),
                      testing::ValuesIn(Concat(Atan2Cases<AFloat>(),  //
                                               Atan2Cases<f32>(),
                                               Atan2Cases<f16>()))));
@@ -336,7 +336,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Atan,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kAtan),
+    testing::Combine(testing::Values(builtin::Function::kAtan),
                      testing::ValuesIn(Concat(AtanCases<AFloat>(),  //
                                               AtanCases<f32>(),
                                               AtanCases<f16>()))));
@@ -361,7 +361,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Atanh,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kAtanh),
+    testing::Combine(testing::Values(builtin::Function::kAtanh),
                      testing::ValuesIn(Concat(AtanhCases<AFloat>(),  //
                                               AtanhCases<f32>(),
                                               AtanhCases<f16>()))));
@@ -387,7 +387,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Acos,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kAcos),
+    testing::Combine(testing::Values(builtin::Function::kAcos),
                      testing::ValuesIn(Concat(AcosCases<AFloat>(),  //
                                               AcosCases<f32>(),
                                               AcosCases<f16>()))));
@@ -409,7 +409,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Acosh,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kAcosh),
+    testing::Combine(testing::Values(builtin::Function::kAcosh),
                      testing::ValuesIn(Concat(AcoshCases<AFloat>(),  //
                                               AcoshCases<f32>(),
                                               AcoshCases<f16>()))));
@@ -436,7 +436,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Asin,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kAsin),
+    testing::Combine(testing::Values(builtin::Function::kAsin),
                      testing::ValuesIn(Concat(AsinCases<AFloat>(),  //
                                               AsinCases<f32>(),
                                               AsinCases<f16>()))));
@@ -460,7 +460,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Asinh,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kAsinh),
+    testing::Combine(testing::Values(builtin::Function::kAsinh),
                      testing::ValuesIn(Concat(AsinhCases<AFloat>(),  //
                                               AsinhCases<f32>(),
                                               AsinhCases<f16>()))));
@@ -482,7 +482,7 @@
     Ceil,
     ResolverConstEvalBuiltinTest,
     testing::Combine(
-        testing::Values(sem::BuiltinType::kCeil),
+        testing::Values(builtin::Function::kCeil),
         testing::ValuesIn(Concat(CeilCases<AFloat>(), CeilCases<f32>(), CeilCases<f16>()))));
 
 template <typename T>
@@ -512,7 +512,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Clamp,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kClamp),
+    testing::Combine(testing::Values(builtin::Function::kClamp),
                      testing::ValuesIn(Concat(ClampCases<AInt>(),  //
                                               ClampCases<i32>(),
                                               ClampCases<u32>(),
@@ -535,7 +535,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Cos,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kCos),
+    testing::Combine(testing::Values(builtin::Function::kCos),
                      testing::ValuesIn(Concat(CosCases<AFloat>(),  //
                                               CosCases<f32>(),
                                               CosCases<f16>()))));
@@ -561,7 +561,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Cosh,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kCosh),
+    testing::Combine(testing::Values(builtin::Function::kCosh),
                      testing::ValuesIn(Concat(CoshCases<AFloat>(),  //
                                               CoshCases<f32>(),
                                               CoshCases<f16>()))));
@@ -608,7 +608,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     CountLeadingZeros,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kCountLeadingZeros),
+    testing::Combine(testing::Values(builtin::Function::kCountLeadingZeros),
                      testing::ValuesIn(Concat(CountLeadingZerosCases<i32>(),  //
                                               CountLeadingZerosCases<u32>()))));
 
@@ -654,7 +654,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     CountTrailingZeros,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kCountTrailingZeros),
+    testing::Combine(testing::Values(builtin::Function::kCountTrailingZeros),
                      testing::ValuesIn(Concat(CountTrailingZerosCases<i32>(),  //
                                               CountTrailingZerosCases<u32>()))));
 
@@ -691,7 +691,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     CountOneBits,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kCountOneBits),
+    testing::Combine(testing::Values(builtin::Function::kCountOneBits),
                      testing::ValuesIn(Concat(CountOneBitsCases<i32>(),  //
                                               CountOneBitsCases<u32>()))));
 
@@ -790,7 +790,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Cross,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kCross),
+    testing::Combine(testing::Values(builtin::Function::kCross),
                      testing::ValuesIn(Concat(CrossCases<AFloat>(),  //
                                               CrossCases<f32>(),     //
                                               CrossCases<f16>()))));
@@ -817,7 +817,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Distance,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kDistance),
+    testing::Combine(testing::Values(builtin::Function::kDistance),
                      testing::ValuesIn(Concat(DistanceCases<AFloat>(),  //
                                               DistanceCases<f32>(),     //
                                               DistanceCases<f16>()))));
@@ -865,7 +865,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Dot,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kDot),
+    testing::Combine(testing::Values(builtin::Function::kDot),
                      testing::ValuesIn(Concat(DotCases<AInt>(),    //
                                               DotCases<i32>(),     //
                                               DotCases<u32>(),     //
@@ -945,7 +945,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Determinant,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kDeterminant),
+    testing::Combine(testing::Values(builtin::Function::kDeterminant),
                      testing::ValuesIn(Concat(DeterminantCases<AFloat>(),  //
                                               DeterminantCases<f32>(),     //
                                               DeterminantCases<f16>()))));
@@ -1027,7 +1027,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     FaceForward,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kFaceForward),
+    testing::Combine(testing::Values(builtin::Function::kFaceForward),
                      testing::ValuesIn(Concat(FaceForwardCases<AFloat>(),  //
                                               FaceForwardCases<f32>(),     //
                                               FaceForwardCases<f16>()))));
@@ -1090,7 +1090,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     FirstLeadingBit,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kFirstLeadingBit),
+    testing::Combine(testing::Values(builtin::Function::kFirstLeadingBit),
                      testing::ValuesIn(Concat(FirstLeadingBitCases<i32>(),  //
                                               FirstLeadingBitCases<u32>()))));
 
@@ -1123,7 +1123,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     FirstTrailingBit,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kFirstTrailingBit),
+    testing::Combine(testing::Values(builtin::Function::kFirstTrailingBit),
                      testing::ValuesIn(Concat(FirstTrailingBitCases<i32>(),  //
                                               FirstTrailingBitCases<u32>()))));
 
@@ -1143,7 +1143,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Floor,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kFloor),
+    testing::Combine(testing::Values(builtin::Function::kFloor),
                      testing::ValuesIn(Concat(FloorCases<AFloat>(),  //
                                               FloorCases<f32>(),
                                               FloorCases<f16>()))));
@@ -1167,7 +1167,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Fma,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kFma),
+    testing::Combine(testing::Values(builtin::Function::kFma),
                      testing::ValuesIn(Concat(FmaCases<AFloat>(),  //
                                               FmaCases<f32>(),
                                               FmaCases<f16>()))));
@@ -1199,7 +1199,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Fract,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kFract),
+    testing::Combine(testing::Values(builtin::Function::kFract),
                      testing::ValuesIn(Concat(FractCases<AFloat>(),  //
                                               FractCases<f32>(),
                                               FractCases<f16>()))));
@@ -1256,7 +1256,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Frexp,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kFrexp),
+    testing::Combine(testing::Values(builtin::Function::kFrexp),
                      testing::ValuesIn(Concat(FrexpCases<AFloat>(),  //
                                               FrexpCases<f32>(),     //
                                               FrexpCases<f16>()))));
@@ -1338,7 +1338,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     InsertBits,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kInsertBits),
+    testing::Combine(testing::Values(builtin::Function::kInsertBits),
                      testing::ValuesIn(Concat(InsertBitsCases<i32>(),  //
                                               InsertBitsCases<u32>()))));
 
@@ -1358,7 +1358,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     InverseSqrt,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kInverseSqrt),
+    testing::Combine(testing::Values(builtin::Function::kInverseSqrt),
                      testing::ValuesIn(Concat(InverseSqrtCases<AFloat>(),  //
                                               InverseSqrtCases<f32>(),
                                               InverseSqrtCases<f16>()))));
@@ -1377,7 +1377,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     DegreesAFloat,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kDegrees),
+    testing::Combine(testing::Values(builtin::Function::kDegrees),
                      testing::ValuesIn(DegreesAFloatCases<AFloat>())));
 
 template <typename T>
@@ -1394,7 +1394,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     DegreesF32,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kDegrees),
+    testing::Combine(testing::Values(builtin::Function::kDegrees),
                      testing::ValuesIn(DegreesF32Cases<f32>())));
 
 template <typename T>
@@ -1411,7 +1411,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     DegreesF16,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kDegrees),
+    testing::Combine(testing::Values(builtin::Function::kDegrees),
                      testing::ValuesIn(DegreesF16Cases<f16>())));
 
 template <typename T>
@@ -1428,7 +1428,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Exp,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kExp),
+    testing::Combine(testing::Values(builtin::Function::kExp),
                      testing::ValuesIn(Concat(ExpCases<AFloat>(),  //
                                               ExpCases<f32>(),
                                               ExpCases<f16>()))));
@@ -1449,7 +1449,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Exp2,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kExp2),
+    testing::Combine(testing::Values(builtin::Function::kExp2),
                      testing::ValuesIn(Concat(Exp2Cases<AFloat>(),  //
                                               Exp2Cases<f32>(),
                                               Exp2Cases<f16>()))));
@@ -1546,7 +1546,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     ExtractBits,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kExtractBits),
+    testing::Combine(testing::Values(builtin::Function::kExtractBits),
                      testing::ValuesIn(Concat(ExtractBitsCases<i32>(),  //
                                               ExtractBitsCases<u32>()))));
 
@@ -1610,7 +1610,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Ldexp,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kLdexp),
+    testing::Combine(testing::Values(builtin::Function::kLdexp),
                      testing::ValuesIn(Concat(LdexpCases<AFloat>(),  //
                                               LdexpCases<f32>(),
                                               LdexpCases<f16>()))));
@@ -1669,7 +1669,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Length,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kLength),
+    testing::Combine(testing::Values(builtin::Function::kLength),
                      testing::ValuesIn(Concat(LengthCases<AFloat>(),  //
                                               LengthCases<f32>(),
                                               LengthCases<f16>()))));
@@ -1685,7 +1685,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Log,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kLog),
+    testing::Combine(testing::Values(builtin::Function::kLog),
                      testing::ValuesIn(Concat(LogCases<AFloat>(),  //
                                               LogCases<f32>(),
                                               LogCases<f16>()))));
@@ -1698,7 +1698,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     LogF16,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kLog),
+    testing::Combine(testing::Values(builtin::Function::kLog),
                      testing::ValuesIn(LogF16Cases<f16>())));
 template <typename T>
 std::vector<Case> LogF32Cases() {
@@ -1709,7 +1709,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     LogF32,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kLog),
+    testing::Combine(testing::Values(builtin::Function::kLog),
                      testing::ValuesIn(LogF32Cases<f32>())));
 
 template <typename T>
@@ -1721,7 +1721,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     LogAbstract,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kLog),
+    testing::Combine(testing::Values(builtin::Function::kLog),
                      testing::ValuesIn(LogAbstractCases<AFloat>())));
 
 template <typename T>
@@ -1739,7 +1739,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Log2,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kLog2),
+    testing::Combine(testing::Values(builtin::Function::kLog2),
                      testing::ValuesIn(Concat(Log2Cases<AFloat>(),  //
                                               Log2Cases<f32>(),
                                               Log2Cases<f16>()))));
@@ -1752,7 +1752,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Log2F16,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kLog2),
+    testing::Combine(testing::Values(builtin::Function::kLog2),
                      testing::ValuesIn(Log2F16Cases<f16>())));
 template <typename T>
 std::vector<Case> Log2F32Cases() {
@@ -1763,7 +1763,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Log2F32,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kLog2),
+    testing::Combine(testing::Values(builtin::Function::kLog2),
                      testing::ValuesIn(Log2F32Cases<f32>())));
 template <typename T>
 std::vector<Case> Log2AbstractCases() {
@@ -1774,7 +1774,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Log2Abstract,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kLog2),
+    testing::Combine(testing::Values(builtin::Function::kLog2),
                      testing::ValuesIn(Log2AbstractCases<AFloat>())));
 
 template <typename T>
@@ -1797,7 +1797,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Max,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kMax),
+    testing::Combine(testing::Values(builtin::Function::kMax),
                      testing::ValuesIn(Concat(MaxCases<AInt>(),  //
                                               MaxCases<i32>(),
                                               MaxCases<u32>(),
@@ -1823,7 +1823,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Min,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kMin),
+    testing::Combine(testing::Values(builtin::Function::kMin),
                      testing::ValuesIn(Concat(MinCases<AInt>(),  //
                                               MinCases<i32>(),
                                               MinCases<u32>(),
@@ -1913,7 +1913,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Mix,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kMix),
+    testing::Combine(testing::Values(builtin::Function::kMix),
                      testing::ValuesIn(Concat(MixCases<AFloat>(),  //
                                               MixCases<f32>(),     //
                                               MixCases<f16>()))));
@@ -1947,7 +1947,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Modf,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kModf),
+    testing::Combine(testing::Values(builtin::Function::kModf),
                      testing::ValuesIn(Concat(ModfCases<AFloat>(),  //
                                               ModfCases<f32>(),     //
                                               ModfCases<f16>()))));
@@ -1977,7 +1977,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Normalize,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kNormalize),
+    testing::Combine(testing::Values(builtin::Function::kNormalize),
                      testing::ValuesIn(Concat(NormalizeCases<AFloat>(),  //
                                               NormalizeCases<f32>(),     //
                                               NormalizeCases<f16>()))));
@@ -1997,7 +1997,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Pack4x8snorm,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kPack4X8Snorm),
+    testing::Combine(testing::Values(builtin::Function::kPack4X8Snorm),
                      testing::ValuesIn(Pack4x8snormCases())));
 
 std::vector<Case> Pack4x8unormCases() {
@@ -2014,7 +2014,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Pack4x8unorm,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kPack4X8Unorm),
+    testing::Combine(testing::Values(builtin::Function::kPack4X8Unorm),
                      testing::ValuesIn(Pack4x8unormCases())));
 
 std::vector<Case> Pack2x16floatCases() {
@@ -2035,7 +2035,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Pack2x16float,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kPack2X16Float),
+    testing::Combine(testing::Values(builtin::Function::kPack2X16Float),
                      testing::ValuesIn(Pack2x16floatCases())));
 
 std::vector<Case> Pack2x16snormCases() {
@@ -2053,7 +2053,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Pack2x16snorm,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kPack2X16Snorm),
+    testing::Combine(testing::Values(builtin::Function::kPack2X16Snorm),
                      testing::ValuesIn(Pack2x16snormCases())));
 
 std::vector<Case> Pack2x16unormCases() {
@@ -2067,7 +2067,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Pack2x16unorm,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kPack2X16Unorm),
+    testing::Combine(testing::Values(builtin::Function::kPack2X16Unorm),
                      testing::ValuesIn(Pack2x16unormCases())));
 
 template <typename T>
@@ -2113,7 +2113,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Pow,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kPow),
+    testing::Combine(testing::Values(builtin::Function::kPow),
                      testing::ValuesIn(Concat(PowCases<AFloat>(),  //
                                               PowCases<f32>(),     //
                                               PowCases<f16>()))));
@@ -2160,7 +2160,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     ReverseBits,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kReverseBits),
+    testing::Combine(testing::Values(builtin::Function::kReverseBits),
                      testing::ValuesIn(Concat(ReverseBitsCases<i32>(),  //
                                               ReverseBitsCases<u32>()))));
 
@@ -2212,7 +2212,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Reflect,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kReflect),
+    testing::Combine(testing::Values(builtin::Function::kReflect),
                      testing::ValuesIn(Concat(ReflectCases<AFloat>(),  //
                                               ReflectCases<f32>(),     //
                                               ReflectCases<f16>()))));
@@ -2294,7 +2294,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Refract,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kRefract),
+    testing::Combine(testing::Values(builtin::Function::kRefract),
                      testing::ValuesIn(Concat(RefractCases<AFloat>(),  //
                                               RefractCases<f32>(),     //
                                               RefractCases<f16>()))));
@@ -2313,7 +2313,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Radians,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kRadians),
+    testing::Combine(testing::Values(builtin::Function::kRadians),
                      testing::ValuesIn(Concat(RadiansCases<AFloat>(),  //
                                               RadiansCases<f32>()))));
 
@@ -2331,7 +2331,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     RadiansF16,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kRadians),
+    testing::Combine(testing::Values(builtin::Function::kRadians),
                      testing::ValuesIn(RadiansF16Cases<f16>())));
 
 template <typename T>
@@ -2357,7 +2357,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Round,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kRound),
+    testing::Combine(testing::Values(builtin::Function::kRound),
                      testing::ValuesIn(Concat(RoundCases<AFloat>(),  //
                                               RoundCases<f32>(),
                                               RoundCases<f16>()))));
@@ -2382,7 +2382,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Saturate,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kSaturate),
+    testing::Combine(testing::Values(builtin::Function::kSaturate),
                      testing::ValuesIn(Concat(SaturateCases<AFloat>(),  //
                                               SaturateCases<f32>(),
                                               SaturateCases<f16>()))));
@@ -2424,7 +2424,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Select,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kSelect),
+    testing::Combine(testing::Values(builtin::Function::kSelect),
                      testing::ValuesIn(Concat(SelectCases<AInt>(),  //
                                               SelectCases<i32>(),
                                               SelectCases<u32>(),
@@ -2465,7 +2465,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Sign,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kSign),
+    testing::Combine(testing::Values(builtin::Function::kSign),
                      testing::ValuesIn(Concat(SignCases<AInt>(),  //
                                               SignCases<i32>(),
                                               SignCases<AFloat>(),
@@ -2487,7 +2487,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Sin,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kSin),
+    testing::Combine(testing::Values(builtin::Function::kSin),
                      testing::ValuesIn(Concat(SinCases<AFloat>(),  //
                                               SinCases<f32>(),
                                               SinCases<f16>()))));
@@ -2512,7 +2512,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Sinh,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kSinh),
+    testing::Combine(testing::Values(builtin::Function::kSinh),
                      testing::ValuesIn(Concat(SinhCases<AFloat>(),  //
                                               SinhCases<f32>(),
                                               SinhCases<f16>()))));
@@ -2545,7 +2545,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Smoothstep,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kSmoothstep),
+    testing::Combine(testing::Values(builtin::Function::kSmoothstep),
                      testing::ValuesIn(Concat(SmoothstepCases<AFloat>(),  //
                                               SmoothstepCases<f32>(),
                                               SmoothstepCases<f16>()))));
@@ -2577,7 +2577,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Step,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kStep),
+    testing::Combine(testing::Values(builtin::Function::kStep),
                      testing::ValuesIn(Concat(StepCases<AFloat>(),  //
                                               StepCases<f32>(),
                                               StepCases<f16>()))));
@@ -2598,7 +2598,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Sqrt,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kSqrt),
+    testing::Combine(testing::Values(builtin::Function::kSqrt),
                      testing::ValuesIn(Concat(SqrtCases<AFloat>(),  //
                                               SqrtCases<f32>(),
                                               SqrtCases<f16>()))));
@@ -2617,7 +2617,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Tan,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kTan),
+    testing::Combine(testing::Values(builtin::Function::kTan),
                      testing::ValuesIn(Concat(TanCases<AFloat>(),  //
                                               TanCases<f32>(),
                                               TanCases<f16>()))));
@@ -2637,7 +2637,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Tanh,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kTanh),
+    testing::Combine(testing::Values(builtin::Function::kTanh),
                      testing::ValuesIn(Concat(TanhCases<AFloat>(),  //
                                               TanhCases<f32>(),
                                               TanhCases<f16>()))));
@@ -2703,7 +2703,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Transpose,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kTranspose),
+    testing::Combine(testing::Values(builtin::Function::kTranspose),
                      testing::ValuesIn(Concat(TransposeCases<AFloat>(),  //
                                               TransposeCases<f32>(),
                                               TransposeCases<f16>()))));
@@ -2721,7 +2721,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Trunc,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kTrunc),
+    testing::Combine(testing::Values(builtin::Function::kTrunc),
                      testing::ValuesIn(Concat(TruncCases<AFloat>(),  //
                                               TruncCases<f32>(),
                                               TruncCases<f16>()))));
@@ -2742,7 +2742,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Unpack4x8snorm,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kUnpack4X8Snorm),
+    testing::Combine(testing::Values(builtin::Function::kUnpack4X8Snorm),
                      testing::ValuesIn(Unpack4x8snormCases())));
 
 std::vector<Case> Unpack4x8unormCases() {
@@ -2759,7 +2759,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Unpack4x8unorm,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kUnpack4X8Unorm),
+    testing::Combine(testing::Values(builtin::Function::kUnpack4X8Unorm),
                      testing::ValuesIn(Unpack4x8unormCases())));
 
 std::vector<Case> Unpack2x16floatCases() {
@@ -2773,7 +2773,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Unpack2x16float,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kUnpack2X16Float),
+    testing::Combine(testing::Values(builtin::Function::kUnpack2X16Float),
                      testing::ValuesIn(Unpack2x16floatCases())));
 
 std::vector<Case> Unpack2x16snormCases() {
@@ -2791,7 +2791,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Unpack2x16snorm,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kUnpack2X16Snorm),
+    testing::Combine(testing::Values(builtin::Function::kUnpack2X16Snorm),
                      testing::ValuesIn(Unpack2x16snormCases())));
 
 std::vector<Case> Unpack2x16unormCases() {
@@ -2805,7 +2805,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Unpack2x16unorm,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kUnpack2X16Unorm),
+    testing::Combine(testing::Values(builtin::Function::kUnpack2X16Unorm),
                      testing::ValuesIn(Unpack2x16unormCases())));
 
 std::vector<Case> QuantizeToF16Cases() {
@@ -2864,7 +2864,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     QuantizeToF16,
     ResolverConstEvalBuiltinTest,
-    testing::Combine(testing::Values(sem::BuiltinType::kQuantizeToF16),
+    testing::Combine(testing::Values(builtin::Function::kQuantizeToF16),
                      testing::ValuesIn(QuantizeToF16Cases())));
 
 }  // namespace
diff --git a/src/tint/resolver/dependency_graph.cc b/src/tint/resolver/dependency_graph.cc
index f718a46..67eb430 100644
--- a/src/tint/resolver/dependency_graph.cc
+++ b/src/tint/resolver/dependency_graph.cc
@@ -440,7 +440,8 @@
         auto* resolved = scope_stack_.Get(to);
         if (!resolved) {
             auto s = symbols_.NameFor(to);
-            if (auto builtin_fn = sem::ParseBuiltinType(s); builtin_fn != sem::BuiltinType::kNone) {
+            if (auto builtin_fn = builtin::ParseFunction(s);
+                builtin_fn != builtin::Function::kNone) {
                 graph_.resolved_identifiers.Add(from, ResolvedIdentifier(builtin_fn));
                 return;
             }
@@ -838,7 +839,7 @@
                 return "<unknown>";
             });
     }
-    if (auto builtin_fn = BuiltinFunction(); builtin_fn != sem::BuiltinType::kNone) {
+    if (auto builtin_fn = BuiltinFunction(); builtin_fn != builtin::Function::kNone) {
         return "builtin function '" + utils::ToString(builtin_fn) + "'";
     }
     if (auto builtin_ty = BuiltinType(); builtin_ty != builtin::Builtin::kUndefined) {
diff --git a/src/tint/resolver/dependency_graph.h b/src/tint/resolver/dependency_graph.h
index 429a47a..f58b2a2 100644
--- a/src/tint/resolver/dependency_graph.h
+++ b/src/tint/resolver/dependency_graph.h
@@ -22,11 +22,11 @@
 #include "src/tint/builtin/access.h"
 #include "src/tint/builtin/builtin.h"
 #include "src/tint/builtin/builtin_value.h"
+#include "src/tint/builtin/function.h"
 #include "src/tint/builtin/interpolation_sampling.h"
 #include "src/tint/builtin/interpolation_type.h"
 #include "src/tint/builtin/texel_format.h"
 #include "src/tint/diagnostic/diagnostic.h"
-#include "src/tint/sem/builtin_type.h"
 #include "src/tint/symbol_table.h"
 #include "src/tint/utils/hashmap.h"
 
@@ -44,7 +44,7 @@
 /// - const ast::TypeDecl*  (as const ast::Node*)
 /// - const ast::Variable*  (as const ast::Node*)
 /// - const ast::Function*  (as const ast::Node*)
-/// - sem::BuiltinType
+/// - builtin::Function
 /// - builtin::Access
 /// - builtin::AddressSpace
 /// - builtin::Builtin
@@ -75,13 +75,13 @@
         return nullptr;
     }
 
-    /// @return the builtin function if the ResolvedIdentifier holds sem::BuiltinType, otherwise
-    /// sem::BuiltinType::kNone
-    sem::BuiltinType BuiltinFunction() const {
-        if (auto n = std::get_if<sem::BuiltinType>(&value_)) {
+    /// @return the builtin function if the ResolvedIdentifier holds builtin::Function, otherwise
+    /// builtin::Function::kNone
+    builtin::Function BuiltinFunction() const {
+        if (auto n = std::get_if<builtin::Function>(&value_)) {
             return *n;
         }
-        return sem::BuiltinType::kNone;
+        return builtin::Function::kNone;
     }
 
     /// @return the access if the ResolvedIdentifier holds builtin::Access, otherwise
@@ -172,7 +172,7 @@
   private:
     std::variant<UnresolvedIdentifier,
                  const ast::Node*,
-                 sem::BuiltinType,
+                 builtin::Function,
                  builtin::Access,
                  builtin::AddressSpace,
                  builtin::Builtin,
diff --git a/src/tint/resolver/dependency_graph_test.cc b/src/tint/resolver/dependency_graph_test.cc
index c81c336..c9ce3b8 100644
--- a/src/tint/resolver/dependency_graph_test.cc
+++ b/src/tint/resolver/dependency_graph_test.cc
@@ -1181,7 +1181,7 @@
 namespace resolve_to_builtin_func {
 
 using ResolverDependencyGraphResolveToBuiltinFunc =
-    ResolverDependencyGraphTestWithParam<std::tuple<SymbolUseKind, sem::BuiltinType>>;
+    ResolverDependencyGraphTestWithParam<std::tuple<SymbolUseKind, builtin::Function>>;
 
 TEST_P(ResolverDependencyGraphResolveToBuiltinFunc, Resolve) {
     const auto use = std::get<0>(GetParam());
@@ -1200,17 +1200,17 @@
 INSTANTIATE_TEST_SUITE_P(Types,
                          ResolverDependencyGraphResolveToBuiltinFunc,
                          testing::Combine(testing::ValuesIn(kTypeUseKinds),
-                                          testing::ValuesIn(sem::kBuiltinTypes)));
+                                          testing::ValuesIn(builtin::kFunctions)));
 
 INSTANTIATE_TEST_SUITE_P(Values,
                          ResolverDependencyGraphResolveToBuiltinFunc,
                          testing::Combine(testing::ValuesIn(kValueUseKinds),
-                                          testing::ValuesIn(sem::kBuiltinTypes)));
+                                          testing::ValuesIn(builtin::kFunctions)));
 
 INSTANTIATE_TEST_SUITE_P(Functions,
                          ResolverDependencyGraphResolveToBuiltinFunc,
                          testing::Combine(testing::ValuesIn(kFuncUseKinds),
-                                          testing::ValuesIn(sem::kBuiltinTypes)));
+                                          testing::ValuesIn(builtin::kFunctions)));
 
 }  // namespace resolve_to_builtin_func
 
diff --git a/src/tint/resolver/intrinsic_table.cc b/src/tint/resolver/intrinsic_table.cc
index e8fe271..8bd12e2 100644
--- a/src/tint/resolver/intrinsic_table.cc
+++ b/src/tint/resolver/intrinsic_table.cc
@@ -1096,7 +1096,7 @@
   public:
     explicit Impl(ProgramBuilder& builder);
 
-    Builtin Lookup(sem::BuiltinType builtin_type,
+    Builtin Lookup(builtin::Function builtin_type,
                    utils::VectorRef<const type::Type*> args,
                    sem::EvaluationStage earliest_eval_stage,
                    const Source& source) override;
@@ -1264,11 +1264,11 @@
 
 Impl::Impl(ProgramBuilder& b) : builder(b) {}
 
-Impl::Builtin Impl::Lookup(sem::BuiltinType builtin_type,
+Impl::Builtin Impl::Lookup(builtin::Function builtin_type,
                            utils::VectorRef<const type::Type*> args,
                            sem::EvaluationStage earliest_eval_stage,
                            const Source& source) {
-    const char* intrinsic_name = sem::str(builtin_type);
+    const char* intrinsic_name = builtin::str(builtin_type);
 
     // Generates an error when no overloads match the provided arguments
     auto on_no_match = [&](utils::VectorRef<Candidate> candidates) {
diff --git a/src/tint/resolver/intrinsic_table.h b/src/tint/resolver/intrinsic_table.h
index 515e839..78e2e7a 100644
--- a/src/tint/resolver/intrinsic_table.h
+++ b/src/tint/resolver/intrinsic_table.h
@@ -92,7 +92,7 @@
     ///        after shader creation time (sem::EvaluationStage::kConstant).
     /// @param source the source of the builtin call
     /// @return the semantic builtin if found, otherwise nullptr
-    virtual Builtin Lookup(sem::BuiltinType type,
+    virtual Builtin Lookup(builtin::Function type,
                            utils::VectorRef<const type::Type*> args,
                            sem::EvaluationStage earliest_eval_stage,
                            const Source& source) = 0;
diff --git a/src/tint/resolver/intrinsic_table_test.cc b/src/tint/resolver/intrinsic_table_test.cc
index 7f0399d..c842af5 100644
--- a/src/tint/resolver/intrinsic_table_test.cc
+++ b/src/tint/resolver/intrinsic_table_test.cc
@@ -37,7 +37,6 @@
 
 using ::testing::HasSubstr;
 
-using BuiltinType = sem::BuiltinType;
 using Parameter = sem::Parameter;
 using ParameterUsage = sem::ParameterUsage;
 
@@ -54,11 +53,11 @@
 
 TEST_F(IntrinsicTableTest, MatchF32) {
     auto* f32 = create<type::F32>();
-    auto result = table->Lookup(BuiltinType::kCos, utils::Vector{f32},
+    auto result = table->Lookup(builtin::Function::kCos, utils::Vector{f32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kCos);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kCos);
     EXPECT_EQ(result.sem->ReturnType(), f32);
     ASSERT_EQ(result.sem->Parameters().Length(), 1u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32);
@@ -66,7 +65,7 @@
 
 TEST_F(IntrinsicTableTest, MismatchF32) {
     auto* i32 = create<type::I32>();
-    auto result = table->Lookup(BuiltinType::kCos, utils::Vector{i32},
+    auto result = table->Lookup(builtin::Function::kCos, utils::Vector{i32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(result.sem, nullptr);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -76,11 +75,11 @@
     auto* f32 = create<type::F32>();
     auto* u32 = create<type::U32>();
     auto* vec2_f32 = create<type::Vector>(f32, 2u);
-    auto result = table->Lookup(BuiltinType::kUnpack2X16Float, utils::Vector{u32},
+    auto result = table->Lookup(builtin::Function::kUnpack2X16Float, utils::Vector{u32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kUnpack2X16Float);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kUnpack2X16Float);
     EXPECT_EQ(result.sem->ReturnType(), vec2_f32);
     ASSERT_EQ(result.sem->Parameters().Length(), 1u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), u32);
@@ -88,7 +87,7 @@
 
 TEST_F(IntrinsicTableTest, MismatchU32) {
     auto* f32 = create<type::F32>();
-    auto result = table->Lookup(BuiltinType::kUnpack2X16Float, utils::Vector{f32},
+    auto result = table->Lookup(builtin::Function::kUnpack2X16Float, utils::Vector{f32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(result.sem, nullptr);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -99,11 +98,11 @@
     auto* i32 = create<type::I32>();
     auto* vec4_f32 = create<type::Vector>(f32, 4u);
     auto* tex = create<type::SampledTexture>(type::TextureDimension::k1d, f32);
-    auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, i32, i32},
+    auto result = table->Lookup(builtin::Function::kTextureLoad, utils::Vector{tex, i32, i32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kTextureLoad);
     EXPECT_EQ(result.sem->ReturnType(), vec4_f32);
     ASSERT_EQ(result.sem->Parameters().Length(), 3u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
@@ -117,7 +116,7 @@
 TEST_F(IntrinsicTableTest, MismatchI32) {
     auto* f32 = create<type::F32>();
     auto* tex = create<type::SampledTexture>(type::TextureDimension::k1d, f32);
-    auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, f32},
+    auto result = table->Lookup(builtin::Function::kTextureLoad, utils::Vector{tex, f32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(result.sem, nullptr);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -125,11 +124,11 @@
 
 TEST_F(IntrinsicTableTest, MatchIU32AsI32) {
     auto* i32 = create<type::I32>();
-    auto result = table->Lookup(BuiltinType::kCountOneBits, utils::Vector{i32},
+    auto result = table->Lookup(builtin::Function::kCountOneBits, utils::Vector{i32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kCountOneBits);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kCountOneBits);
     EXPECT_EQ(result.sem->ReturnType(), i32);
     ASSERT_EQ(result.sem->Parameters().Length(), 1u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), i32);
@@ -137,11 +136,11 @@
 
 TEST_F(IntrinsicTableTest, MatchIU32AsU32) {
     auto* u32 = create<type::U32>();
-    auto result = table->Lookup(BuiltinType::kCountOneBits, utils::Vector{u32},
+    auto result = table->Lookup(builtin::Function::kCountOneBits, utils::Vector{u32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kCountOneBits);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kCountOneBits);
     EXPECT_EQ(result.sem->ReturnType(), u32);
     ASSERT_EQ(result.sem->Parameters().Length(), 1u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), u32);
@@ -149,7 +148,7 @@
 
 TEST_F(IntrinsicTableTest, MismatchIU32) {
     auto* f32 = create<type::F32>();
-    auto result = table->Lookup(BuiltinType::kCountOneBits, utils::Vector{f32},
+    auto result = table->Lookup(builtin::Function::kCountOneBits, utils::Vector{f32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(result.sem, nullptr);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -157,11 +156,11 @@
 
 TEST_F(IntrinsicTableTest, MatchFIU32AsI32) {
     auto* i32 = create<type::I32>();
-    auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{i32, i32, i32},
+    auto result = table->Lookup(builtin::Function::kClamp, utils::Vector{i32, i32, i32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kClamp);
     EXPECT_EQ(result.sem->ReturnType(), i32);
     ASSERT_EQ(result.sem->Parameters().Length(), 3u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), i32);
@@ -171,11 +170,11 @@
 
 TEST_F(IntrinsicTableTest, MatchFIU32AsU32) {
     auto* u32 = create<type::U32>();
-    auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{u32, u32, u32},
+    auto result = table->Lookup(builtin::Function::kClamp, utils::Vector{u32, u32, u32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kClamp);
     EXPECT_EQ(result.sem->ReturnType(), u32);
     ASSERT_EQ(result.sem->Parameters().Length(), 3u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), u32);
@@ -185,11 +184,11 @@
 
 TEST_F(IntrinsicTableTest, MatchFIU32AsF32) {
     auto* f32 = create<type::F32>();
-    auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{f32, f32, f32},
+    auto result = table->Lookup(builtin::Function::kClamp, utils::Vector{f32, f32, f32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kClamp);
     EXPECT_EQ(result.sem->ReturnType(), f32);
     ASSERT_EQ(result.sem->Parameters().Length(), 3u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32);
@@ -199,7 +198,7 @@
 
 TEST_F(IntrinsicTableTest, MismatchFIU32) {
     auto* bool_ = create<type::Bool>();
-    auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{bool_, bool_, bool_},
+    auto result = table->Lookup(builtin::Function::kClamp, utils::Vector{bool_, bool_, bool_},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(result.sem, nullptr);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -208,11 +207,11 @@
 TEST_F(IntrinsicTableTest, MatchBool) {
     auto* f32 = create<type::F32>();
     auto* bool_ = create<type::Bool>();
-    auto result = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, bool_},
+    auto result = table->Lookup(builtin::Function::kSelect, utils::Vector{f32, f32, bool_},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kSelect);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kSelect);
     EXPECT_EQ(result.sem->ReturnType(), f32);
     ASSERT_EQ(result.sem->Parameters().Length(), 3u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32);
@@ -222,7 +221,7 @@
 
 TEST_F(IntrinsicTableTest, MismatchBool) {
     auto* f32 = create<type::F32>();
-    auto result = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, f32},
+    auto result = table->Lookup(builtin::Function::kSelect, utils::Vector{f32, f32, f32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(result.sem, nullptr);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -233,11 +232,11 @@
     auto* atomicI32 = create<type::Atomic>(i32);
     auto* ptr = create<type::Pointer>(atomicI32, builtin::AddressSpace::kWorkgroup,
                                       builtin::Access::kReadWrite);
-    auto result = table->Lookup(BuiltinType::kAtomicLoad, utils::Vector{ptr},
+    auto result = table->Lookup(builtin::Function::kAtomicLoad, utils::Vector{ptr},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kAtomicLoad);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kAtomicLoad);
     EXPECT_EQ(result.sem->ReturnType(), i32);
     ASSERT_EQ(result.sem->Parameters().Length(), 1u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), ptr);
@@ -246,7 +245,7 @@
 TEST_F(IntrinsicTableTest, MismatchPointer) {
     auto* i32 = create<type::I32>();
     auto* atomicI32 = create<type::Atomic>(i32);
-    auto result = table->Lookup(BuiltinType::kAtomicLoad, utils::Vector{atomicI32},
+    auto result = table->Lookup(builtin::Function::kAtomicLoad, utils::Vector{atomicI32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(result.sem, nullptr);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -257,11 +256,11 @@
         create<type::Array>(create<type::U32>(), create<type::RuntimeArrayCount>(), 4u, 4u, 4u, 4u);
     auto* arr_ptr =
         create<type::Pointer>(arr, builtin::AddressSpace::kStorage, builtin::Access::kReadWrite);
-    auto result = table->Lookup(BuiltinType::kArrayLength, utils::Vector{arr_ptr},
+    auto result = table->Lookup(builtin::Function::kArrayLength, utils::Vector{arr_ptr},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kArrayLength);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kArrayLength);
     EXPECT_TRUE(result.sem->ReturnType()->Is<type::U32>());
     ASSERT_EQ(result.sem->Parameters().Length(), 1u);
     auto* param_type = result.sem->Parameters()[0]->Type();
@@ -271,7 +270,7 @@
 
 TEST_F(IntrinsicTableTest, MismatchArray) {
     auto* f32 = create<type::F32>();
-    auto result = table->Lookup(BuiltinType::kArrayLength, utils::Vector{f32},
+    auto result = table->Lookup(builtin::Function::kArrayLength, utils::Vector{f32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(result.sem, nullptr);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -283,11 +282,12 @@
     auto* vec4_f32 = create<type::Vector>(f32, 4u);
     auto* tex = create<type::SampledTexture>(type::TextureDimension::k2d, f32);
     auto* sampler = create<type::Sampler>(type::SamplerKind::kSampler);
-    auto result = table->Lookup(BuiltinType::kTextureSample, utils::Vector{tex, sampler, vec2_f32},
-                                sem::EvaluationStage::kConstant, Source{});
+    auto result =
+        table->Lookup(builtin::Function::kTextureSample, utils::Vector{tex, sampler, vec2_f32},
+                      sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureSample);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kTextureSample);
     EXPECT_EQ(result.sem->ReturnType(), vec4_f32);
     ASSERT_EQ(result.sem->Parameters().Length(), 3u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
@@ -302,8 +302,9 @@
     auto* f32 = create<type::F32>();
     auto* vec2_f32 = create<type::Vector>(f32, 2u);
     auto* tex = create<type::SampledTexture>(type::TextureDimension::k2d, f32);
-    auto result = table->Lookup(BuiltinType::kTextureSample, utils::Vector{tex, f32, vec2_f32},
-                                sem::EvaluationStage::kConstant, Source{});
+    auto result =
+        table->Lookup(builtin::Function::kTextureSample, utils::Vector{tex, f32, vec2_f32},
+                      sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(result.sem, nullptr);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
 }
@@ -314,11 +315,11 @@
     auto* vec2_i32 = create<type::Vector>(i32, 2u);
     auto* vec4_f32 = create<type::Vector>(f32, 4u);
     auto* tex = create<type::SampledTexture>(type::TextureDimension::k2d, f32);
-    auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32},
+    auto result = table->Lookup(builtin::Function::kTextureLoad, utils::Vector{tex, vec2_i32, i32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kTextureLoad);
     EXPECT_EQ(result.sem->ReturnType(), vec4_f32);
     ASSERT_EQ(result.sem->Parameters().Length(), 3u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
@@ -335,11 +336,11 @@
     auto* vec2_i32 = create<type::Vector>(i32, 2u);
     auto* vec4_f32 = create<type::Vector>(f32, 4u);
     auto* tex = create<type::MultisampledTexture>(type::TextureDimension::k2d, f32);
-    auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32},
+    auto result = table->Lookup(builtin::Function::kTextureLoad, utils::Vector{tex, vec2_i32, i32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kTextureLoad);
     EXPECT_EQ(result.sem->ReturnType(), vec4_f32);
     ASSERT_EQ(result.sem->Parameters().Length(), 3u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
@@ -355,11 +356,11 @@
     auto* i32 = create<type::I32>();
     auto* vec2_i32 = create<type::Vector>(i32, 2u);
     auto* tex = create<type::DepthTexture>(type::TextureDimension::k2d);
-    auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32},
+    auto result = table->Lookup(builtin::Function::kTextureLoad, utils::Vector{tex, vec2_i32, i32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kTextureLoad);
     EXPECT_EQ(result.sem->ReturnType(), f32);
     ASSERT_EQ(result.sem->Parameters().Length(), 3u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
@@ -375,11 +376,11 @@
     auto* i32 = create<type::I32>();
     auto* vec2_i32 = create<type::Vector>(i32, 2u);
     auto* tex = create<type::DepthMultisampledTexture>(type::TextureDimension::k2d);
-    auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32, i32},
+    auto result = table->Lookup(builtin::Function::kTextureLoad, utils::Vector{tex, vec2_i32, i32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kTextureLoad);
     EXPECT_EQ(result.sem->ReturnType(), f32);
     ASSERT_EQ(result.sem->Parameters().Length(), 3u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
@@ -396,11 +397,11 @@
     auto* vec2_i32 = create<type::Vector>(i32, 2u);
     auto* vec4_f32 = create<type::Vector>(f32, 4u);
     auto* tex = create<type::ExternalTexture>();
-    auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{tex, vec2_i32},
+    auto result = table->Lookup(builtin::Function::kTextureLoad, utils::Vector{tex, vec2_i32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureLoad);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kTextureLoad);
     EXPECT_EQ(result.sem->ReturnType(), vec4_f32);
     ASSERT_EQ(result.sem->Parameters().Length(), 2u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
@@ -419,11 +420,12 @@
         create<type::StorageTexture>(type::TextureDimension::k2d, builtin::TexelFormat::kR32Float,
                                      builtin::Access::kWrite, subtype);
 
-    auto result = table->Lookup(BuiltinType::kTextureStore, utils::Vector{tex, vec2_i32, vec4_f32},
-                                sem::EvaluationStage::kConstant, Source{});
+    auto result =
+        table->Lookup(builtin::Function::kTextureStore, utils::Vector{tex, vec2_i32, vec4_f32},
+                      sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kTextureStore);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kTextureStore);
     EXPECT_TRUE(result.sem->ReturnType()->Is<type::Void>());
     ASSERT_EQ(result.sem->Parameters().Length(), 3u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), tex);
@@ -438,7 +440,7 @@
     auto* f32 = create<type::F32>();
     auto* i32 = create<type::I32>();
     auto* vec2_i32 = create<type::Vector>(i32, 2u);
-    auto result = table->Lookup(BuiltinType::kTextureLoad, utils::Vector{f32, vec2_i32},
+    auto result = table->Lookup(builtin::Function::kTextureLoad, utils::Vector{f32, vec2_i32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(result.sem, nullptr);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -446,7 +448,7 @@
 
 TEST_F(IntrinsicTableTest, ImplicitLoadOnReference) {
     auto* f32 = create<type::F32>();
-    auto result = table->Lookup(BuiltinType::kCos,
+    auto result = table->Lookup(builtin::Function::kCos,
                                 utils::Vector{
                                     create<type::Reference>(f32, builtin::AddressSpace::kFunction,
                                                             builtin::Access::kReadWrite),
@@ -454,7 +456,7 @@
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kCos);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kCos);
     EXPECT_EQ(result.sem->ReturnType(), f32);
     ASSERT_EQ(result.sem->Parameters().Length(), 1u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32);
@@ -462,11 +464,11 @@
 
 TEST_F(IntrinsicTableTest, MatchTemplateType) {
     auto* f32 = create<type::F32>();
-    auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{f32, f32, f32},
+    auto result = table->Lookup(builtin::Function::kClamp, utils::Vector{f32, f32, f32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kClamp);
     EXPECT_EQ(result.sem->ReturnType(), f32);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), f32);
     EXPECT_EQ(result.sem->Parameters()[1]->Type(), f32);
@@ -476,7 +478,7 @@
 TEST_F(IntrinsicTableTest, MismatchTemplateType) {
     auto* f32 = create<type::F32>();
     auto* u32 = create<type::U32>();
-    auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{f32, u32, f32},
+    auto result = table->Lookup(builtin::Function::kClamp, utils::Vector{f32, u32, f32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(result.sem, nullptr);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -485,11 +487,12 @@
 TEST_F(IntrinsicTableTest, MatchOpenSizeVector) {
     auto* f32 = create<type::F32>();
     auto* vec2_f32 = create<type::Vector>(f32, 2u);
-    auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{vec2_f32, vec2_f32, vec2_f32},
-                                sem::EvaluationStage::kConstant, Source{});
+    auto result =
+        table->Lookup(builtin::Function::kClamp, utils::Vector{vec2_f32, vec2_f32, vec2_f32},
+                      sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kClamp);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kClamp);
     EXPECT_EQ(result.sem->ReturnType(), vec2_f32);
     ASSERT_EQ(result.sem->Parameters().Length(), 3u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), vec2_f32);
@@ -501,7 +504,7 @@
     auto* f32 = create<type::F32>();
     auto* u32 = create<type::U32>();
     auto* vec2_f32 = create<type::Vector>(f32, 2u);
-    auto result = table->Lookup(BuiltinType::kClamp, utils::Vector{vec2_f32, u32, vec2_f32},
+    auto result = table->Lookup(builtin::Function::kClamp, utils::Vector{vec2_f32, u32, vec2_f32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(result.sem, nullptr);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -511,11 +514,11 @@
     auto* f32 = create<type::F32>();
     auto* vec3_f32 = create<type::Vector>(f32, 3u);
     auto* mat3_f32 = create<type::Matrix>(vec3_f32, 3u);
-    auto result = table->Lookup(BuiltinType::kDeterminant, utils::Vector{mat3_f32},
+    auto result = table->Lookup(builtin::Function::kDeterminant, utils::Vector{mat3_f32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kDeterminant);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kDeterminant);
     EXPECT_EQ(result.sem->ReturnType(), f32);
     ASSERT_EQ(result.sem->Parameters().Length(), 1u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), mat3_f32);
@@ -525,7 +528,7 @@
     auto* f32 = create<type::F32>();
     auto* vec2_f32 = create<type::Vector>(f32, 2u);
     auto* mat3x2_f32 = create<type::Matrix>(vec2_f32, 3u);
-    auto result = table->Lookup(BuiltinType::kDeterminant, utils::Vector{mat3x2_f32},
+    auto result = table->Lookup(builtin::Function::kDeterminant, utils::Vector{mat3x2_f32},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(result.sem, nullptr);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -534,12 +537,12 @@
 TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_Builtin_ConstantEval) {
     auto* af = create<type::AbstractFloat>();
     auto* bool_ = create<type::Bool>();
-    auto result = table->Lookup(BuiltinType::kSelect, utils::Vector{af, af, bool_},
+    auto result = table->Lookup(builtin::Function::kSelect, utils::Vector{af, af, bool_},
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
     EXPECT_EQ(result.sem->Stage(), sem::EvaluationStage::kConstant);
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kSelect);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kSelect);
     EXPECT_EQ(result.sem->ReturnType(), af);
     ASSERT_EQ(result.sem->Parameters().Length(), 3u);
     EXPECT_EQ(result.sem->Parameters()[0]->Type(), af);
@@ -551,12 +554,12 @@
     auto* af = create<type::AbstractFloat>();
     auto* bool_ref = create<type::Reference>(create<type::Bool>(), builtin::AddressSpace::kFunction,
                                              builtin::Access::kReadWrite);
-    auto result = table->Lookup(BuiltinType::kSelect, utils::Vector{af, af, bool_ref},
+    auto result = table->Lookup(builtin::Function::kSelect, utils::Vector{af, af, bool_ref},
                                 sem::EvaluationStage::kRuntime, Source{});
     ASSERT_NE(result.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
     EXPECT_EQ(result.sem->Stage(), sem::EvaluationStage::kConstant);
-    EXPECT_EQ(result.sem->Type(), BuiltinType::kSelect);
+    EXPECT_EQ(result.sem->Type(), builtin::Function::kSelect);
     EXPECT_TRUE(result.sem->ReturnType()->Is<type::F32>());
     ASSERT_EQ(result.sem->Parameters().Length(), 3u);
     EXPECT_TRUE(result.sem->Parameters()[0]->Type()->Is<type::F32>());
@@ -594,7 +597,7 @@
     // None of the arguments match, so expect the overloads with 2 parameters to
     // come first
     auto* bool_ = create<type::Bool>();
-    table->Lookup(BuiltinType::kTextureDimensions, utils::Vector{bool_, bool_},
+    table->Lookup(builtin::Function::kTextureDimensions, utils::Vector{bool_, bool_},
                   sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(Diagnostics().str(),
               R"(error: no matching call to textureDimensions(bool, bool)
@@ -633,7 +636,7 @@
 TEST_F(IntrinsicTableTest, OverloadOrderByMatchingParameter) {
     auto* tex = create<type::DepthTexture>(type::TextureDimension::k2d);
     auto* bool_ = create<type::Bool>();
-    table->Lookup(BuiltinType::kTextureDimensions, utils::Vector{tex, bool_},
+    table->Lookup(builtin::Function::kTextureDimensions, utils::Vector{tex, bool_},
                   sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(Diagnostics().str(),
               R"(error: no matching call to textureDimensions(texture_depth_2d, bool)
@@ -673,16 +676,16 @@
     auto* f32 = create<type::F32>();
     auto* vec2_f32 = create<type::Vector>(create<type::F32>(), 2u);
     auto* bool_ = create<type::Bool>();
-    auto a = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, bool_},
+    auto a = table->Lookup(builtin::Function::kSelect, utils::Vector{f32, f32, bool_},
                            sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(a.sem, nullptr) << Diagnostics().str();
 
-    auto b = table->Lookup(BuiltinType::kSelect, utils::Vector{f32, f32, bool_},
+    auto b = table->Lookup(builtin::Function::kSelect, utils::Vector{f32, f32, bool_},
                            sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(b.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
 
-    auto c = table->Lookup(BuiltinType::kSelect, utils::Vector{vec2_f32, vec2_f32, bool_},
+    auto c = table->Lookup(builtin::Function::kSelect, utils::Vector{vec2_f32, vec2_f32, bool_},
                            sem::EvaluationStage::kConstant, Source{});
     ASSERT_NE(c.sem, nullptr) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -1022,7 +1025,7 @@
     auto* f32 = create<type::F32>();
     utils::Vector<const type::Type*, 0> arg_tys;
     arg_tys.Resize(257, f32);
-    auto result = table->Lookup(BuiltinType::kAbs, std::move(arg_tys),
+    auto result = table->Lookup(builtin::Function::kAbs, std::move(arg_tys),
                                 sem::EvaluationStage::kConstant, Source{});
     ASSERT_EQ(result.sem, nullptr);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -1261,7 +1264,7 @@
     auto* arg_a = GetParam().arg_a(*this);
     auto* arg_b = GetParam().arg_b(*this);
     auto* arg_c = GetParam().arg_c(*this);
-    auto builtin = table->Lookup(sem::BuiltinType::kClamp, utils::Vector{arg_a, arg_b, arg_c},
+    auto builtin = table->Lookup(builtin::Function::kClamp, utils::Vector{arg_a, arg_b, arg_c},
                                  sem::EvaluationStage::kConstant, Source{{12, 34}});
 
     bool matched = builtin.sem != nullptr;
diff --git a/src/tint/resolver/materialize_test.cc b/src/tint/resolver/materialize_test.cc
index 839389a..115c4b8 100644
--- a/src/tint/resolver/materialize_test.cc
+++ b/src/tint/resolver/materialize_test.cc
@@ -939,7 +939,7 @@
             break;
         }
         case Method::kTintMaterializeBuiltin: {
-            auto* call = Call(sem::str(sem::BuiltinType::kTintMaterialize), abstract_expr());
+            auto* call = Call(builtin::str(builtin::Function::kTintMaterialize), abstract_expr());
             WrapInFunction(Decl(Const("c", call)));
             break;
         }
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index f51e5cc..597821f 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -2167,7 +2167,7 @@
                 });
         }
 
-        if (auto f = resolved->BuiltinFunction(); f != sem::BuiltinType::kNone) {
+        if (auto f = resolved->BuiltinFunction(); f != builtin::Function::kNone) {
             return BuiltinCall(expr, f, args);
         }
 
@@ -2239,7 +2239,7 @@
 
 template <size_t N>
 sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
-                                 sem::BuiltinType builtin_type,
+                                 builtin::Function builtin_type,
                                  utils::Vector<const sem::ValueExpression*, N>& args) {
     auto arg_stage = sem::EvaluationStage::kConstant;
     for (auto* arg : args) {
@@ -2255,7 +2255,7 @@
         }
     }
 
-    if (builtin_type == sem::BuiltinType::kTintMaterialize) {
+    if (builtin_type == builtin::Function::kTintMaterialize) {
         args[0] = Materialize(args[0]);
         if (!args[0]) {
             return nullptr;
@@ -2307,14 +2307,14 @@
         return nullptr;
     }
 
-    if (IsTextureBuiltin(builtin_type)) {
+    if (sem::IsTextureBuiltin(builtin_type)) {
         if (!validator_.TextureBuiltinFunction(call)) {
             return nullptr;
         }
         CollectTextureSamplerPairs(builtin.sem, call->Arguments());
     }
 
-    if (builtin_type == sem::BuiltinType::kWorkgroupUniformLoad) {
+    if (builtin_type == builtin::Function::kWorkgroupUniformLoad) {
         if (!validator_.WorkgroupUniformLoad(call)) {
             return nullptr;
         }
@@ -3050,7 +3050,7 @@
         return builder_->create<sem::TypeExpression>(expr, current_statement_, ty);
     }
 
-    if (resolved->BuiltinFunction() != sem::BuiltinType::kNone) {
+    if (resolved->BuiltinFunction() != builtin::Function::kNone) {
         AddError("missing '(' for builtin function call", expr->source.End());
         return nullptr;
     }
diff --git a/src/tint/resolver/resolver.h b/src/tint/resolver/resolver.h
index 8acf602..cab7b37 100644
--- a/src/tint/resolver/resolver.h
+++ b/src/tint/resolver/resolver.h
@@ -204,7 +204,7 @@
     sem::Expression* Identifier(const ast::IdentifierExpression*);
     template <size_t N>
     sem::Call* BuiltinCall(const ast::CallExpression*,
-                           sem::BuiltinType,
+                           builtin::Function,
                            utils::Vector<const sem::ValueExpression*, N>& args);
     sem::ValueExpression* Literal(const ast::LiteralExpression*);
     sem::ValueExpression* MemberAccessor(const ast::MemberAccessorExpression*);
diff --git a/src/tint/resolver/uniformity.cc b/src/tint/resolver/uniformity.cc
index 673c1c0..4b63523 100644
--- a/src/tint/resolver/uniformity.cc
+++ b/src/tint/resolver/uniformity.cc
@@ -1538,12 +1538,12 @@
                 // some texture sampling builtins, and atomics.
                 if (builtin->IsBarrier()) {
                     callsite_tag = {CallSiteTag::CallSiteRequiredToBeUniform, default_severity};
-                } else if (builtin->Type() == sem::BuiltinType::kWorkgroupUniformLoad) {
+                } else if (builtin->Type() == builtin::Function::kWorkgroupUniformLoad) {
                     callsite_tag = {CallSiteTag::CallSiteRequiredToBeUniform, default_severity};
                 } else if (builtin->IsDerivative() ||
-                           builtin->Type() == sem::BuiltinType::kTextureSample ||
-                           builtin->Type() == sem::BuiltinType::kTextureSampleBias ||
-                           builtin->Type() == sem::BuiltinType::kTextureSampleCompare) {
+                           builtin->Type() == builtin::Function::kTextureSample ||
+                           builtin->Type() == builtin::Function::kTextureSampleBias ||
+                           builtin->Type() == builtin::Function::kTextureSampleCompare) {
                     // Get the severity of derivative uniformity violations in this context.
                     auto severity = sem_.DiagnosticSeverity(
                         call, builtin::DiagnosticRule::kDerivativeUniformity);
@@ -1650,7 +1650,7 @@
                 }
             } else {
                 auto* builtin = sem->Target()->As<sem::Builtin>();
-                if (builtin && builtin->Type() == sem::BuiltinType::kWorkgroupUniformLoad) {
+                if (builtin && builtin->Type() == builtin::Function::kWorkgroupUniformLoad) {
                     // The workgroupUniformLoad builtin requires its parameter to be uniform.
                     current_function_->RequiredToBeUniform(default_severity)->AddEdge(args[i]);
                 } else {
diff --git a/src/tint/sem/builtin.cc b/src/tint/sem/builtin.cc
index 4fd2c34..4f33ebb 100644
--- a/src/tint/sem/builtin.cc
+++ b/src/tint/sem/builtin.cc
@@ -27,74 +27,76 @@
 namespace tint::sem {
 
 const char* Builtin::str() const {
-    return sem::str(type_);
+    return builtin::str(type_);
 }
 
-bool IsCoarseDerivativeBuiltin(BuiltinType i) {
-    return i == BuiltinType::kDpdxCoarse || i == BuiltinType::kDpdyCoarse ||
-           i == BuiltinType::kFwidthCoarse;
+bool IsCoarseDerivativeBuiltin(builtin::Function i) {
+    return i == builtin::Function::kDpdxCoarse || i == builtin::Function::kDpdyCoarse ||
+           i == builtin::Function::kFwidthCoarse;
 }
 
-bool IsFineDerivativeBuiltin(BuiltinType i) {
-    return i == BuiltinType::kDpdxFine || i == BuiltinType::kDpdyFine ||
-           i == BuiltinType::kFwidthFine;
+bool IsFineDerivativeBuiltin(builtin::Function i) {
+    return i == builtin::Function::kDpdxFine || i == builtin::Function::kDpdyFine ||
+           i == builtin::Function::kFwidthFine;
 }
 
-bool IsDerivativeBuiltin(BuiltinType i) {
-    return i == BuiltinType::kDpdx || i == BuiltinType::kDpdy || i == BuiltinType::kFwidth ||
-           IsCoarseDerivativeBuiltin(i) || IsFineDerivativeBuiltin(i);
+bool IsDerivativeBuiltin(builtin::Function i) {
+    return i == builtin::Function::kDpdx || i == builtin::Function::kDpdy ||
+           i == builtin::Function::kFwidth || IsCoarseDerivativeBuiltin(i) ||
+           IsFineDerivativeBuiltin(i);
 }
 
-bool IsTextureBuiltin(BuiltinType i) {
-    return IsImageQueryBuiltin(i) ||                           //
-           i == BuiltinType::kTextureGather ||                 //
-           i == BuiltinType::kTextureGatherCompare ||          //
-           i == BuiltinType::kTextureLoad ||                   //
-           i == BuiltinType::kTextureSample ||                 //
-           i == BuiltinType::kTextureSampleBaseClampToEdge ||  //
-           i == BuiltinType::kTextureSampleBias ||             //
-           i == BuiltinType::kTextureSampleCompare ||          //
-           i == BuiltinType::kTextureSampleCompareLevel ||     //
-           i == BuiltinType::kTextureSampleGrad ||             //
-           i == BuiltinType::kTextureSampleLevel ||            //
-           i == BuiltinType::kTextureStore;
+bool IsTextureBuiltin(builtin::Function i) {
+    return IsImageQueryBuiltin(i) ||                                 //
+           i == builtin::Function::kTextureGather ||                 //
+           i == builtin::Function::kTextureGatherCompare ||          //
+           i == builtin::Function::kTextureLoad ||                   //
+           i == builtin::Function::kTextureSample ||                 //
+           i == builtin::Function::kTextureSampleBaseClampToEdge ||  //
+           i == builtin::Function::kTextureSampleBias ||             //
+           i == builtin::Function::kTextureSampleCompare ||          //
+           i == builtin::Function::kTextureSampleCompareLevel ||     //
+           i == builtin::Function::kTextureSampleGrad ||             //
+           i == builtin::Function::kTextureSampleLevel ||            //
+           i == builtin::Function::kTextureStore;
 }
 
-bool IsImageQueryBuiltin(BuiltinType i) {
-    return i == BuiltinType::kTextureDimensions || i == BuiltinType::kTextureNumLayers ||
-           i == BuiltinType::kTextureNumLevels || i == BuiltinType::kTextureNumSamples;
+bool IsImageQueryBuiltin(builtin::Function i) {
+    return i == builtin::Function::kTextureDimensions ||
+           i == builtin::Function::kTextureNumLayers || i == builtin::Function::kTextureNumLevels ||
+           i == builtin::Function::kTextureNumSamples;
 }
 
-bool IsDataPackingBuiltin(BuiltinType i) {
-    return i == BuiltinType::kPack4X8Snorm || i == BuiltinType::kPack4X8Unorm ||
-           i == BuiltinType::kPack2X16Snorm || i == BuiltinType::kPack2X16Unorm ||
-           i == BuiltinType::kPack2X16Float;
+bool IsDataPackingBuiltin(builtin::Function i) {
+    return i == builtin::Function::kPack4X8Snorm || i == builtin::Function::kPack4X8Unorm ||
+           i == builtin::Function::kPack2X16Snorm || i == builtin::Function::kPack2X16Unorm ||
+           i == builtin::Function::kPack2X16Float;
 }
 
-bool IsDataUnpackingBuiltin(BuiltinType i) {
-    return i == BuiltinType::kUnpack4X8Snorm || i == BuiltinType::kUnpack4X8Unorm ||
-           i == BuiltinType::kUnpack2X16Snorm || i == BuiltinType::kUnpack2X16Unorm ||
-           i == BuiltinType::kUnpack2X16Float;
+bool IsDataUnpackingBuiltin(builtin::Function i) {
+    return i == builtin::Function::kUnpack4X8Snorm || i == builtin::Function::kUnpack4X8Unorm ||
+           i == builtin::Function::kUnpack2X16Snorm || i == builtin::Function::kUnpack2X16Unorm ||
+           i == builtin::Function::kUnpack2X16Float;
 }
 
-bool IsBarrierBuiltin(BuiltinType i) {
-    return i == BuiltinType::kWorkgroupBarrier || i == BuiltinType::kStorageBarrier;
+bool IsBarrierBuiltin(builtin::Function i) {
+    return i == builtin::Function::kWorkgroupBarrier || i == builtin::Function::kStorageBarrier;
 }
 
-bool IsAtomicBuiltin(BuiltinType i) {
-    return i == sem::BuiltinType::kAtomicLoad || i == sem::BuiltinType::kAtomicStore ||
-           i == sem::BuiltinType::kAtomicAdd || i == sem::BuiltinType::kAtomicSub ||
-           i == sem::BuiltinType::kAtomicMax || i == sem::BuiltinType::kAtomicMin ||
-           i == sem::BuiltinType::kAtomicAnd || i == sem::BuiltinType::kAtomicOr ||
-           i == sem::BuiltinType::kAtomicXor || i == sem::BuiltinType::kAtomicExchange ||
-           i == sem::BuiltinType::kAtomicCompareExchangeWeak;
+bool IsAtomicBuiltin(builtin::Function i) {
+    return i == builtin::Function::kAtomicLoad || i == builtin::Function::kAtomicStore ||
+           i == builtin::Function::kAtomicAdd || i == builtin::Function::kAtomicSub ||
+           i == builtin::Function::kAtomicMax || i == builtin::Function::kAtomicMin ||
+           i == builtin::Function::kAtomicAnd || i == builtin::Function::kAtomicOr ||
+           i == builtin::Function::kAtomicXor || i == builtin::Function::kAtomicExchange ||
+           i == builtin::Function::kAtomicCompareExchangeWeak;
 }
 
-bool IsDP4aBuiltin(BuiltinType i) {
-    return i == sem::BuiltinType::kDot4I8Packed || i == sem::BuiltinType::kDot4U8Packed;
+bool IsDP4aBuiltin(builtin::Function i) {
+    return i == builtin::Function::kDot4I8Packed || i == builtin::Function::kDot4U8Packed;
 }
 
-Builtin::Builtin(BuiltinType type,
+Builtin::Builtin(builtin::Function type,
                  const type::Type* return_type,
                  utils::VectorRef<Parameter*> parameters,
                  EvaluationStage eval_stage,
@@ -150,18 +152,18 @@
 
 bool Builtin::HasSideEffects() const {
     switch (type_) {
-        case sem::BuiltinType::kAtomicAdd:
-        case sem::BuiltinType::kAtomicAnd:
-        case sem::BuiltinType::kAtomicCompareExchangeWeak:
-        case sem::BuiltinType::kAtomicExchange:
-        case sem::BuiltinType::kAtomicMax:
-        case sem::BuiltinType::kAtomicMin:
-        case sem::BuiltinType::kAtomicOr:
-        case sem::BuiltinType::kAtomicStore:
-        case sem::BuiltinType::kAtomicSub:
-        case sem::BuiltinType::kAtomicXor:
-        case sem::BuiltinType::kTextureStore:
-        case sem::BuiltinType::kWorkgroupUniformLoad:
+        case builtin::Function::kAtomicAdd:
+        case builtin::Function::kAtomicAnd:
+        case builtin::Function::kAtomicCompareExchangeWeak:
+        case builtin::Function::kAtomicExchange:
+        case builtin::Function::kAtomicMax:
+        case builtin::Function::kAtomicMin:
+        case builtin::Function::kAtomicOr:
+        case builtin::Function::kAtomicStore:
+        case builtin::Function::kAtomicSub:
+        case builtin::Function::kAtomicXor:
+        case builtin::Function::kTextureStore:
+        case builtin::Function::kWorkgroupUniformLoad:
             return true;
         default:
             break;
diff --git a/src/tint/sem/builtin.h b/src/tint/sem/builtin.h
index 55d882e..b535e72 100644
--- a/src/tint/sem/builtin.h
+++ b/src/tint/sem/builtin.h
@@ -19,7 +19,7 @@
 #include <vector>
 
 #include "src/tint/builtin/extension.h"
-#include "src/tint/sem/builtin_type.h"
+#include "src/tint/builtin/function.h"
 #include "src/tint/sem/call_target.h"
 #include "src/tint/sem/pipeline_stage_set.h"
 #include "src/tint/utils/hash.h"
@@ -29,52 +29,52 @@
 /// Determines if the given `i` is a coarse derivative
 /// @param i the builtin type
 /// @returns true if the given derivative is coarse.
-bool IsCoarseDerivativeBuiltin(BuiltinType i);
+bool IsCoarseDerivativeBuiltin(builtin::Function i);
 
 /// Determines if the given `i` is a fine derivative
 /// @param i the builtin type
 /// @returns true if the given derivative is fine.
-bool IsFineDerivativeBuiltin(BuiltinType i);
+bool IsFineDerivativeBuiltin(builtin::Function i);
 
 /// Determine if the given `i` is a derivative builtin
 /// @param i the builtin type
 /// @returns true if the given `i` is a derivative builtin
-bool IsDerivativeBuiltin(BuiltinType i);
+bool IsDerivativeBuiltin(builtin::Function i);
 
 /// Determines if the given `i` is a texture operation builtin
 /// @param i the builtin type
 /// @returns true if the given `i` is a texture operation builtin
-bool IsTextureBuiltin(BuiltinType i);
+bool IsTextureBuiltin(builtin::Function i);
 
 /// Determines if the given `i` is a image query builtin
 /// @param i the builtin type
 /// @returns true if the given `i` is a image query builtin
-bool IsImageQueryBuiltin(BuiltinType i);
+bool IsImageQueryBuiltin(builtin::Function i);
 
 /// Determines if the given `i` is a data packing builtin
 /// @param i the builtin
 /// @returns true if the given `i` is a data packing builtin
-bool IsDataPackingBuiltin(BuiltinType i);
+bool IsDataPackingBuiltin(builtin::Function i);
 
 /// Determines if the given `i` is a data unpacking builtin
 /// @param i the builtin
 /// @returns true if the given `i` is a data unpacking builtin
-bool IsDataUnpackingBuiltin(BuiltinType i);
+bool IsDataUnpackingBuiltin(builtin::Function i);
 
 /// Determines if the given `i` is a barrier builtin
 /// @param i the builtin
 /// @returns true if the given `i` is a barrier builtin
-bool IsBarrierBuiltin(BuiltinType i);
+bool IsBarrierBuiltin(builtin::Function i);
 
 /// Determines if the given `i` is a atomic builtin
 /// @param i the builtin
 /// @returns true if the given `i` is a atomic builtin
-bool IsAtomicBuiltin(BuiltinType i);
+bool IsAtomicBuiltin(builtin::Function i);
 
 /// Determins if the given `i` is a DP4a builtin
 /// @param i the builtin
 /// @returns true if the given `i` is a DP4a builtin
-bool IsDP4aBuiltin(BuiltinType i);
+bool IsDP4aBuiltin(builtin::Function i);
 
 /// Builtin holds the semantic information for a builtin function.
 class Builtin final : public Castable<Builtin, CallTarget> {
@@ -87,7 +87,7 @@
     /// @param supported_stages the pipeline stages that this builtin can be used in
     /// @param is_deprecated true if the particular overload is considered deprecated
     /// @param must_use true if the builtin was annotated with `@must_use`
-    Builtin(BuiltinType type,
+    Builtin(builtin::Function type,
             const type::Type* return_type,
             utils::VectorRef<Parameter*> parameters,
             EvaluationStage eval_stage,
@@ -99,7 +99,7 @@
     ~Builtin() override;
 
     /// @return the type of the builtin
-    BuiltinType Type() const { return type_; }
+    builtin::Function Type() const { return type_; }
 
     /// @return the pipeline stages that this builtin can be used in
     PipelineStageSet SupportedStages() const { return supported_stages_; }
@@ -151,7 +151,7 @@
     builtin::Extension RequiredExtension() const;
 
   private:
-    const BuiltinType type_;
+    const builtin::Function type_;
     const PipelineStageSet supported_stages_;
     const bool is_deprecated_;
 };
diff --git a/src/tint/sem/builtin_test.cc b/src/tint/sem/builtin_test.cc
index ff66e1b..ef63dc6 100644
--- a/src/tint/sem/builtin_test.cc
+++ b/src/tint/sem/builtin_test.cc
@@ -21,7 +21,7 @@
 
 struct BuiltinData {
     const char* name;
-    BuiltinType builtin;
+    builtin::Function builtin;
 };
 
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
@@ -29,98 +29,98 @@
     return out;
 }
 
-using BuiltinTypeTest = testing::TestWithParam<BuiltinData>;
+using BuiltinFunctionTest = testing::TestWithParam<BuiltinData>;
 
-TEST_P(BuiltinTypeTest, Parse) {
+TEST_P(BuiltinFunctionTest, Parse) {
     auto param = GetParam();
-    EXPECT_EQ(ParseBuiltinType(param.name), param.builtin);
+    EXPECT_EQ(builtin::ParseFunction(param.name), param.builtin);
 }
 
 INSTANTIATE_TEST_SUITE_P(
-    BuiltinTypeTest,
-    BuiltinTypeTest,
-    testing::Values(BuiltinData{"abs", BuiltinType::kAbs},
-                    BuiltinData{"acos", BuiltinType::kAcos},
-                    BuiltinData{"all", BuiltinType::kAll},
-                    BuiltinData{"any", BuiltinType::kAny},
-                    BuiltinData{"arrayLength", BuiltinType::kArrayLength},
-                    BuiltinData{"asin", BuiltinType::kAsin},
-                    BuiltinData{"atan", BuiltinType::kAtan},
-                    BuiltinData{"atan2", BuiltinType::kAtan2},
-                    BuiltinData{"ceil", BuiltinType::kCeil},
-                    BuiltinData{"clamp", BuiltinType::kClamp},
-                    BuiltinData{"cos", BuiltinType::kCos},
-                    BuiltinData{"cosh", BuiltinType::kCosh},
-                    BuiltinData{"countOneBits", BuiltinType::kCountOneBits},
-                    BuiltinData{"cross", BuiltinType::kCross},
-                    BuiltinData{"determinant", BuiltinType::kDeterminant},
-                    BuiltinData{"distance", BuiltinType::kDistance},
-                    BuiltinData{"dot", BuiltinType::kDot},
-                    BuiltinData{"dot4I8Packed", BuiltinType::kDot4I8Packed},
-                    BuiltinData{"dot4U8Packed", BuiltinType::kDot4U8Packed},
-                    BuiltinData{"dpdx", BuiltinType::kDpdx},
-                    BuiltinData{"dpdxCoarse", BuiltinType::kDpdxCoarse},
-                    BuiltinData{"dpdxFine", BuiltinType::kDpdxFine},
-                    BuiltinData{"dpdy", BuiltinType::kDpdy},
-                    BuiltinData{"dpdyCoarse", BuiltinType::kDpdyCoarse},
-                    BuiltinData{"dpdyFine", BuiltinType::kDpdyFine},
-                    BuiltinData{"exp", BuiltinType::kExp},
-                    BuiltinData{"exp2", BuiltinType::kExp2},
-                    BuiltinData{"faceForward", BuiltinType::kFaceForward},
-                    BuiltinData{"floor", BuiltinType::kFloor},
-                    BuiltinData{"fma", BuiltinType::kFma},
-                    BuiltinData{"fract", BuiltinType::kFract},
-                    BuiltinData{"frexp", BuiltinType::kFrexp},
-                    BuiltinData{"fwidth", BuiltinType::kFwidth},
-                    BuiltinData{"fwidthCoarse", BuiltinType::kFwidthCoarse},
-                    BuiltinData{"fwidthFine", BuiltinType::kFwidthFine},
-                    BuiltinData{"inverseSqrt", BuiltinType::kInverseSqrt},
-                    BuiltinData{"ldexp", BuiltinType::kLdexp},
-                    BuiltinData{"length", BuiltinType::kLength},
-                    BuiltinData{"log", BuiltinType::kLog},
-                    BuiltinData{"log2", BuiltinType::kLog2},
-                    BuiltinData{"max", BuiltinType::kMax},
-                    BuiltinData{"min", BuiltinType::kMin},
-                    BuiltinData{"mix", BuiltinType::kMix},
-                    BuiltinData{"modf", BuiltinType::kModf},
-                    BuiltinData{"normalize", BuiltinType::kNormalize},
-                    BuiltinData{"pow", BuiltinType::kPow},
-                    BuiltinData{"reflect", BuiltinType::kReflect},
-                    BuiltinData{"reverseBits", BuiltinType::kReverseBits},
-                    BuiltinData{"round", BuiltinType::kRound},
-                    BuiltinData{"select", BuiltinType::kSelect},
-                    BuiltinData{"sign", BuiltinType::kSign},
-                    BuiltinData{"sin", BuiltinType::kSin},
-                    BuiltinData{"sinh", BuiltinType::kSinh},
-                    BuiltinData{"smoothstep", BuiltinType::kSmoothstep},
-                    BuiltinData{"sqrt", BuiltinType::kSqrt},
-                    BuiltinData{"step", BuiltinType::kStep},
-                    BuiltinData{"storageBarrier", BuiltinType::kStorageBarrier},
-                    BuiltinData{"tan", BuiltinType::kTan},
-                    BuiltinData{"tanh", BuiltinType::kTanh},
-                    BuiltinData{"textureDimensions", BuiltinType::kTextureDimensions},
-                    BuiltinData{"textureLoad", BuiltinType::kTextureLoad},
-                    BuiltinData{"textureNumLayers", BuiltinType::kTextureNumLayers},
-                    BuiltinData{"textureNumLevels", BuiltinType::kTextureNumLevels},
-                    BuiltinData{"textureNumSamples", BuiltinType::kTextureNumSamples},
-                    BuiltinData{"textureSample", BuiltinType::kTextureSample},
-                    BuiltinData{"textureSampleBias", BuiltinType::kTextureSampleBias},
-                    BuiltinData{"textureSampleCompare", BuiltinType::kTextureSampleCompare},
+    BuiltinFunctionTest,
+    BuiltinFunctionTest,
+    testing::Values(BuiltinData{"abs", builtin::Function::kAbs},
+                    BuiltinData{"acos", builtin::Function::kAcos},
+                    BuiltinData{"all", builtin::Function::kAll},
+                    BuiltinData{"any", builtin::Function::kAny},
+                    BuiltinData{"arrayLength", builtin::Function::kArrayLength},
+                    BuiltinData{"asin", builtin::Function::kAsin},
+                    BuiltinData{"atan", builtin::Function::kAtan},
+                    BuiltinData{"atan2", builtin::Function::kAtan2},
+                    BuiltinData{"ceil", builtin::Function::kCeil},
+                    BuiltinData{"clamp", builtin::Function::kClamp},
+                    BuiltinData{"cos", builtin::Function::kCos},
+                    BuiltinData{"cosh", builtin::Function::kCosh},
+                    BuiltinData{"countOneBits", builtin::Function::kCountOneBits},
+                    BuiltinData{"cross", builtin::Function::kCross},
+                    BuiltinData{"determinant", builtin::Function::kDeterminant},
+                    BuiltinData{"distance", builtin::Function::kDistance},
+                    BuiltinData{"dot", builtin::Function::kDot},
+                    BuiltinData{"dot4I8Packed", builtin::Function::kDot4I8Packed},
+                    BuiltinData{"dot4U8Packed", builtin::Function::kDot4U8Packed},
+                    BuiltinData{"dpdx", builtin::Function::kDpdx},
+                    BuiltinData{"dpdxCoarse", builtin::Function::kDpdxCoarse},
+                    BuiltinData{"dpdxFine", builtin::Function::kDpdxFine},
+                    BuiltinData{"dpdy", builtin::Function::kDpdy},
+                    BuiltinData{"dpdyCoarse", builtin::Function::kDpdyCoarse},
+                    BuiltinData{"dpdyFine", builtin::Function::kDpdyFine},
+                    BuiltinData{"exp", builtin::Function::kExp},
+                    BuiltinData{"exp2", builtin::Function::kExp2},
+                    BuiltinData{"faceForward", builtin::Function::kFaceForward},
+                    BuiltinData{"floor", builtin::Function::kFloor},
+                    BuiltinData{"fma", builtin::Function::kFma},
+                    BuiltinData{"fract", builtin::Function::kFract},
+                    BuiltinData{"frexp", builtin::Function::kFrexp},
+                    BuiltinData{"fwidth", builtin::Function::kFwidth},
+                    BuiltinData{"fwidthCoarse", builtin::Function::kFwidthCoarse},
+                    BuiltinData{"fwidthFine", builtin::Function::kFwidthFine},
+                    BuiltinData{"inverseSqrt", builtin::Function::kInverseSqrt},
+                    BuiltinData{"ldexp", builtin::Function::kLdexp},
+                    BuiltinData{"length", builtin::Function::kLength},
+                    BuiltinData{"log", builtin::Function::kLog},
+                    BuiltinData{"log2", builtin::Function::kLog2},
+                    BuiltinData{"max", builtin::Function::kMax},
+                    BuiltinData{"min", builtin::Function::kMin},
+                    BuiltinData{"mix", builtin::Function::kMix},
+                    BuiltinData{"modf", builtin::Function::kModf},
+                    BuiltinData{"normalize", builtin::Function::kNormalize},
+                    BuiltinData{"pow", builtin::Function::kPow},
+                    BuiltinData{"reflect", builtin::Function::kReflect},
+                    BuiltinData{"reverseBits", builtin::Function::kReverseBits},
+                    BuiltinData{"round", builtin::Function::kRound},
+                    BuiltinData{"select", builtin::Function::kSelect},
+                    BuiltinData{"sign", builtin::Function::kSign},
+                    BuiltinData{"sin", builtin::Function::kSin},
+                    BuiltinData{"sinh", builtin::Function::kSinh},
+                    BuiltinData{"smoothstep", builtin::Function::kSmoothstep},
+                    BuiltinData{"sqrt", builtin::Function::kSqrt},
+                    BuiltinData{"step", builtin::Function::kStep},
+                    BuiltinData{"storageBarrier", builtin::Function::kStorageBarrier},
+                    BuiltinData{"tan", builtin::Function::kTan},
+                    BuiltinData{"tanh", builtin::Function::kTanh},
+                    BuiltinData{"textureDimensions", builtin::Function::kTextureDimensions},
+                    BuiltinData{"textureLoad", builtin::Function::kTextureLoad},
+                    BuiltinData{"textureNumLayers", builtin::Function::kTextureNumLayers},
+                    BuiltinData{"textureNumLevels", builtin::Function::kTextureNumLevels},
+                    BuiltinData{"textureNumSamples", builtin::Function::kTextureNumSamples},
+                    BuiltinData{"textureSample", builtin::Function::kTextureSample},
+                    BuiltinData{"textureSampleBias", builtin::Function::kTextureSampleBias},
+                    BuiltinData{"textureSampleCompare", builtin::Function::kTextureSampleCompare},
                     BuiltinData{"textureSampleCompareLevel",
-                                BuiltinType::kTextureSampleCompareLevel},
-                    BuiltinData{"textureSampleGrad", BuiltinType::kTextureSampleGrad},
-                    BuiltinData{"textureSampleLevel", BuiltinType::kTextureSampleLevel},
-                    BuiltinData{"trunc", BuiltinType::kTrunc},
-                    BuiltinData{"unpack2x16float", BuiltinType::kUnpack2X16Float},
-                    BuiltinData{"unpack2x16snorm", BuiltinType::kUnpack2X16Snorm},
-                    BuiltinData{"unpack2x16unorm", BuiltinType::kUnpack2X16Unorm},
-                    BuiltinData{"unpack4x8snorm", BuiltinType::kUnpack4X8Snorm},
-                    BuiltinData{"unpack4x8unorm", BuiltinType::kUnpack4X8Unorm},
-                    BuiltinData{"workgroupBarrier", BuiltinType::kWorkgroupBarrier},
-                    BuiltinData{"workgroupUniformLoad", BuiltinType::kWorkgroupUniformLoad}));
+                                builtin::Function::kTextureSampleCompareLevel},
+                    BuiltinData{"textureSampleGrad", builtin::Function::kTextureSampleGrad},
+                    BuiltinData{"textureSampleLevel", builtin::Function::kTextureSampleLevel},
+                    BuiltinData{"trunc", builtin::Function::kTrunc},
+                    BuiltinData{"unpack2x16float", builtin::Function::kUnpack2X16Float},
+                    BuiltinData{"unpack2x16snorm", builtin::Function::kUnpack2X16Snorm},
+                    BuiltinData{"unpack2x16unorm", builtin::Function::kUnpack2X16Unorm},
+                    BuiltinData{"unpack4x8snorm", builtin::Function::kUnpack4X8Snorm},
+                    BuiltinData{"unpack4x8unorm", builtin::Function::kUnpack4X8Unorm},
+                    BuiltinData{"workgroupBarrier", builtin::Function::kWorkgroupBarrier},
+                    BuiltinData{"workgroupUniformLoad", builtin::Function::kWorkgroupUniformLoad}));
 
-TEST_F(BuiltinTypeTest, ParseNoMatch) {
-    EXPECT_EQ(ParseBuiltinType("not_builtin"), BuiltinType::kNone);
+TEST_F(BuiltinFunctionTest, ParseNoMatch) {
+    EXPECT_EQ(builtin::ParseFunction("not_builtin"), builtin::Function::kNone);
 }
 
 }  // namespace
diff --git a/src/tint/sem/builtin_type.cc b/src/tint/sem/builtin_type.cc
deleted file mode 100644
index 8abcec0..0000000
--- a/src/tint/sem/builtin_type.cc
+++ /dev/null
@@ -1,614 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/src/cmd/gen
-// using the template:
-//   src/tint/sem/builtin_type.cc.tmpl
-//
-// Do not modify this file directly
-////////////////////////////////////////////////////////////////////////////////
-
-#include "src/tint/sem/builtin_type.h"
-
-namespace tint::sem {
-
-BuiltinType ParseBuiltinType(const std::string& name) {
-    if (name == "abs") {
-        return BuiltinType::kAbs;
-    }
-    if (name == "acos") {
-        return BuiltinType::kAcos;
-    }
-    if (name == "acosh") {
-        return BuiltinType::kAcosh;
-    }
-    if (name == "all") {
-        return BuiltinType::kAll;
-    }
-    if (name == "any") {
-        return BuiltinType::kAny;
-    }
-    if (name == "arrayLength") {
-        return BuiltinType::kArrayLength;
-    }
-    if (name == "asin") {
-        return BuiltinType::kAsin;
-    }
-    if (name == "asinh") {
-        return BuiltinType::kAsinh;
-    }
-    if (name == "atan") {
-        return BuiltinType::kAtan;
-    }
-    if (name == "atan2") {
-        return BuiltinType::kAtan2;
-    }
-    if (name == "atanh") {
-        return BuiltinType::kAtanh;
-    }
-    if (name == "ceil") {
-        return BuiltinType::kCeil;
-    }
-    if (name == "clamp") {
-        return BuiltinType::kClamp;
-    }
-    if (name == "cos") {
-        return BuiltinType::kCos;
-    }
-    if (name == "cosh") {
-        return BuiltinType::kCosh;
-    }
-    if (name == "countLeadingZeros") {
-        return BuiltinType::kCountLeadingZeros;
-    }
-    if (name == "countOneBits") {
-        return BuiltinType::kCountOneBits;
-    }
-    if (name == "countTrailingZeros") {
-        return BuiltinType::kCountTrailingZeros;
-    }
-    if (name == "cross") {
-        return BuiltinType::kCross;
-    }
-    if (name == "degrees") {
-        return BuiltinType::kDegrees;
-    }
-    if (name == "determinant") {
-        return BuiltinType::kDeterminant;
-    }
-    if (name == "distance") {
-        return BuiltinType::kDistance;
-    }
-    if (name == "dot") {
-        return BuiltinType::kDot;
-    }
-    if (name == "dot4I8Packed") {
-        return BuiltinType::kDot4I8Packed;
-    }
-    if (name == "dot4U8Packed") {
-        return BuiltinType::kDot4U8Packed;
-    }
-    if (name == "dpdx") {
-        return BuiltinType::kDpdx;
-    }
-    if (name == "dpdxCoarse") {
-        return BuiltinType::kDpdxCoarse;
-    }
-    if (name == "dpdxFine") {
-        return BuiltinType::kDpdxFine;
-    }
-    if (name == "dpdy") {
-        return BuiltinType::kDpdy;
-    }
-    if (name == "dpdyCoarse") {
-        return BuiltinType::kDpdyCoarse;
-    }
-    if (name == "dpdyFine") {
-        return BuiltinType::kDpdyFine;
-    }
-    if (name == "exp") {
-        return BuiltinType::kExp;
-    }
-    if (name == "exp2") {
-        return BuiltinType::kExp2;
-    }
-    if (name == "extractBits") {
-        return BuiltinType::kExtractBits;
-    }
-    if (name == "faceForward") {
-        return BuiltinType::kFaceForward;
-    }
-    if (name == "firstLeadingBit") {
-        return BuiltinType::kFirstLeadingBit;
-    }
-    if (name == "firstTrailingBit") {
-        return BuiltinType::kFirstTrailingBit;
-    }
-    if (name == "floor") {
-        return BuiltinType::kFloor;
-    }
-    if (name == "fma") {
-        return BuiltinType::kFma;
-    }
-    if (name == "fract") {
-        return BuiltinType::kFract;
-    }
-    if (name == "frexp") {
-        return BuiltinType::kFrexp;
-    }
-    if (name == "fwidth") {
-        return BuiltinType::kFwidth;
-    }
-    if (name == "fwidthCoarse") {
-        return BuiltinType::kFwidthCoarse;
-    }
-    if (name == "fwidthFine") {
-        return BuiltinType::kFwidthFine;
-    }
-    if (name == "insertBits") {
-        return BuiltinType::kInsertBits;
-    }
-    if (name == "inverseSqrt") {
-        return BuiltinType::kInverseSqrt;
-    }
-    if (name == "ldexp") {
-        return BuiltinType::kLdexp;
-    }
-    if (name == "length") {
-        return BuiltinType::kLength;
-    }
-    if (name == "log") {
-        return BuiltinType::kLog;
-    }
-    if (name == "log2") {
-        return BuiltinType::kLog2;
-    }
-    if (name == "max") {
-        return BuiltinType::kMax;
-    }
-    if (name == "min") {
-        return BuiltinType::kMin;
-    }
-    if (name == "mix") {
-        return BuiltinType::kMix;
-    }
-    if (name == "modf") {
-        return BuiltinType::kModf;
-    }
-    if (name == "normalize") {
-        return BuiltinType::kNormalize;
-    }
-    if (name == "pack2x16float") {
-        return BuiltinType::kPack2X16Float;
-    }
-    if (name == "pack2x16snorm") {
-        return BuiltinType::kPack2X16Snorm;
-    }
-    if (name == "pack2x16unorm") {
-        return BuiltinType::kPack2X16Unorm;
-    }
-    if (name == "pack4x8snorm") {
-        return BuiltinType::kPack4X8Snorm;
-    }
-    if (name == "pack4x8unorm") {
-        return BuiltinType::kPack4X8Unorm;
-    }
-    if (name == "pow") {
-        return BuiltinType::kPow;
-    }
-    if (name == "quantizeToF16") {
-        return BuiltinType::kQuantizeToF16;
-    }
-    if (name == "radians") {
-        return BuiltinType::kRadians;
-    }
-    if (name == "reflect") {
-        return BuiltinType::kReflect;
-    }
-    if (name == "refract") {
-        return BuiltinType::kRefract;
-    }
-    if (name == "reverseBits") {
-        return BuiltinType::kReverseBits;
-    }
-    if (name == "round") {
-        return BuiltinType::kRound;
-    }
-    if (name == "saturate") {
-        return BuiltinType::kSaturate;
-    }
-    if (name == "select") {
-        return BuiltinType::kSelect;
-    }
-    if (name == "sign") {
-        return BuiltinType::kSign;
-    }
-    if (name == "sin") {
-        return BuiltinType::kSin;
-    }
-    if (name == "sinh") {
-        return BuiltinType::kSinh;
-    }
-    if (name == "smoothstep") {
-        return BuiltinType::kSmoothstep;
-    }
-    if (name == "sqrt") {
-        return BuiltinType::kSqrt;
-    }
-    if (name == "step") {
-        return BuiltinType::kStep;
-    }
-    if (name == "storageBarrier") {
-        return BuiltinType::kStorageBarrier;
-    }
-    if (name == "tan") {
-        return BuiltinType::kTan;
-    }
-    if (name == "tanh") {
-        return BuiltinType::kTanh;
-    }
-    if (name == "transpose") {
-        return BuiltinType::kTranspose;
-    }
-    if (name == "trunc") {
-        return BuiltinType::kTrunc;
-    }
-    if (name == "unpack2x16float") {
-        return BuiltinType::kUnpack2X16Float;
-    }
-    if (name == "unpack2x16snorm") {
-        return BuiltinType::kUnpack2X16Snorm;
-    }
-    if (name == "unpack2x16unorm") {
-        return BuiltinType::kUnpack2X16Unorm;
-    }
-    if (name == "unpack4x8snorm") {
-        return BuiltinType::kUnpack4X8Snorm;
-    }
-    if (name == "unpack4x8unorm") {
-        return BuiltinType::kUnpack4X8Unorm;
-    }
-    if (name == "workgroupBarrier") {
-        return BuiltinType::kWorkgroupBarrier;
-    }
-    if (name == "workgroupUniformLoad") {
-        return BuiltinType::kWorkgroupUniformLoad;
-    }
-    if (name == "textureDimensions") {
-        return BuiltinType::kTextureDimensions;
-    }
-    if (name == "textureGather") {
-        return BuiltinType::kTextureGather;
-    }
-    if (name == "textureGatherCompare") {
-        return BuiltinType::kTextureGatherCompare;
-    }
-    if (name == "textureNumLayers") {
-        return BuiltinType::kTextureNumLayers;
-    }
-    if (name == "textureNumLevels") {
-        return BuiltinType::kTextureNumLevels;
-    }
-    if (name == "textureNumSamples") {
-        return BuiltinType::kTextureNumSamples;
-    }
-    if (name == "textureSample") {
-        return BuiltinType::kTextureSample;
-    }
-    if (name == "textureSampleBias") {
-        return BuiltinType::kTextureSampleBias;
-    }
-    if (name == "textureSampleCompare") {
-        return BuiltinType::kTextureSampleCompare;
-    }
-    if (name == "textureSampleCompareLevel") {
-        return BuiltinType::kTextureSampleCompareLevel;
-    }
-    if (name == "textureSampleGrad") {
-        return BuiltinType::kTextureSampleGrad;
-    }
-    if (name == "textureSampleLevel") {
-        return BuiltinType::kTextureSampleLevel;
-    }
-    if (name == "textureSampleBaseClampToEdge") {
-        return BuiltinType::kTextureSampleBaseClampToEdge;
-    }
-    if (name == "textureStore") {
-        return BuiltinType::kTextureStore;
-    }
-    if (name == "textureLoad") {
-        return BuiltinType::kTextureLoad;
-    }
-    if (name == "atomicLoad") {
-        return BuiltinType::kAtomicLoad;
-    }
-    if (name == "atomicStore") {
-        return BuiltinType::kAtomicStore;
-    }
-    if (name == "atomicAdd") {
-        return BuiltinType::kAtomicAdd;
-    }
-    if (name == "atomicSub") {
-        return BuiltinType::kAtomicSub;
-    }
-    if (name == "atomicMax") {
-        return BuiltinType::kAtomicMax;
-    }
-    if (name == "atomicMin") {
-        return BuiltinType::kAtomicMin;
-    }
-    if (name == "atomicAnd") {
-        return BuiltinType::kAtomicAnd;
-    }
-    if (name == "atomicOr") {
-        return BuiltinType::kAtomicOr;
-    }
-    if (name == "atomicXor") {
-        return BuiltinType::kAtomicXor;
-    }
-    if (name == "atomicExchange") {
-        return BuiltinType::kAtomicExchange;
-    }
-    if (name == "atomicCompareExchangeWeak") {
-        return BuiltinType::kAtomicCompareExchangeWeak;
-    }
-    if (name == "_tint_materialize") {
-        return BuiltinType::kTintMaterialize;
-    }
-    return BuiltinType::kNone;
-}
-
-const char* str(BuiltinType i) {
-    switch (i) {
-        case BuiltinType::kNone:
-            return "<none>";
-        case BuiltinType::kAbs:
-            return "abs";
-        case BuiltinType::kAcos:
-            return "acos";
-        case BuiltinType::kAcosh:
-            return "acosh";
-        case BuiltinType::kAll:
-            return "all";
-        case BuiltinType::kAny:
-            return "any";
-        case BuiltinType::kArrayLength:
-            return "arrayLength";
-        case BuiltinType::kAsin:
-            return "asin";
-        case BuiltinType::kAsinh:
-            return "asinh";
-        case BuiltinType::kAtan:
-            return "atan";
-        case BuiltinType::kAtan2:
-            return "atan2";
-        case BuiltinType::kAtanh:
-            return "atanh";
-        case BuiltinType::kCeil:
-            return "ceil";
-        case BuiltinType::kClamp:
-            return "clamp";
-        case BuiltinType::kCos:
-            return "cos";
-        case BuiltinType::kCosh:
-            return "cosh";
-        case BuiltinType::kCountLeadingZeros:
-            return "countLeadingZeros";
-        case BuiltinType::kCountOneBits:
-            return "countOneBits";
-        case BuiltinType::kCountTrailingZeros:
-            return "countTrailingZeros";
-        case BuiltinType::kCross:
-            return "cross";
-        case BuiltinType::kDegrees:
-            return "degrees";
-        case BuiltinType::kDeterminant:
-            return "determinant";
-        case BuiltinType::kDistance:
-            return "distance";
-        case BuiltinType::kDot:
-            return "dot";
-        case BuiltinType::kDot4I8Packed:
-            return "dot4I8Packed";
-        case BuiltinType::kDot4U8Packed:
-            return "dot4U8Packed";
-        case BuiltinType::kDpdx:
-            return "dpdx";
-        case BuiltinType::kDpdxCoarse:
-            return "dpdxCoarse";
-        case BuiltinType::kDpdxFine:
-            return "dpdxFine";
-        case BuiltinType::kDpdy:
-            return "dpdy";
-        case BuiltinType::kDpdyCoarse:
-            return "dpdyCoarse";
-        case BuiltinType::kDpdyFine:
-            return "dpdyFine";
-        case BuiltinType::kExp:
-            return "exp";
-        case BuiltinType::kExp2:
-            return "exp2";
-        case BuiltinType::kExtractBits:
-            return "extractBits";
-        case BuiltinType::kFaceForward:
-            return "faceForward";
-        case BuiltinType::kFirstLeadingBit:
-            return "firstLeadingBit";
-        case BuiltinType::kFirstTrailingBit:
-            return "firstTrailingBit";
-        case BuiltinType::kFloor:
-            return "floor";
-        case BuiltinType::kFma:
-            return "fma";
-        case BuiltinType::kFract:
-            return "fract";
-        case BuiltinType::kFrexp:
-            return "frexp";
-        case BuiltinType::kFwidth:
-            return "fwidth";
-        case BuiltinType::kFwidthCoarse:
-            return "fwidthCoarse";
-        case BuiltinType::kFwidthFine:
-            return "fwidthFine";
-        case BuiltinType::kInsertBits:
-            return "insertBits";
-        case BuiltinType::kInverseSqrt:
-            return "inverseSqrt";
-        case BuiltinType::kLdexp:
-            return "ldexp";
-        case BuiltinType::kLength:
-            return "length";
-        case BuiltinType::kLog:
-            return "log";
-        case BuiltinType::kLog2:
-            return "log2";
-        case BuiltinType::kMax:
-            return "max";
-        case BuiltinType::kMin:
-            return "min";
-        case BuiltinType::kMix:
-            return "mix";
-        case BuiltinType::kModf:
-            return "modf";
-        case BuiltinType::kNormalize:
-            return "normalize";
-        case BuiltinType::kPack2X16Float:
-            return "pack2x16float";
-        case BuiltinType::kPack2X16Snorm:
-            return "pack2x16snorm";
-        case BuiltinType::kPack2X16Unorm:
-            return "pack2x16unorm";
-        case BuiltinType::kPack4X8Snorm:
-            return "pack4x8snorm";
-        case BuiltinType::kPack4X8Unorm:
-            return "pack4x8unorm";
-        case BuiltinType::kPow:
-            return "pow";
-        case BuiltinType::kQuantizeToF16:
-            return "quantizeToF16";
-        case BuiltinType::kRadians:
-            return "radians";
-        case BuiltinType::kReflect:
-            return "reflect";
-        case BuiltinType::kRefract:
-            return "refract";
-        case BuiltinType::kReverseBits:
-            return "reverseBits";
-        case BuiltinType::kRound:
-            return "round";
-        case BuiltinType::kSaturate:
-            return "saturate";
-        case BuiltinType::kSelect:
-            return "select";
-        case BuiltinType::kSign:
-            return "sign";
-        case BuiltinType::kSin:
-            return "sin";
-        case BuiltinType::kSinh:
-            return "sinh";
-        case BuiltinType::kSmoothstep:
-            return "smoothstep";
-        case BuiltinType::kSqrt:
-            return "sqrt";
-        case BuiltinType::kStep:
-            return "step";
-        case BuiltinType::kStorageBarrier:
-            return "storageBarrier";
-        case BuiltinType::kTan:
-            return "tan";
-        case BuiltinType::kTanh:
-            return "tanh";
-        case BuiltinType::kTranspose:
-            return "transpose";
-        case BuiltinType::kTrunc:
-            return "trunc";
-        case BuiltinType::kUnpack2X16Float:
-            return "unpack2x16float";
-        case BuiltinType::kUnpack2X16Snorm:
-            return "unpack2x16snorm";
-        case BuiltinType::kUnpack2X16Unorm:
-            return "unpack2x16unorm";
-        case BuiltinType::kUnpack4X8Snorm:
-            return "unpack4x8snorm";
-        case BuiltinType::kUnpack4X8Unorm:
-            return "unpack4x8unorm";
-        case BuiltinType::kWorkgroupBarrier:
-            return "workgroupBarrier";
-        case BuiltinType::kWorkgroupUniformLoad:
-            return "workgroupUniformLoad";
-        case BuiltinType::kTextureDimensions:
-            return "textureDimensions";
-        case BuiltinType::kTextureGather:
-            return "textureGather";
-        case BuiltinType::kTextureGatherCompare:
-            return "textureGatherCompare";
-        case BuiltinType::kTextureNumLayers:
-            return "textureNumLayers";
-        case BuiltinType::kTextureNumLevels:
-            return "textureNumLevels";
-        case BuiltinType::kTextureNumSamples:
-            return "textureNumSamples";
-        case BuiltinType::kTextureSample:
-            return "textureSample";
-        case BuiltinType::kTextureSampleBias:
-            return "textureSampleBias";
-        case BuiltinType::kTextureSampleCompare:
-            return "textureSampleCompare";
-        case BuiltinType::kTextureSampleCompareLevel:
-            return "textureSampleCompareLevel";
-        case BuiltinType::kTextureSampleGrad:
-            return "textureSampleGrad";
-        case BuiltinType::kTextureSampleLevel:
-            return "textureSampleLevel";
-        case BuiltinType::kTextureSampleBaseClampToEdge:
-            return "textureSampleBaseClampToEdge";
-        case BuiltinType::kTextureStore:
-            return "textureStore";
-        case BuiltinType::kTextureLoad:
-            return "textureLoad";
-        case BuiltinType::kAtomicLoad:
-            return "atomicLoad";
-        case BuiltinType::kAtomicStore:
-            return "atomicStore";
-        case BuiltinType::kAtomicAdd:
-            return "atomicAdd";
-        case BuiltinType::kAtomicSub:
-            return "atomicSub";
-        case BuiltinType::kAtomicMax:
-            return "atomicMax";
-        case BuiltinType::kAtomicMin:
-            return "atomicMin";
-        case BuiltinType::kAtomicAnd:
-            return "atomicAnd";
-        case BuiltinType::kAtomicOr:
-            return "atomicOr";
-        case BuiltinType::kAtomicXor:
-            return "atomicXor";
-        case BuiltinType::kAtomicExchange:
-            return "atomicExchange";
-        case BuiltinType::kAtomicCompareExchangeWeak:
-            return "atomicCompareExchangeWeak";
-        case BuiltinType::kTintMaterialize:
-            return "_tint_materialize";
-    }
-    return "<unknown>";
-}
-
-utils::StringStream& operator<<(utils::StringStream& out, BuiltinType i) {
-    out << str(i);
-    return out;
-}
-
-}  // namespace tint::sem
diff --git a/src/tint/sem/builtin_type.cc.tmpl b/src/tint/sem/builtin_type.cc.tmpl
deleted file mode 100644
index 86a8623..0000000
--- a/src/tint/sem/builtin_type.cc.tmpl
+++ /dev/null
@@ -1,44 +0,0 @@
-{{- /*
---------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate builtin_type.cc
-
-To update the generated file, run:
-    ./tools/run gen
-
-See:
-* tools/src/cmd/gen for structures used by this template
-* https://golang.org/pkg/text/template/ for documentation on the template syntax
---------------------------------------------------------------------------------
-*/ -}}
-
-#include "src/tint/sem/builtin_type.h"
-
-namespace tint::sem {
-
-BuiltinType ParseBuiltinType(const std::string& name) {
-{{- range Sem.Builtins  }}
-    if (name == "{{.Name}}") {
-        return BuiltinType::k{{PascalCase .Name}};
-    }
-{{- end  }}
-    return BuiltinType::kNone;
-}
-
-const char* str(BuiltinType i) {
-    switch (i) {
-        case BuiltinType::kNone:
-            return "<none>";
-{{- range Sem.Builtins  }}
-        case BuiltinType::k{{PascalCase .Name}}:
-            return "{{.Name}}";
-{{- end  }}
-    }
-    return "<unknown>";
-}
-
-utils::StringStream& operator<<(utils::StringStream& out, BuiltinType i) {
-    out << str(i);
-    return out;
-}
-
-}  // namespace tint::sem
diff --git a/src/tint/sem/builtin_type.h b/src/tint/sem/builtin_type.h
deleted file mode 100644
index 23f3749..0000000
--- a/src/tint/sem/builtin_type.h
+++ /dev/null
@@ -1,403 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-////////////////////////////////////////////////////////////////////////////////
-// File generated by tools/src/cmd/gen
-// using the template:
-//   src/tint/sem/builtin_type.h.tmpl
-//
-// Do not modify this file directly
-////////////////////////////////////////////////////////////////////////////////
-
-#ifndef SRC_TINT_SEM_BUILTIN_TYPE_H_
-#define SRC_TINT_SEM_BUILTIN_TYPE_H_
-
-#include <string>
-
-#include "src/tint/utils/string_stream.h"
-
-namespace tint::sem {
-
-/// Enumerator of all builtin functions
-enum class BuiltinType {
-    kNone = -1,
-    kAbs,
-    kAcos,
-    kAcosh,
-    kAll,
-    kAny,
-    kArrayLength,
-    kAsin,
-    kAsinh,
-    kAtan,
-    kAtan2,
-    kAtanh,
-    kCeil,
-    kClamp,
-    kCos,
-    kCosh,
-    kCountLeadingZeros,
-    kCountOneBits,
-    kCountTrailingZeros,
-    kCross,
-    kDegrees,
-    kDeterminant,
-    kDistance,
-    kDot,
-    kDot4I8Packed,
-    kDot4U8Packed,
-    kDpdx,
-    kDpdxCoarse,
-    kDpdxFine,
-    kDpdy,
-    kDpdyCoarse,
-    kDpdyFine,
-    kExp,
-    kExp2,
-    kExtractBits,
-    kFaceForward,
-    kFirstLeadingBit,
-    kFirstTrailingBit,
-    kFloor,
-    kFma,
-    kFract,
-    kFrexp,
-    kFwidth,
-    kFwidthCoarse,
-    kFwidthFine,
-    kInsertBits,
-    kInverseSqrt,
-    kLdexp,
-    kLength,
-    kLog,
-    kLog2,
-    kMax,
-    kMin,
-    kMix,
-    kModf,
-    kNormalize,
-    kPack2X16Float,
-    kPack2X16Snorm,
-    kPack2X16Unorm,
-    kPack4X8Snorm,
-    kPack4X8Unorm,
-    kPow,
-    kQuantizeToF16,
-    kRadians,
-    kReflect,
-    kRefract,
-    kReverseBits,
-    kRound,
-    kSaturate,
-    kSelect,
-    kSign,
-    kSin,
-    kSinh,
-    kSmoothstep,
-    kSqrt,
-    kStep,
-    kStorageBarrier,
-    kTan,
-    kTanh,
-    kTranspose,
-    kTrunc,
-    kUnpack2X16Float,
-    kUnpack2X16Snorm,
-    kUnpack2X16Unorm,
-    kUnpack4X8Snorm,
-    kUnpack4X8Unorm,
-    kWorkgroupBarrier,
-    kWorkgroupUniformLoad,
-    kTextureDimensions,
-    kTextureGather,
-    kTextureGatherCompare,
-    kTextureNumLayers,
-    kTextureNumLevels,
-    kTextureNumSamples,
-    kTextureSample,
-    kTextureSampleBias,
-    kTextureSampleCompare,
-    kTextureSampleCompareLevel,
-    kTextureSampleGrad,
-    kTextureSampleLevel,
-    kTextureSampleBaseClampToEdge,
-    kTextureStore,
-    kTextureLoad,
-    kAtomicLoad,
-    kAtomicStore,
-    kAtomicAdd,
-    kAtomicSub,
-    kAtomicMax,
-    kAtomicMin,
-    kAtomicAnd,
-    kAtomicOr,
-    kAtomicXor,
-    kAtomicExchange,
-    kAtomicCompareExchangeWeak,
-    kTintMaterialize,
-};
-
-/// Matches the BuiltinType by name
-/// @param name the builtin name to parse
-/// @returns the parsed BuiltinType, or BuiltinType::kNone if `name` did not
-/// match any builtin.
-BuiltinType ParseBuiltinType(const std::string& name);
-
-/// @returns the name of the builtin function type. The spelling, including
-/// case, matches the name in the WGSL spec.
-const char* str(BuiltinType i);
-
-/// Emits the name of the builtin function type. The spelling, including case,
-/// matches the name in the WGSL spec.
-utils::StringStream& operator<<(utils::StringStream& out, BuiltinType i);
-
-/// All builtin function
-constexpr BuiltinType kBuiltinTypes[] = {
-    BuiltinType::kAbs,
-    BuiltinType::kAcos,
-    BuiltinType::kAcosh,
-    BuiltinType::kAll,
-    BuiltinType::kAny,
-    BuiltinType::kArrayLength,
-    BuiltinType::kAsin,
-    BuiltinType::kAsinh,
-    BuiltinType::kAtan,
-    BuiltinType::kAtan2,
-    BuiltinType::kAtanh,
-    BuiltinType::kCeil,
-    BuiltinType::kClamp,
-    BuiltinType::kCos,
-    BuiltinType::kCosh,
-    BuiltinType::kCountLeadingZeros,
-    BuiltinType::kCountOneBits,
-    BuiltinType::kCountTrailingZeros,
-    BuiltinType::kCross,
-    BuiltinType::kDegrees,
-    BuiltinType::kDeterminant,
-    BuiltinType::kDistance,
-    BuiltinType::kDot,
-    BuiltinType::kDot4I8Packed,
-    BuiltinType::kDot4U8Packed,
-    BuiltinType::kDpdx,
-    BuiltinType::kDpdxCoarse,
-    BuiltinType::kDpdxFine,
-    BuiltinType::kDpdy,
-    BuiltinType::kDpdyCoarse,
-    BuiltinType::kDpdyFine,
-    BuiltinType::kExp,
-    BuiltinType::kExp2,
-    BuiltinType::kExtractBits,
-    BuiltinType::kFaceForward,
-    BuiltinType::kFirstLeadingBit,
-    BuiltinType::kFirstTrailingBit,
-    BuiltinType::kFloor,
-    BuiltinType::kFma,
-    BuiltinType::kFract,
-    BuiltinType::kFrexp,
-    BuiltinType::kFwidth,
-    BuiltinType::kFwidthCoarse,
-    BuiltinType::kFwidthFine,
-    BuiltinType::kInsertBits,
-    BuiltinType::kInverseSqrt,
-    BuiltinType::kLdexp,
-    BuiltinType::kLength,
-    BuiltinType::kLog,
-    BuiltinType::kLog2,
-    BuiltinType::kMax,
-    BuiltinType::kMin,
-    BuiltinType::kMix,
-    BuiltinType::kModf,
-    BuiltinType::kNormalize,
-    BuiltinType::kPack2X16Float,
-    BuiltinType::kPack2X16Snorm,
-    BuiltinType::kPack2X16Unorm,
-    BuiltinType::kPack4X8Snorm,
-    BuiltinType::kPack4X8Unorm,
-    BuiltinType::kPow,
-    BuiltinType::kQuantizeToF16,
-    BuiltinType::kRadians,
-    BuiltinType::kReflect,
-    BuiltinType::kRefract,
-    BuiltinType::kReverseBits,
-    BuiltinType::kRound,
-    BuiltinType::kSaturate,
-    BuiltinType::kSelect,
-    BuiltinType::kSign,
-    BuiltinType::kSin,
-    BuiltinType::kSinh,
-    BuiltinType::kSmoothstep,
-    BuiltinType::kSqrt,
-    BuiltinType::kStep,
-    BuiltinType::kStorageBarrier,
-    BuiltinType::kTan,
-    BuiltinType::kTanh,
-    BuiltinType::kTranspose,
-    BuiltinType::kTrunc,
-    BuiltinType::kUnpack2X16Float,
-    BuiltinType::kUnpack2X16Snorm,
-    BuiltinType::kUnpack2X16Unorm,
-    BuiltinType::kUnpack4X8Snorm,
-    BuiltinType::kUnpack4X8Unorm,
-    BuiltinType::kWorkgroupBarrier,
-    BuiltinType::kWorkgroupUniformLoad,
-    BuiltinType::kTextureDimensions,
-    BuiltinType::kTextureGather,
-    BuiltinType::kTextureGatherCompare,
-    BuiltinType::kTextureNumLayers,
-    BuiltinType::kTextureNumLevels,
-    BuiltinType::kTextureNumSamples,
-    BuiltinType::kTextureSample,
-    BuiltinType::kTextureSampleBias,
-    BuiltinType::kTextureSampleCompare,
-    BuiltinType::kTextureSampleCompareLevel,
-    BuiltinType::kTextureSampleGrad,
-    BuiltinType::kTextureSampleLevel,
-    BuiltinType::kTextureSampleBaseClampToEdge,
-    BuiltinType::kTextureStore,
-    BuiltinType::kTextureLoad,
-    BuiltinType::kAtomicLoad,
-    BuiltinType::kAtomicStore,
-    BuiltinType::kAtomicAdd,
-    BuiltinType::kAtomicSub,
-    BuiltinType::kAtomicMax,
-    BuiltinType::kAtomicMin,
-    BuiltinType::kAtomicAnd,
-    BuiltinType::kAtomicOr,
-    BuiltinType::kAtomicXor,
-    BuiltinType::kAtomicExchange,
-    BuiltinType::kAtomicCompareExchangeWeak,
-    BuiltinType::kTintMaterialize,
-};
-
-/// All builtin function names
-constexpr const char* kBuiltinStrings[] = {
-    "abs",
-    "acos",
-    "acosh",
-    "all",
-    "any",
-    "arrayLength",
-    "asin",
-    "asinh",
-    "atan",
-    "atan2",
-    "atanh",
-    "ceil",
-    "clamp",
-    "cos",
-    "cosh",
-    "countLeadingZeros",
-    "countOneBits",
-    "countTrailingZeros",
-    "cross",
-    "degrees",
-    "determinant",
-    "distance",
-    "dot",
-    "dot4I8Packed",
-    "dot4U8Packed",
-    "dpdx",
-    "dpdxCoarse",
-    "dpdxFine",
-    "dpdy",
-    "dpdyCoarse",
-    "dpdyFine",
-    "exp",
-    "exp2",
-    "extractBits",
-    "faceForward",
-    "firstLeadingBit",
-    "firstTrailingBit",
-    "floor",
-    "fma",
-    "fract",
-    "frexp",
-    "fwidth",
-    "fwidthCoarse",
-    "fwidthFine",
-    "insertBits",
-    "inverseSqrt",
-    "ldexp",
-    "length",
-    "log",
-    "log2",
-    "max",
-    "min",
-    "mix",
-    "modf",
-    "normalize",
-    "pack2x16float",
-    "pack2x16snorm",
-    "pack2x16unorm",
-    "pack4x8snorm",
-    "pack4x8unorm",
-    "pow",
-    "quantizeToF16",
-    "radians",
-    "reflect",
-    "refract",
-    "reverseBits",
-    "round",
-    "saturate",
-    "select",
-    "sign",
-    "sin",
-    "sinh",
-    "smoothstep",
-    "sqrt",
-    "step",
-    "storageBarrier",
-    "tan",
-    "tanh",
-    "transpose",
-    "trunc",
-    "unpack2x16float",
-    "unpack2x16snorm",
-    "unpack2x16unorm",
-    "unpack4x8snorm",
-    "unpack4x8unorm",
-    "workgroupBarrier",
-    "workgroupUniformLoad",
-    "textureDimensions",
-    "textureGather",
-    "textureGatherCompare",
-    "textureNumLayers",
-    "textureNumLevels",
-    "textureNumSamples",
-    "textureSample",
-    "textureSampleBias",
-    "textureSampleCompare",
-    "textureSampleCompareLevel",
-    "textureSampleGrad",
-    "textureSampleLevel",
-    "textureSampleBaseClampToEdge",
-    "textureStore",
-    "textureLoad",
-    "atomicLoad",
-    "atomicStore",
-    "atomicAdd",
-    "atomicSub",
-    "atomicMax",
-    "atomicMin",
-    "atomicAnd",
-    "atomicOr",
-    "atomicXor",
-    "atomicExchange",
-    "atomicCompareExchangeWeak",
-    "_tint_materialize",
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_BUILTIN_TYPE_H_
diff --git a/src/tint/sem/builtin_type.h.tmpl b/src/tint/sem/builtin_type.h.tmpl
deleted file mode 100644
index 366db95..0000000
--- a/src/tint/sem/builtin_type.h.tmpl
+++ /dev/null
@@ -1,61 +0,0 @@
-{{- /*
---------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate builtin_type.h
-
-To update the generated file, run:
-    ./tools/run gen
-
-See:
-* tools/src/cmd/gen for structures used by this template
-* https://golang.org/pkg/text/template/ for documentation on the template syntax
---------------------------------------------------------------------------------
-*/ -}}
-
-#ifndef SRC_TINT_SEM_BUILTIN_TYPE_H_
-#define SRC_TINT_SEM_BUILTIN_TYPE_H_
-
-#include <string>
-
-#include "src/tint/utils/string_stream.h"
-
-namespace tint::sem {
-
-/// Enumerator of all builtin functions
-enum class BuiltinType {
-    kNone = -1,
-{{- range Sem.Builtins }}
-    k{{PascalCase .Name}},
-{{- end }}
-};
-
-/// Matches the BuiltinType by name
-/// @param name the builtin name to parse
-/// @returns the parsed BuiltinType, or BuiltinType::kNone if `name` did not
-/// match any builtin.
-BuiltinType ParseBuiltinType(const std::string& name);
-
-/// @returns the name of the builtin function type. The spelling, including
-/// case, matches the name in the WGSL spec.
-const char* str(BuiltinType i);
-
-/// Emits the name of the builtin function type. The spelling, including case,
-/// matches the name in the WGSL spec.
-utils::StringStream& operator<<(utils::StringStream& out, BuiltinType i);
-
-/// All builtin function
-constexpr BuiltinType kBuiltinTypes[] = {
-{{- range Sem.Builtins }}
-    BuiltinType::k{{PascalCase .Name}},
-{{- end }}
-};
-
-/// All builtin function names
-constexpr const char* kBuiltinStrings[] = {
-{{- range Sem.Builtins }}
-    "{{.Name}}",
-{{- end }}
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_BUILTIN_TYPE_H_
diff --git a/src/tint/transform/array_length_from_uniform.cc b/src/tint/transform/array_length_from_uniform.cc
index 78535f1..a396965 100644
--- a/src/tint/transform/array_length_from_uniform.cc
+++ b/src/tint/transform/array_length_from_uniform.cc
@@ -37,7 +37,7 @@
     for (auto* fn : program->AST().Functions()) {
         if (auto* sem_fn = program->Sem().Get(fn)) {
             for (auto* builtin : sem_fn->DirectlyCalledBuiltins()) {
-                if (builtin->Type() == sem::BuiltinType::kArrayLength) {
+                if (builtin->Type() == builtin::Function::kArrayLength) {
                     return true;
                 }
             }
@@ -199,7 +199,7 @@
 
             auto* call = sem.Get(call_expr)->UnwrapMaterialize()->As<sem::Call>();
             auto* builtin = call->Target()->As<sem::Builtin>();
-            if (!builtin || builtin->Type() != sem::BuiltinType::kArrayLength) {
+            if (!builtin || builtin->Type() != builtin::Function::kArrayLength) {
                 continue;
             }
 
diff --git a/src/tint/transform/builtin_polyfill.cc b/src/tint/transform/builtin_polyfill.cc
index 587dcf0..f66025c 100644
--- a/src/tint/transform/builtin_polyfill.cc
+++ b/src/tint/transform/builtin_polyfill.cc
@@ -1030,28 +1030,28 @@
             call->Target(),  //
             [&](const sem::Builtin* builtin) {
                 switch (builtin->Type()) {
-                    case sem::BuiltinType::kAcosh:
+                    case builtin::Function::kAcosh:
                         if (cfg.builtins.acosh != Level::kNone) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return acosh(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kAsinh:
+                    case builtin::Function::kAsinh:
                         if (cfg.builtins.asinh) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return asinh(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kAtanh:
+                    case builtin::Function::kAtanh:
                         if (cfg.builtins.atanh != Level::kNone) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return atanh(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kClamp:
+                    case builtin::Function::kClamp:
                         if (cfg.builtins.clamp_int) {
                             auto& sig = builtin->Signature();
                             if (sig.parameters[0]->Type()->is_integer_scalar_or_vector()) {
@@ -1061,49 +1061,49 @@
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kCountLeadingZeros:
+                    case builtin::Function::kCountLeadingZeros:
                         if (cfg.builtins.count_leading_zeros) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return countLeadingZeros(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kCountTrailingZeros:
+                    case builtin::Function::kCountTrailingZeros:
                         if (cfg.builtins.count_trailing_zeros) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return countTrailingZeros(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kExtractBits:
+                    case builtin::Function::kExtractBits:
                         if (cfg.builtins.extract_bits != Level::kNone) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return extractBits(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kFirstLeadingBit:
+                    case builtin::Function::kFirstLeadingBit:
                         if (cfg.builtins.first_leading_bit) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return firstLeadingBit(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kFirstTrailingBit:
+                    case builtin::Function::kFirstTrailingBit:
                         if (cfg.builtins.first_trailing_bit) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return firstTrailingBit(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kInsertBits:
+                    case builtin::Function::kInsertBits:
                         if (cfg.builtins.insert_bits != Level::kNone) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return insertBits(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kReflect:
+                    case builtin::Function::kReflect:
                         // Only polyfill for vec2<f32>. See https://crbug.com/tint/1798 for
                         // more details.
                         if (cfg.builtins.reflect_vec2_f32) {
@@ -1116,14 +1116,14 @@
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kSaturate:
+                    case builtin::Function::kSaturate:
                         if (cfg.builtins.saturate) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return saturate(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kSign:
+                    case builtin::Function::kSign:
                         if (cfg.builtins.sign_int) {
                             auto* ty = builtin->ReturnType();
                             if (ty->is_signed_integer_scalar_or_vector()) {
@@ -1133,7 +1133,7 @@
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kTextureSampleBaseClampToEdge:
+                    case builtin::Function::kTextureSampleBaseClampToEdge:
                         if (cfg.builtins.texture_sample_base_clamp_to_edge_2d_f32) {
                             auto& sig = builtin->Signature();
                             auto* tex = sig.Parameter(sem::ParameterUsage::kTexture);
@@ -1147,7 +1147,7 @@
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kTextureStore:
+                    case builtin::Function::kTextureStore:
                         if (cfg.builtins.bgra8unorm) {
                             auto& sig = builtin->Signature();
                             auto* tex = sig.Parameter(sem::ParameterUsage::kTexture);
@@ -1165,7 +1165,7 @@
                                             args.Push(arg);
                                         }
                                         return ctx.dst->Call(
-                                            utils::ToString(sem::BuiltinType::kTextureStore),
+                                            utils::ToString(builtin::Function::kTextureStore),
                                             std::move(args));
                                     });
                                     made_changes = true;
@@ -1174,7 +1174,7 @@
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kQuantizeToF16:
+                    case builtin::Function::kQuantizeToF16:
                         if (cfg.builtins.quantize_to_vec_f16) {
                             if (auto* vec = builtin->ReturnType()->As<type::Vector>()) {
                                 return builtin_polyfills.GetOrCreate(
@@ -1183,7 +1183,7 @@
                         }
                         return Symbol{};
 
-                    case sem::BuiltinType::kWorkgroupUniformLoad:
+                    case builtin::Function::kWorkgroupUniformLoad:
                         if (cfg.builtins.workgroup_uniform_load) {
                             return builtin_polyfills.GetOrCreate(builtin, [&] {
                                 return workgroupUniformLoad(builtin->ReturnType());
diff --git a/src/tint/transform/calculate_array_length.cc b/src/tint/transform/calculate_array_length.cc
index 9f5b659..36ad192 100644
--- a/src/tint/transform/calculate_array_length.cc
+++ b/src/tint/transform/calculate_array_length.cc
@@ -44,7 +44,7 @@
     for (auto* fn : program->AST().Functions()) {
         if (auto* sem_fn = program->Sem().Get(fn)) {
             for (auto* builtin : sem_fn->DirectlyCalledBuiltins()) {
-                if (builtin->Type() == sem::BuiltinType::kArrayLength) {
+                if (builtin->Type() == builtin::Function::kArrayLength) {
                     return true;
                 }
             }
@@ -130,7 +130,7 @@
         if (auto* call_expr = node->As<ast::CallExpression>()) {
             auto* call = sem.Get(call_expr)->UnwrapMaterialize()->As<sem::Call>();
             if (auto* builtin = call->Target()->As<sem::Builtin>()) {
-                if (builtin->Type() == sem::BuiltinType::kArrayLength) {
+                if (builtin->Type() == builtin::Function::kArrayLength) {
                     // We're dealing with an arrayLength() call
 
                     if (auto* call_stmt = call->Stmt()->Declaration()->As<ast::CallStatement>()) {
diff --git a/src/tint/transform/combine_samplers.cc b/src/tint/transform/combine_samplers.cc
index 7b9f9fd..ca8111c 100644
--- a/src/tint/transform/combine_samplers.cc
+++ b/src/tint/transform/combine_samplers.cc
@@ -276,7 +276,7 @@
                         }
                     }
                     const ast::Expression* value = ctx.dst->Call(ctx.Clone(expr->target), args);
-                    if (builtin->Type() == sem::BuiltinType::kTextureLoad &&
+                    if (builtin->Type() == builtin::Function::kTextureLoad &&
                         texture_var->Type()->UnwrapRef()->Is<type::DepthTexture>() &&
                         !call->Stmt()->Declaration()->Is<ast::CallStatement>()) {
                         value = ctx.dst->MemberAccessor(value, "x");
diff --git a/src/tint/transform/decompose_memory_access.cc b/src/tint/transform/decompose_memory_access.cc
index f3d92c5..2ff62b4 100644
--- a/src/tint/transform/decompose_memory_access.cc
+++ b/src/tint/transform/decompose_memory_access.cc
@@ -124,7 +124,7 @@
 /// AtomicKey is the unordered map key to an atomic intrinsic.
 struct AtomicKey {
     type::Type const* el_ty = nullptr;  // element type
-    sem::BuiltinType const op;          // atomic op
+    builtin::Function const op;         // atomic op
     Symbol const buffer;                // buffer name
     bool operator==(const AtomicKey& rhs) const {
         return el_ty == rhs.el_ty && op == rhs.op && buffer == rhs.buffer;
@@ -248,42 +248,42 @@
 /// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied to a stub function for
 /// the atomic op and the type @p ty.
 DecomposeMemoryAccess::Intrinsic* IntrinsicAtomicFor(ProgramBuilder* builder,
-                                                     sem::BuiltinType ity,
+                                                     builtin::Function ity,
                                                      const type::Type* ty,
                                                      const Symbol& buffer) {
     auto op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicLoad;
     switch (ity) {
-        case sem::BuiltinType::kAtomicLoad:
+        case builtin::Function::kAtomicLoad:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicLoad;
             break;
-        case sem::BuiltinType::kAtomicStore:
+        case builtin::Function::kAtomicStore:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicStore;
             break;
-        case sem::BuiltinType::kAtomicAdd:
+        case builtin::Function::kAtomicAdd:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicAdd;
             break;
-        case sem::BuiltinType::kAtomicSub:
+        case builtin::Function::kAtomicSub:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicSub;
             break;
-        case sem::BuiltinType::kAtomicMax:
+        case builtin::Function::kAtomicMax:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicMax;
             break;
-        case sem::BuiltinType::kAtomicMin:
+        case builtin::Function::kAtomicMin:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicMin;
             break;
-        case sem::BuiltinType::kAtomicAnd:
+        case builtin::Function::kAtomicAnd:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicAnd;
             break;
-        case sem::BuiltinType::kAtomicOr:
+        case builtin::Function::kAtomicOr:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicOr;
             break;
-        case sem::BuiltinType::kAtomicXor:
+        case builtin::Function::kAtomicXor:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicXor;
             break;
-        case sem::BuiltinType::kAtomicExchange:
+        case builtin::Function::kAtomicExchange:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicExchange;
             break;
-        case sem::BuiltinType::kAtomicCompareExchangeWeak:
+        case builtin::Function::kAtomicCompareExchangeWeak:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicCompareExchangeWeak;
             break;
         default:
@@ -658,7 +658,7 @@
             ast::Type ret_ty;
 
             // For intrinsics that return a struct, there is no AST node for it, so create one now.
-            if (intrinsic->Type() == sem::BuiltinType::kAtomicCompareExchangeWeak) {
+            if (intrinsic->Type() == builtin::Function::kAtomicCompareExchangeWeak) {
                 auto* str = intrinsic->ReturnType()->As<sem::Struct>();
                 TINT_ASSERT(Transform, str && str->Declaration() == nullptr);
 
@@ -937,7 +937,7 @@
         if (auto* call_expr = node->As<ast::CallExpression>()) {
             auto* call = sem.Get(call_expr)->UnwrapMaterialize()->As<sem::Call>();
             if (auto* builtin = call->Target()->As<sem::Builtin>()) {
-                if (builtin->Type() == sem::BuiltinType::kArrayLength) {
+                if (builtin->Type() == builtin::Function::kArrayLength) {
                     // arrayLength(X)
                     // Don't convert X into a load, this builtin actually requires the real pointer.
                     state.TakeAccess(call_expr->args[0]);
diff --git a/src/tint/transform/demote_to_helper.cc b/src/tint/transform/demote_to_helper.cc
index ac3c15e..1cb6f96 100644
--- a/src/tint/transform/demote_to_helper.cc
+++ b/src/tint/transform/demote_to_helper.cc
@@ -152,13 +152,13 @@
                     return;
                 }
 
-                if (builtin->Type() == sem::BuiltinType::kTextureStore) {
+                if (builtin->Type() == builtin::Function::kTextureStore) {
                     // A call to textureStore() will always be a statement.
                     // Wrap it inside a conditional block.
                     auto* masked_call = b.If(b.Not(flag), b.Block(ctx.Clone(stmt->Declaration())));
                     ctx.Replace(stmt->Declaration(), masked_call);
                 } else if (builtin->IsAtomic() &&
-                           builtin->Type() != sem::BuiltinType::kAtomicLoad) {
+                           builtin->Type() != builtin::Function::kAtomicLoad) {
                     // A call to an atomic builtin can be a statement or an expression.
                     if (auto* call_stmt = stmt->Declaration()->As<ast::CallStatement>();
                         call_stmt && call_stmt->expr == call) {
@@ -179,7 +179,7 @@
                         auto result = b.Sym();
                         ast::Type result_ty;
                         const ast::Statement* masked_call = nullptr;
-                        if (builtin->Type() == sem::BuiltinType::kAtomicCompareExchangeWeak) {
+                        if (builtin->Type() == builtin::Function::kAtomicCompareExchangeWeak) {
                             // Special case for atomicCompareExchangeWeak as we cannot name its
                             // result type. We have to declare an equivalent struct and copy the
                             // original member values over to it.
diff --git a/src/tint/transform/multiplanar_external_texture.cc b/src/tint/transform/multiplanar_external_texture.cc
index 800a057..310bc46 100644
--- a/src/tint/transform/multiplanar_external_texture.cc
+++ b/src/tint/transform/multiplanar_external_texture.cc
@@ -196,7 +196,7 @@
 
             if (builtin && !builtin->Parameters().IsEmpty() &&
                 builtin->Parameters()[0]->Type()->Is<type::ExternalTexture>() &&
-                builtin->Type() != sem::BuiltinType::kTextureDimensions) {
+                builtin->Type() != builtin::Function::kTextureDimensions) {
                 if (auto* var_user =
                         sem.GetVal(expr->args[0])->UnwrapLoad()->As<sem::VariableUser>()) {
                     auto it = new_binding_symbols.find(var_user->Variable());
@@ -210,9 +210,9 @@
                     auto& syms = it->second;
 
                     switch (builtin->Type()) {
-                        case sem::BuiltinType::kTextureLoad:
+                        case builtin::Function::kTextureLoad:
                             return createTextureLoad(call, syms);
-                        case sem::BuiltinType::kTextureSampleBaseClampToEdge:
+                        case builtin::Function::kTextureSampleBaseClampToEdge:
                             return createTextureSampleBaseClampToEdge(expr, syms);
                         default:
                             break;
@@ -310,13 +310,13 @@
     /// builtin function.
     /// @param call_type determines which function body to generate
     /// @returns a statement list that makes of the body of the chosen function
-    auto buildTextureBuiltinBody(sem::BuiltinType call_type) {
+    auto buildTextureBuiltinBody(builtin::Function call_type) {
         utils::Vector<const ast::Statement*, 16> stmts;
         const ast::CallExpression* single_plane_call = nullptr;
         const ast::CallExpression* plane_0_call = nullptr;
         const ast::CallExpression* plane_1_call = nullptr;
         switch (call_type) {
-            case sem::BuiltinType::kTextureSampleBaseClampToEdge:
+            case builtin::Function::kTextureSampleBaseClampToEdge:
                 stmts.Push(b.Decl(b.Let(
                     "modifiedCoords", b.Mul(b.MemberAccessor("params", "coordTransformationMatrix"),
                                             b.vec3<f32>("coord", 1_a)))));
@@ -346,7 +346,7 @@
                 // textureSampleLevel(plane1, smp, plane1_clamped, 0.0);
                 plane_1_call = b.Call("textureSampleLevel", "plane1", "smp", "plane1_clamped", 0_a);
                 break;
-            case sem::BuiltinType::kTextureLoad:
+            case builtin::Function::kTextureLoad:
                 // textureLoad(plane0, coord, 0);
                 single_plane_call = b.Call("textureLoad", "plane0", "coord", 0_a);
                 // textureLoad(plane0, coord, 0);
@@ -433,7 +433,7 @@
                        b.Param("params", b.ty(params_struct_sym)),
                    },
                    b.ty.vec4(b.ty.f32()),
-                   buildTextureBuiltinBody(sem::BuiltinType::kTextureSampleBaseClampToEdge));
+                   buildTextureBuiltinBody(builtin::Function::kTextureSampleBaseClampToEdge));
         }
 
         return b.Call(texture_sample_external_sym, utils::Vector{
@@ -480,7 +480,7 @@
                        b.Param("params", b.ty(params_struct_sym)),
                    },
                    b.ty.vec4(b.ty.f32()),  //
-                   buildTextureBuiltinBody(sem::BuiltinType::kTextureLoad));
+                   buildTextureBuiltinBody(builtin::Function::kTextureLoad));
 
             return name;
         });
diff --git a/src/tint/transform/multiplanar_external_texture.h b/src/tint/transform/multiplanar_external_texture.h
index 2e6f99f..625c756 100644
--- a/src/tint/transform/multiplanar_external_texture.h
+++ b/src/tint/transform/multiplanar_external_texture.h
@@ -19,8 +19,8 @@
 #include <utility>
 
 #include "src/tint/ast/struct_member.h"
+#include "src/tint/builtin/function.h"
 #include "src/tint/sem/binding_point.h"
-#include "src/tint/sem/builtin_type.h"
 #include "src/tint/transform/transform.h"
 
 namespace tint::transform {
diff --git a/src/tint/transform/robustness.cc b/src/tint/transform/robustness.cc
index b79a029..b7a46f5 100644
--- a/src/tint/transform/robustness.cc
+++ b/src/tint/transform/robustness.cc
@@ -231,7 +231,7 @@
                     // Must clamp, even if the index is constant.
 
                     auto* arr_ptr = b.AddressOf(ctx.Clone(expr->Object()->Declaration()));
-                    return b.Sub(b.Call(sem::BuiltinType::kArrayLength, arr_ptr), 1_u);
+                    return b.Sub(b.Call(builtin::Function::kArrayLength, arr_ptr), 1_u);
                 }
                 if (auto count = arr->ConstantCount()) {
                     if (expr->Index()->ConstantValue()) {
@@ -343,7 +343,7 @@
         if (expr_sem->Index()->Type()->is_signed_integer_scalar()) {
             idx = b.Call<u32>(idx);  // u32(idx)
         }
-        auto* clamped_idx = b.Call(sem::BuiltinType::kMin, idx, max);
+        auto* clamped_idx = b.Call(builtin::Function::kMin, idx, max);
         ctx.Replace(expr->Declaration()->index, clamped_idx);
     }
 
@@ -358,14 +358,14 @@
         }
 
         if (predicate) {
-            if (builtin->Type() == sem::BuiltinType::kWorkgroupUniformLoad) {
+            if (builtin->Type() == builtin::Function::kWorkgroupUniformLoad) {
                 // https://www.w3.org/TR/WGSL/#workgroupUniformLoad-builtin:
                 //  "Executes a control barrier synchronization function that affects memory and
                 //   atomic operations in the workgroup address space."
                 // Because the call acts like a control barrier, we need to make sure that we still
                 // trigger a workgroup barrier if the predicate fails.
                 PredicateCall(call, predicate,
-                              b.Block(b.CallStmt(b.Call(sem::BuiltinType::kWorkgroupBarrier))));
+                              b.Block(b.CallStmt(b.Call(builtin::Function::kWorkgroupBarrier))));
             } else {
                 PredicateCall(call, predicate);
             }
@@ -408,7 +408,7 @@
                 // let num_levels = textureNumLevels(texture-arg);
                 num_levels = b.Symbols().New("num_levels");
                 hoist.InsertBefore(
-                    stmt, b.Decl(b.Let(num_levels, b.Call(sem::BuiltinType::kTextureNumLevels,
+                    stmt, b.Decl(b.Let(num_levels, b.Call(builtin::Function::kTextureNumLevels,
                                                           ctx.Clone(texture_arg)))));
 
                 // predicate: level_idx < num_levels
@@ -433,12 +433,12 @@
                 // predicate: all(coords < textureDimensions(texture))
                 auto* dimensions =
                     level_idx.IsValid()
-                        ? b.Call(sem::BuiltinType::kTextureDimensions, ctx.Clone(texture_arg),
-                                 b.Call(sem::BuiltinType::kMin, b.Expr(level_idx),
+                        ? b.Call(builtin::Function::kTextureDimensions, ctx.Clone(texture_arg),
+                                 b.Call(builtin::Function::kMin, b.Expr(level_idx),
                                         b.Sub(num_levels, 1_a)))
-                        : b.Call(sem::BuiltinType::kTextureDimensions, ctx.Clone(texture_arg));
+                        : b.Call(builtin::Function::kTextureDimensions, ctx.Clone(texture_arg));
                 predicate =
-                    And(predicate, b.Call(sem::BuiltinType::kAll, b.LessThan(coords, dimensions)));
+                    And(predicate, b.Call(builtin::Function::kAll, b.LessThan(coords, dimensions)));
 
                 // Replace the level argument with `coord`
                 ctx.Replace(arg, b.Expr(coords));
@@ -448,7 +448,7 @@
         if (array_arg_idx >= 0) {
             // let array_idx = u32(array-arg)
             auto* arg = expr->args[static_cast<size_t>(array_arg_idx)];
-            auto* num_layers = b.Call(sem::BuiltinType::kTextureNumLayers, ctx.Clone(texture_arg));
+            auto* num_layers = b.Call(builtin::Function::kTextureNumLayers, ctx.Clone(texture_arg));
             auto array_idx = b.Symbols().New("array_idx");
             hoist.InsertBefore(stmt, b.Decl(b.Let(array_idx, CastToUnsigned(ctx.Clone(arg), 1u))));
 
@@ -493,10 +493,10 @@
                 const auto* arg = expr->args[static_cast<size_t>(level_arg_idx)];
                 level_idx = b.Symbols().New("level_idx");
                 const auto* num_levels =
-                    b.Call(sem::BuiltinType::kTextureNumLevels, ctx.Clone(texture_arg));
+                    b.Call(builtin::Function::kTextureNumLevels, ctx.Clone(texture_arg));
                 const auto* max = b.Sub(num_levels, 1_a);
                 hoist.InsertBefore(
-                    stmt, b.Decl(b.Let(level_idx, b.Call(sem::BuiltinType::kMin,
+                    stmt, b.Decl(b.Let(level_idx, b.Call(builtin::Function::kMin,
                                                          b.Call<u32>(ctx.Clone(arg)), max))));
                 ctx.Replace(arg, b.Expr(level_idx));
             }
@@ -510,19 +510,19 @@
                 const auto width = WidthOf(param->Type());
                 const auto* dimensions =
                     level_idx.IsValid()
-                        ? b.Call(sem::BuiltinType::kTextureDimensions, ctx.Clone(texture_arg),
+                        ? b.Call(builtin::Function::kTextureDimensions, ctx.Clone(texture_arg),
                                  level_idx)
-                        : b.Call(sem::BuiltinType::kTextureDimensions, ctx.Clone(texture_arg));
+                        : b.Call(builtin::Function::kTextureDimensions, ctx.Clone(texture_arg));
 
                 // dimensions is u32 or vecN<u32>
                 const auto* unsigned_max = b.Sub(dimensions, ScalarOrVec(b.Expr(1_a), width));
                 if (param->Type()->is_signed_integer_scalar_or_vector()) {
                     const auto* zero = ScalarOrVec(b.Expr(0_a), width);
                     const auto* signed_max = CastToSigned(unsigned_max, width);
-                    ctx.Replace(arg,
-                                b.Call(sem::BuiltinType::kClamp, ctx.Clone(arg), zero, signed_max));
+                    ctx.Replace(
+                        arg, b.Call(builtin::Function::kClamp, ctx.Clone(arg), zero, signed_max));
                 } else {
-                    ctx.Replace(arg, b.Call(sem::BuiltinType::kMin, ctx.Clone(arg), unsigned_max));
+                    ctx.Replace(arg, b.Call(builtin::Function::kMin, ctx.Clone(arg), unsigned_max));
                 }
             }
         }
@@ -531,14 +531,15 @@
         if (array_arg_idx >= 0) {
             auto* param = builtin->Parameters()[static_cast<size_t>(array_arg_idx)];
             auto* arg = expr->args[static_cast<size_t>(array_arg_idx)];
-            auto* num_layers = b.Call(sem::BuiltinType::kTextureNumLayers, ctx.Clone(texture_arg));
+            auto* num_layers = b.Call(builtin::Function::kTextureNumLayers, ctx.Clone(texture_arg));
 
             const auto* unsigned_max = b.Sub(num_layers, 1_a);
             if (param->Type()->is_signed_integer_scalar()) {
                 const auto* signed_max = CastToSigned(unsigned_max, 1u);
-                ctx.Replace(arg, b.Call(sem::BuiltinType::kClamp, ctx.Clone(arg), 0_a, signed_max));
+                ctx.Replace(arg,
+                            b.Call(builtin::Function::kClamp, ctx.Clone(arg), 0_a, signed_max));
             } else {
-                ctx.Replace(arg, b.Call(sem::BuiltinType::kMin, ctx.Clone(arg), unsigned_max));
+                ctx.Replace(arg, b.Call(builtin::Function::kMin, ctx.Clone(arg), unsigned_max));
             }
         }
     }
@@ -546,9 +547,10 @@
     /// @param type builtin type
     /// @returns true if the given builtin is a texture function that requires predication or
     /// clamping of arguments.
-    bool TextureBuiltinNeedsRobustness(sem::BuiltinType type) {
-        return type == sem::BuiltinType::kTextureLoad || type == sem::BuiltinType::kTextureStore ||
-               type == sem::BuiltinType::kTextureDimensions;
+    bool TextureBuiltinNeedsRobustness(builtin::Function type) {
+        return type == builtin::Function::kTextureLoad ||
+               type == builtin::Function::kTextureStore ||
+               type == builtin::Function::kTextureDimensions;
     }
 
     /// @returns a bitwise and of the two expressions, or the other expression if one is null.
diff --git a/src/tint/transform/spirv_atomic.cc b/src/tint/transform/spirv_atomic.cc
index 043861b..73c2ae2 100644
--- a/src/tint/transform/spirv_atomic.cc
+++ b/src/tint/transform/spirv_atomic.cc
@@ -81,22 +81,22 @@
                     out_args[0] = b.AddressOf(out_args[0]);
 
                     // Replace all callsites of this stub to a call to the real builtin
-                    if (stub->builtin == sem::BuiltinType::kAtomicCompareExchangeWeak) {
+                    if (stub->builtin == builtin::Function::kAtomicCompareExchangeWeak) {
                         // atomicCompareExchangeWeak returns a struct, so insert a call to it above
                         // the current statement, and replace the current call with the struct's
                         // `old_value` member.
                         auto* block = call->Stmt()->Block()->Declaration();
                         auto old_value = b.Symbols().New("old_value");
                         auto old_value_decl = b.Decl(b.Let(
-                            old_value,
-                            b.MemberAccessor(b.Call(sem::str(stub->builtin), std::move(out_args)),
-                                             "old_value")));
+                            old_value, b.MemberAccessor(
+                                           b.Call(builtin::str(stub->builtin), std::move(out_args)),
+                                           "old_value")));
                         ctx.InsertBefore(block->statements, call->Stmt()->Declaration(),
                                          old_value_decl);
                         ctx.Replace(call->Declaration(), b.Expr(old_value));
                     } else {
                         ctx.Replace(call->Declaration(),
-                                    b.Call(sem::str(stub->builtin), std::move(out_args)));
+                                    b.Call(builtin::str(stub->builtin), std::move(out_args)));
                     }
 
                     // Keep track of this expression. We'll need to modify the root identifier /
@@ -255,7 +255,7 @@
                             ctx.Replace(assign, [=] {
                                 auto* lhs = ctx.CloneWithoutTransform(assign->lhs);
                                 auto* rhs = ctx.CloneWithoutTransform(assign->rhs);
-                                auto* call = b.Call(sem::str(sem::BuiltinType::kAtomicStore),
+                                auto* call = b.Call(builtin::str(builtin::Function::kAtomicStore),
                                                     b.AddressOf(lhs), rhs);
                                 return b.CallStmt(call);
                             });
@@ -266,7 +266,7 @@
                         if (is_ref_to_atomic_var(sem_rhs->UnwrapLoad())) {
                             ctx.Replace(assign->rhs, [=] {
                                 auto* rhs = ctx.CloneWithoutTransform(assign->rhs);
-                                return b.Call(sem::str(sem::BuiltinType::kAtomicLoad),
+                                return b.Call(builtin::str(builtin::Function::kAtomicLoad),
                                               b.AddressOf(rhs));
                             });
                             return;
@@ -278,7 +278,7 @@
                             if (is_ref_to_atomic_var(sem_init->UnwrapLoad())) {
                                 ctx.Replace(var->initializer, [=] {
                                     auto* rhs = ctx.CloneWithoutTransform(var->initializer);
-                                    return b.Call(sem::str(sem::BuiltinType::kAtomicLoad),
+                                    return b.Call(builtin::str(builtin::Function::kAtomicLoad),
                                                   b.AddressOf(rhs));
                                 });
                                 return;
@@ -293,11 +293,11 @@
 SpirvAtomic::SpirvAtomic() = default;
 SpirvAtomic::~SpirvAtomic() = default;
 
-SpirvAtomic::Stub::Stub(ProgramID pid, ast::NodeID nid, sem::BuiltinType b)
+SpirvAtomic::Stub::Stub(ProgramID pid, ast::NodeID nid, builtin::Function b)
     : Base(pid, nid, utils::Empty), builtin(b) {}
 SpirvAtomic::Stub::~Stub() = default;
 std::string SpirvAtomic::Stub::InternalName() const {
-    return "@internal(spirv-atomic " + std::string(sem::str(builtin)) + ")";
+    return "@internal(spirv-atomic " + std::string(builtin::str(builtin)) + ")";
 }
 
 const SpirvAtomic::Stub* SpirvAtomic::Stub::Clone(CloneContext* ctx) const {
diff --git a/src/tint/transform/spirv_atomic.h b/src/tint/transform/spirv_atomic.h
index 0f99dba..b524200 100644
--- a/src/tint/transform/spirv_atomic.h
+++ b/src/tint/transform/spirv_atomic.h
@@ -18,7 +18,7 @@
 #include <string>
 
 #include "src/tint/ast/internal_attribute.h"
-#include "src/tint/sem/builtin_type.h"
+#include "src/tint/builtin/function.h"
 #include "src/tint/transform/transform.h"
 
 // Forward declarations
@@ -46,7 +46,7 @@
         /// @param pid the identifier of the program that owns this node
         /// @param nid the unique node identifier
         /// @param builtin the atomic builtin this stub represents
-        Stub(ProgramID pid, ast::NodeID nid, sem::BuiltinType builtin);
+        Stub(ProgramID pid, ast::NodeID nid, builtin::Function builtin);
         /// Destructor
         ~Stub() override;
 
@@ -60,7 +60,7 @@
         const Stub* Clone(CloneContext* ctx) const override;
 
         /// The type of the intrinsic
-        const sem::BuiltinType builtin;
+        const builtin::Function builtin;
     };
 
     /// @copydoc Transform::Apply
diff --git a/src/tint/transform/spirv_atomic_test.cc b/src/tint/transform/spirv_atomic_test.cc
index 7bb9f2a..29976b5 100644
--- a/src/tint/transform/spirv_atomic_test.cc
+++ b/src/tint/transform/spirv_atomic_test.cc
@@ -36,14 +36,14 @@
 
         auto& b = parser.builder();
 
-        sem::BuiltinType two_params[] = {
-            sem::BuiltinType::kAtomicExchange, sem::BuiltinType::kAtomicAdd,
-            sem::BuiltinType::kAtomicSub,      sem::BuiltinType::kAtomicMin,
-            sem::BuiltinType::kAtomicMax,      sem::BuiltinType::kAtomicAnd,
-            sem::BuiltinType::kAtomicOr,       sem::BuiltinType::kAtomicXor,
+        builtin::Function two_params[] = {
+            builtin::Function::kAtomicExchange, builtin::Function::kAtomicAdd,
+            builtin::Function::kAtomicSub,      builtin::Function::kAtomicMin,
+            builtin::Function::kAtomicMax,      builtin::Function::kAtomicAnd,
+            builtin::Function::kAtomicOr,       builtin::Function::kAtomicXor,
         };
         for (auto& a : two_params) {
-            b.Func(std::string{"stub_"} + sem::str(a) + "_u32",
+            b.Func(std::string{"stub_"} + builtin::str(a) + "_u32",
                    utils::Vector{
                        b.Param("p0", b.ty.u32()),
                        b.Param("p1", b.ty.u32()),
@@ -55,7 +55,7 @@
                    utils::Vector{
                        b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(), a),
                    });
-            b.Func(std::string{"stub_"} + sem::str(a) + "_i32",
+            b.Func(std::string{"stub_"} + builtin::str(a) + "_i32",
                    utils::Vector{
                        b.Param("p0", b.ty.i32()),
                        b.Param("p1", b.ty.i32()),
@@ -79,7 +79,7 @@
                },
                utils::Vector{
                    b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(),
-                                                          sem::BuiltinType::kAtomicLoad),
+                                                          builtin::Function::kAtomicLoad),
                });
         b.Func("stub_atomicLoad_i32",
                utils::Vector{
@@ -91,7 +91,7 @@
                },
                utils::Vector{
                    b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(),
-                                                          sem::BuiltinType::kAtomicLoad),
+                                                          builtin::Function::kAtomicLoad),
                });
 
         b.Func("stub_atomicStore_u32",
@@ -102,7 +102,7 @@
                b.ty.void_(), utils::Empty,
                utils::Vector{
                    b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(),
-                                                          sem::BuiltinType::kAtomicStore),
+                                                          builtin::Function::kAtomicStore),
                });
         b.Func("stub_atomicStore_i32",
                utils::Vector{
@@ -112,7 +112,7 @@
                b.ty.void_(), utils::Empty,
                utils::Vector{
                    b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(),
-                                                          sem::BuiltinType::kAtomicStore),
+                                                          builtin::Function::kAtomicStore),
                });
 
         b.Func("stub_atomic_compare_exchange_weak_u32",
@@ -127,7 +127,7 @@
                },
                utils::Vector{
                    b.ASTNodes().Create<SpirvAtomic::Stub>(
-                       b.ID(), b.AllocateNodeID(), sem::BuiltinType::kAtomicCompareExchangeWeak),
+                       b.ID(), b.AllocateNodeID(), builtin::Function::kAtomicCompareExchangeWeak),
                });
         b.Func("stub_atomic_compare_exchange_weak_i32",
                utils::Vector{b.Param("p0", b.ty.i32()), b.Param("p1", b.ty.i32()),
@@ -138,7 +138,7 @@
                },
                utils::Vector{
                    b.ASTNodes().Create<SpirvAtomic::Stub>(
-                       b.ID(), b.AllocateNodeID(), sem::BuiltinType::kAtomicCompareExchangeWeak),
+                       b.ID(), b.AllocateNodeID(), builtin::Function::kAtomicCompareExchangeWeak),
                });
 
         // Keep this pointer alive after Transform() returns
diff --git a/src/tint/transform/substitute_override.cc b/src/tint/transform/substitute_override.cc
index 2d6b995..e4b2d7b 100644
--- a/src/tint/transform/substitute_override.cc
+++ b/src/tint/transform/substitute_override.cc
@@ -17,6 +17,7 @@
 #include <functional>
 #include <utility>
 
+#include "src/tint/builtin/function.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/builtin.h"
 #include "src/tint/sem/index_accessor_expression.h"
@@ -105,7 +106,7 @@
                 if (auto* access = sem->UnwrapMaterialize()->As<sem::IndexAccessorExpression>()) {
                     if (access->Object()->UnwrapMaterialize()->Type()->HoldsAbstract() &&
                         access->Index()->Stage() == sem::EvaluationStage::kOverride) {
-                        auto* obj = b.Call(sem::str(sem::BuiltinType::kTintMaterialize),
+                        auto* obj = b.Call(builtin::str(builtin::Function::kTintMaterialize),
                                            ctx.Clone(expr->object));
                         return b.IndexAccessor(obj, ctx.Clone(expr->index));
                     }
diff --git a/src/tint/transform/texture_1d_to_2d.cc b/src/tint/transform/texture_1d_to_2d.cc
index d1caaab..5050aa0 100644
--- a/src/tint/transform/texture_1d_to_2d.cc
+++ b/src/tint/transform/texture_1d_to_2d.cc
@@ -137,7 +137,7 @@
                 return nullptr;
             }
 
-            if (builtin->Type() == sem::BuiltinType::kTextureDimensions) {
+            if (builtin->Type() == builtin::Function::kTextureDimensions) {
                 // If this textureDimensions() call is in a CallStatement, we can leave it
                 // unmodified since the return value will be dropped on the floor anyway.
                 if (call->Stmt()->Declaration()->Is<ast::CallStatement>()) {
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index 5e06902..61b281f 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -776,48 +776,49 @@
     if (builtin->IsTexture()) {
         return EmitTextureCall(out, call, builtin);
     }
-    if (builtin->Type() == sem::BuiltinType::kCountOneBits) {
+    if (builtin->Type() == builtin::Function::kCountOneBits) {
         return EmitCountOneBitsCall(out, expr);
     }
-    if (builtin->Type() == sem::BuiltinType::kSelect) {
+    if (builtin->Type() == builtin::Function::kSelect) {
         return EmitSelectCall(out, expr, builtin);
     }
-    if (builtin->Type() == sem::BuiltinType::kDot) {
+    if (builtin->Type() == builtin::Function::kDot) {
         return EmitDotCall(out, expr, builtin);
     }
-    if (builtin->Type() == sem::BuiltinType::kModf) {
+    if (builtin->Type() == builtin::Function::kModf) {
         return EmitModfCall(out, expr, builtin);
     }
-    if (builtin->Type() == sem::BuiltinType::kFrexp) {
+    if (builtin->Type() == builtin::Function::kFrexp) {
         return EmitFrexpCall(out, expr, builtin);
     }
-    if (builtin->Type() == sem::BuiltinType::kDegrees) {
+    if (builtin->Type() == builtin::Function::kDegrees) {
         return EmitDegreesCall(out, expr, builtin);
     }
-    if (builtin->Type() == sem::BuiltinType::kRadians) {
+    if (builtin->Type() == builtin::Function::kRadians) {
         return EmitRadiansCall(out, expr, builtin);
     }
-    if (builtin->Type() == sem::BuiltinType::kQuantizeToF16) {
+    if (builtin->Type() == builtin::Function::kQuantizeToF16) {
         return EmitQuantizeToF16Call(out, expr, builtin);
     }
-    if (builtin->Type() == sem::BuiltinType::kArrayLength) {
+    if (builtin->Type() == builtin::Function::kArrayLength) {
         return EmitArrayLength(out, expr);
     }
-    if (builtin->Type() == sem::BuiltinType::kExtractBits) {
+    if (builtin->Type() == builtin::Function::kExtractBits) {
         return EmitExtractBits(out, expr);
     }
-    if (builtin->Type() == sem::BuiltinType::kInsertBits) {
+    if (builtin->Type() == builtin::Function::kInsertBits) {
         return EmitInsertBits(out, expr);
     }
-    if (builtin->Type() == sem::BuiltinType::kFma && version_.IsES()) {
+    if (builtin->Type() == builtin::Function::kFma && version_.IsES()) {
         return EmitEmulatedFMA(out, expr);
     }
-    if (builtin->Type() == sem::BuiltinType::kAbs &&
+    if (builtin->Type() == builtin::Function::kAbs &&
         TypeOf(expr->args[0])->UnwrapRef()->is_unsigned_integer_scalar_or_vector()) {
         // GLSL does not support abs() on unsigned arguments. However, it's a no-op.
         return EmitExpression(out, expr->args[0]);
     }
-    if ((builtin->Type() == sem::BuiltinType::kAny || builtin->Type() == sem::BuiltinType::kAll) &&
+    if ((builtin->Type() == builtin::Function::kAny ||
+         builtin->Type() == builtin::Function::kAll) &&
         TypeOf(expr->args[0])->UnwrapRef()->is_scalar()) {
         // GLSL does not support any() or all() on scalar arguments. It's a no-op.
         return EmitExpression(out, expr->args[0]);
@@ -919,7 +920,7 @@
     };
 
     switch (builtin->Type()) {
-        case sem::BuiltinType::kAtomicLoad: {
+        case builtin::Function::kAtomicLoad: {
             // GLSL does not have an atomicLoad, so we emulate it with
             // atomicOr using 0 as the OR value
             out << "atomicOr";
@@ -935,7 +936,7 @@
             }
             return true;
         }
-        case sem::BuiltinType::kAtomicCompareExchangeWeak: {
+        case builtin::Function::kAtomicCompareExchangeWeak: {
             if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
                 return false;
             }
@@ -986,27 +987,27 @@
             return true;
         }
 
-        case sem::BuiltinType::kAtomicAdd:
-        case sem::BuiltinType::kAtomicSub:
+        case builtin::Function::kAtomicAdd:
+        case builtin::Function::kAtomicSub:
             return call("atomicAdd");
 
-        case sem::BuiltinType::kAtomicMax:
+        case builtin::Function::kAtomicMax:
             return call("atomicMax");
 
-        case sem::BuiltinType::kAtomicMin:
+        case builtin::Function::kAtomicMin:
             return call("atomicMin");
 
-        case sem::BuiltinType::kAtomicAnd:
+        case builtin::Function::kAtomicAnd:
             return call("atomicAnd");
 
-        case sem::BuiltinType::kAtomicOr:
+        case builtin::Function::kAtomicOr:
             return call("atomicOr");
 
-        case sem::BuiltinType::kAtomicXor:
+        case builtin::Function::kAtomicXor:
             return call("atomicXor");
 
-        case sem::BuiltinType::kAtomicExchange:
-        case sem::BuiltinType::kAtomicStore:
+        case builtin::Function::kAtomicExchange:
+        case builtin::Function::kAtomicStore:
             // GLSL does not have an atomicStore, so we emulate it with
             // atomicExchange.
             return call("atomicExchange");
@@ -1339,13 +1340,13 @@
 bool GeneratorImpl::EmitBarrierCall(utils::StringStream& out, const sem::Builtin* builtin) {
     // TODO(crbug.com/tint/661): Combine sequential barriers to a single
     // instruction.
-    if (builtin->Type() == sem::BuiltinType::kWorkgroupBarrier) {
+    if (builtin->Type() == builtin::Function::kWorkgroupBarrier) {
         out << "barrier()";
-    } else if (builtin->Type() == sem::BuiltinType::kStorageBarrier) {
+    } else if (builtin->Type() == builtin::Function::kStorageBarrier) {
         out << "{ barrier(); memoryBarrierBuffer(); }";
     } else {
         TINT_UNREACHABLE(Writer, diagnostics_)
-            << "unexpected barrier builtin type " << sem::str(builtin->Type());
+            << "unexpected barrier builtin type " << builtin::str(builtin->Type());
         return false;
     }
     return true;
@@ -1415,7 +1416,7 @@
     };
 
     switch (builtin->Type()) {
-        case sem::BuiltinType::kTextureDimensions: {
+        case builtin::Function::kTextureDimensions: {
             // textureDimensions() returns an unsigned scalar / vector in WGSL.
             // textureSize() / imageSize() returns a signed scalar / vector in GLSL.
             // Cast.
@@ -1454,7 +1455,7 @@
             }
             return true;
         }
-        case sem::BuiltinType::kTextureNumLayers: {
+        case builtin::Function::kTextureNumLayers: {
             // textureNumLayers() returns an unsigned scalar in WGSL.
             // textureSize() / imageSize() returns a signed scalar / vector in GLSL.
             // Cast.
@@ -1488,7 +1489,7 @@
             out << ").z";
             return true;
         }
-        case sem::BuiltinType::kTextureNumLevels: {
+        case builtin::Function::kTextureNumLevels: {
             // textureNumLevels() returns an unsigned scalar in WGSL.
             // textureQueryLevels() returns a signed scalar in GLSL.
             // Cast.
@@ -1502,7 +1503,7 @@
             out << ")";
             return true;
         }
-        case sem::BuiltinType::kTextureNumSamples: {
+        case builtin::Function::kTextureNumSamples: {
             // textureNumSamples() returns an unsigned scalar in WGSL.
             // textureSamples() returns a signed scalar in GLSL.
             // Cast.
@@ -1525,36 +1526,36 @@
     bool is_depth = texture_type->Is<type::DepthTexture>();
 
     switch (builtin->Type()) {
-        case sem::BuiltinType::kTextureSample:
-        case sem::BuiltinType::kTextureSampleBias:
+        case builtin::Function::kTextureSample:
+        case builtin::Function::kTextureSampleBias:
             out << "texture";
             if (is_depth) {
                 glsl_ret_width = 1u;
             }
             break;
-        case sem::BuiltinType::kTextureSampleLevel:
+        case builtin::Function::kTextureSampleLevel:
             out << "textureLod";
             if (is_depth) {
                 glsl_ret_width = 1u;
             }
             break;
-        case sem::BuiltinType::kTextureGather:
-        case sem::BuiltinType::kTextureGatherCompare:
+        case builtin::Function::kTextureGather:
+        case builtin::Function::kTextureGatherCompare:
             out << "textureGather";
             append_depth_ref_to_coords = false;
             break;
-        case sem::BuiltinType::kTextureSampleGrad:
+        case builtin::Function::kTextureSampleGrad:
             out << "textureGrad";
             break;
-        case sem::BuiltinType::kTextureSampleCompare:
-        case sem::BuiltinType::kTextureSampleCompareLevel:
+        case builtin::Function::kTextureSampleCompare:
+        case builtin::Function::kTextureSampleCompareLevel:
             out << "texture";
             glsl_ret_width = 1;
             break;
-        case sem::BuiltinType::kTextureLoad:
+        case builtin::Function::kTextureLoad:
             out << "texelFetch";
             break;
-        case sem::BuiltinType::kTextureStore:
+        case builtin::Function::kTextureStore:
             out << "imageStore";
             break;
         default:
@@ -1633,7 +1634,7 @@
     }
 
     // GLSL's textureGather always requires a refZ parameter.
-    if (is_depth && builtin->Type() == sem::BuiltinType::kTextureGather) {
+    if (is_depth && builtin->Type() == builtin::Function::kTextureGather) {
         out << ", 0.0";
     }
 
@@ -1644,7 +1645,7 @@
             if (!EmitExpression(out, e)) {
                 return false;
             }
-        } else if (builtin->Type() == sem::BuiltinType::kTextureSample) {
+        } else if (builtin->Type() == builtin::Function::kTextureSample) {
             out << ", 0.0f";
         }
     }
@@ -1688,114 +1689,114 @@
 
 std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
     switch (builtin->Type()) {
-        case sem::BuiltinType::kAbs:
-        case sem::BuiltinType::kAcos:
-        case sem::BuiltinType::kAcosh:
-        case sem::BuiltinType::kAll:
-        case sem::BuiltinType::kAny:
-        case sem::BuiltinType::kAsin:
-        case sem::BuiltinType::kAsinh:
-        case sem::BuiltinType::kAtan:
-        case sem::BuiltinType::kAtanh:
-        case sem::BuiltinType::kCeil:
-        case sem::BuiltinType::kClamp:
-        case sem::BuiltinType::kCos:
-        case sem::BuiltinType::kCosh:
-        case sem::BuiltinType::kCross:
-        case sem::BuiltinType::kDeterminant:
-        case sem::BuiltinType::kDistance:
-        case sem::BuiltinType::kDot:
-        case sem::BuiltinType::kExp:
-        case sem::BuiltinType::kExp2:
-        case sem::BuiltinType::kFloor:
-        case sem::BuiltinType::kFrexp:
-        case sem::BuiltinType::kLdexp:
-        case sem::BuiltinType::kLength:
-        case sem::BuiltinType::kLog:
-        case sem::BuiltinType::kLog2:
-        case sem::BuiltinType::kMax:
-        case sem::BuiltinType::kMin:
-        case sem::BuiltinType::kModf:
-        case sem::BuiltinType::kNormalize:
-        case sem::BuiltinType::kPow:
-        case sem::BuiltinType::kReflect:
-        case sem::BuiltinType::kRefract:
-        case sem::BuiltinType::kRound:
-        case sem::BuiltinType::kSign:
-        case sem::BuiltinType::kSin:
-        case sem::BuiltinType::kSinh:
-        case sem::BuiltinType::kSqrt:
-        case sem::BuiltinType::kStep:
-        case sem::BuiltinType::kTan:
-        case sem::BuiltinType::kTanh:
-        case sem::BuiltinType::kTranspose:
-        case sem::BuiltinType::kTrunc:
+        case builtin::Function::kAbs:
+        case builtin::Function::kAcos:
+        case builtin::Function::kAcosh:
+        case builtin::Function::kAll:
+        case builtin::Function::kAny:
+        case builtin::Function::kAsin:
+        case builtin::Function::kAsinh:
+        case builtin::Function::kAtan:
+        case builtin::Function::kAtanh:
+        case builtin::Function::kCeil:
+        case builtin::Function::kClamp:
+        case builtin::Function::kCos:
+        case builtin::Function::kCosh:
+        case builtin::Function::kCross:
+        case builtin::Function::kDeterminant:
+        case builtin::Function::kDistance:
+        case builtin::Function::kDot:
+        case builtin::Function::kExp:
+        case builtin::Function::kExp2:
+        case builtin::Function::kFloor:
+        case builtin::Function::kFrexp:
+        case builtin::Function::kLdexp:
+        case builtin::Function::kLength:
+        case builtin::Function::kLog:
+        case builtin::Function::kLog2:
+        case builtin::Function::kMax:
+        case builtin::Function::kMin:
+        case builtin::Function::kModf:
+        case builtin::Function::kNormalize:
+        case builtin::Function::kPow:
+        case builtin::Function::kReflect:
+        case builtin::Function::kRefract:
+        case builtin::Function::kRound:
+        case builtin::Function::kSign:
+        case builtin::Function::kSin:
+        case builtin::Function::kSinh:
+        case builtin::Function::kSqrt:
+        case builtin::Function::kStep:
+        case builtin::Function::kTan:
+        case builtin::Function::kTanh:
+        case builtin::Function::kTranspose:
+        case builtin::Function::kTrunc:
             return builtin->str();
-        case sem::BuiltinType::kAtan2:
+        case builtin::Function::kAtan2:
             return "atan";
-        case sem::BuiltinType::kCountOneBits:
+        case builtin::Function::kCountOneBits:
             return "bitCount";
-        case sem::BuiltinType::kDpdx:
+        case builtin::Function::kDpdx:
             return "dFdx";
-        case sem::BuiltinType::kDpdxCoarse:
+        case builtin::Function::kDpdxCoarse:
             if (version_.IsES()) {
                 return "dFdx";
             }
             return "dFdxCoarse";
-        case sem::BuiltinType::kDpdxFine:
+        case builtin::Function::kDpdxFine:
             if (version_.IsES()) {
                 return "dFdx";
             }
             return "dFdxFine";
-        case sem::BuiltinType::kDpdy:
+        case builtin::Function::kDpdy:
             return "dFdy";
-        case sem::BuiltinType::kDpdyCoarse:
+        case builtin::Function::kDpdyCoarse:
             if (version_.IsES()) {
                 return "dFdy";
             }
             return "dFdyCoarse";
-        case sem::BuiltinType::kDpdyFine:
+        case builtin::Function::kDpdyFine:
             if (version_.IsES()) {
                 return "dFdy";
             }
             return "dFdyFine";
-        case sem::BuiltinType::kFaceForward:
+        case builtin::Function::kFaceForward:
             return "faceforward";
-        case sem::BuiltinType::kFract:
+        case builtin::Function::kFract:
             return "fract";
-        case sem::BuiltinType::kFma:
+        case builtin::Function::kFma:
             return "fma";
-        case sem::BuiltinType::kFwidth:
-        case sem::BuiltinType::kFwidthCoarse:
-        case sem::BuiltinType::kFwidthFine:
+        case builtin::Function::kFwidth:
+        case builtin::Function::kFwidthCoarse:
+        case builtin::Function::kFwidthFine:
             return "fwidth";
-        case sem::BuiltinType::kInverseSqrt:
+        case builtin::Function::kInverseSqrt:
             return "inversesqrt";
-        case sem::BuiltinType::kMix:
+        case builtin::Function::kMix:
             return "mix";
-        case sem::BuiltinType::kPack2X16Float:
+        case builtin::Function::kPack2X16Float:
             return "packHalf2x16";
-        case sem::BuiltinType::kPack2X16Snorm:
+        case builtin::Function::kPack2X16Snorm:
             return "packSnorm2x16";
-        case sem::BuiltinType::kPack2X16Unorm:
+        case builtin::Function::kPack2X16Unorm:
             return "packUnorm2x16";
-        case sem::BuiltinType::kPack4X8Snorm:
+        case builtin::Function::kPack4X8Snorm:
             return "packSnorm4x8";
-        case sem::BuiltinType::kPack4X8Unorm:
+        case builtin::Function::kPack4X8Unorm:
             return "packUnorm4x8";
-        case sem::BuiltinType::kReverseBits:
+        case builtin::Function::kReverseBits:
             return "bitfieldReverse";
-        case sem::BuiltinType::kSmoothstep:
+        case builtin::Function::kSmoothstep:
             return "smoothstep";
-        case sem::BuiltinType::kUnpack2X16Float:
+        case builtin::Function::kUnpack2X16Float:
             return "unpackHalf2x16";
-        case sem::BuiltinType::kUnpack2X16Snorm:
+        case builtin::Function::kUnpack2X16Snorm:
             return "unpackSnorm2x16";
-        case sem::BuiltinType::kUnpack2X16Unorm:
+        case builtin::Function::kUnpack2X16Unorm:
             return "unpackUnorm2x16";
-        case sem::BuiltinType::kUnpack4X8Snorm:
+        case builtin::Function::kUnpack4X8Snorm:
             return "unpackSnorm4x8";
-        case sem::BuiltinType::kUnpack4X8Unorm:
+        case builtin::Function::kUnpack4X8Unorm:
             return "unpackUnorm4x8";
         default:
             diagnostics_.add_error(diag::System::Writer,
@@ -3236,7 +3237,7 @@
         TextBuffer b;
         TINT_DEFER(helpers_.Append(b));
 
-        auto fn_name = UniqueIdentifier(std::string("tint_") + sem::str(builtin->Type()));
+        auto fn_name = UniqueIdentifier(std::string("tint_") + builtin::str(builtin->Type()));
         std::vector<std::string> parameter_names;
         {
             auto decl = line(&b);
diff --git a/src/tint/writer/glsl/generator_impl_builtin_test.cc b/src/tint/writer/glsl/generator_impl_builtin_test.cc
index 19bf555..27cd717 100644
--- a/src/tint/writer/glsl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/glsl/generator_impl_builtin_test.cc
@@ -26,8 +26,6 @@
 namespace tint::writer::glsl {
 namespace {
 
-using BuiltinType = sem::BuiltinType;
-
 using GlslGeneratorImplTest_Builtin = TestHelper;
 
 enum class CallParamType {
@@ -38,7 +36,7 @@
 };
 
 struct BuiltinData {
-    BuiltinType builtin;
+    builtin::Function builtin;
     CallParamType type;
     const char* glsl_name;
 };
@@ -62,86 +60,86 @@
     return out;
 }
 
-const ast::CallExpression* GenerateCall(BuiltinType builtin,
+const ast::CallExpression* GenerateCall(builtin::Function builtin,
                                         CallParamType type,
                                         ProgramBuilder* builder) {
     std::string name;
     utils::StringStream str;
     str << name << builtin;
     switch (builtin) {
-        case BuiltinType::kAcos:
-        case BuiltinType::kAsin:
-        case BuiltinType::kAtan:
-        case BuiltinType::kCeil:
-        case BuiltinType::kCos:
-        case BuiltinType::kCosh:
-        case BuiltinType::kDpdx:
-        case BuiltinType::kDpdxCoarse:
-        case BuiltinType::kDpdxFine:
-        case BuiltinType::kDpdy:
-        case BuiltinType::kDpdyCoarse:
-        case BuiltinType::kDpdyFine:
-        case BuiltinType::kExp:
-        case BuiltinType::kExp2:
-        case BuiltinType::kFloor:
-        case BuiltinType::kFract:
-        case BuiltinType::kFwidth:
-        case BuiltinType::kFwidthCoarse:
-        case BuiltinType::kFwidthFine:
-        case BuiltinType::kInverseSqrt:
-        case BuiltinType::kLength:
-        case BuiltinType::kLog:
-        case BuiltinType::kLog2:
-        case BuiltinType::kNormalize:
-        case BuiltinType::kRound:
-        case BuiltinType::kSin:
-        case BuiltinType::kSinh:
-        case BuiltinType::kSqrt:
-        case BuiltinType::kTan:
-        case BuiltinType::kTanh:
-        case BuiltinType::kTrunc:
-        case BuiltinType::kSign:
+        case builtin::Function::kAcos:
+        case builtin::Function::kAsin:
+        case builtin::Function::kAtan:
+        case builtin::Function::kCeil:
+        case builtin::Function::kCos:
+        case builtin::Function::kCosh:
+        case builtin::Function::kDpdx:
+        case builtin::Function::kDpdxCoarse:
+        case builtin::Function::kDpdxFine:
+        case builtin::Function::kDpdy:
+        case builtin::Function::kDpdyCoarse:
+        case builtin::Function::kDpdyFine:
+        case builtin::Function::kExp:
+        case builtin::Function::kExp2:
+        case builtin::Function::kFloor:
+        case builtin::Function::kFract:
+        case builtin::Function::kFwidth:
+        case builtin::Function::kFwidthCoarse:
+        case builtin::Function::kFwidthFine:
+        case builtin::Function::kInverseSqrt:
+        case builtin::Function::kLength:
+        case builtin::Function::kLog:
+        case builtin::Function::kLog2:
+        case builtin::Function::kNormalize:
+        case builtin::Function::kRound:
+        case builtin::Function::kSin:
+        case builtin::Function::kSinh:
+        case builtin::Function::kSqrt:
+        case builtin::Function::kTan:
+        case builtin::Function::kTanh:
+        case builtin::Function::kTrunc:
+        case builtin::Function::kSign:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2");
             } else {
                 return builder->Call(str.str(), "f2");
             }
-        case BuiltinType::kLdexp:
+        case builtin::Function::kLdexp:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "i2");
             } else {
                 return builder->Call(str.str(), "f2", "i2");
             }
-        case BuiltinType::kAtan2:
-        case BuiltinType::kDot:
-        case BuiltinType::kDistance:
-        case BuiltinType::kPow:
-        case BuiltinType::kReflect:
-        case BuiltinType::kStep:
+        case builtin::Function::kAtan2:
+        case builtin::Function::kDot:
+        case builtin::Function::kDistance:
+        case builtin::Function::kPow:
+        case builtin::Function::kReflect:
+        case builtin::Function::kStep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2");
             }
-        case BuiltinType::kCross:
+        case builtin::Function::kCross:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h3", "h3");
             } else {
                 return builder->Call(str.str(), "f3", "f3");
             }
-        case BuiltinType::kFma:
-        case BuiltinType::kMix:
-        case BuiltinType::kFaceForward:
-        case BuiltinType::kSmoothstep:
+        case builtin::Function::kFma:
+        case builtin::Function::kMix:
+        case builtin::Function::kFaceForward:
+        case builtin::Function::kSmoothstep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             }
-        case BuiltinType::kAll:
-        case BuiltinType::kAny:
+        case builtin::Function::kAll:
+        case builtin::Function::kAny:
             return builder->Call(str.str(), "b2");
-        case BuiltinType::kAbs:
+        case builtin::Function::kAbs:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2");
             } else if (type == CallParamType::kF16) {
@@ -149,11 +147,11 @@
             } else {
                 return builder->Call(str.str(), "u2");
             }
-        case BuiltinType::kCountOneBits:
-        case BuiltinType::kReverseBits:
+        case builtin::Function::kCountOneBits:
+        case builtin::Function::kReverseBits:
             return builder->Call(str.str(), "u2");
-        case BuiltinType::kMax:
-        case BuiltinType::kMin:
+        case builtin::Function::kMax:
+        case builtin::Function::kMin:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -161,7 +159,7 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2");
             }
-        case BuiltinType::kClamp:
+        case builtin::Function::kClamp:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -169,19 +167,19 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2", "u2");
             }
-        case BuiltinType::kSelect:
+        case builtin::Function::kSelect:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "b2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "b2");
             }
-        case BuiltinType::kDeterminant:
+        case builtin::Function::kDeterminant:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm2x2");
             } else {
                 return builder->Call(str.str(), "m2x2");
             }
-        case BuiltinType::kTranspose:
+        case builtin::Function::kTranspose:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm3x2");
             } else {
@@ -235,110 +233,111 @@
 INSTANTIATE_TEST_SUITE_P(
     GlslGeneratorImplTest_Builtin,
     GlslBuiltinTest,
-    testing::Values(/* Logical built-in */
-                    BuiltinData{BuiltinType::kAll, CallParamType::kBool, "all"},
-                    BuiltinData{BuiltinType::kAny, CallParamType::kBool, "any"},
-                    /* Float built-in */
-                    BuiltinData{BuiltinType::kAbs, CallParamType::kF32, "abs"},
-                    BuiltinData{BuiltinType::kAbs, CallParamType::kF16, "abs"},
-                    BuiltinData{BuiltinType::kAcos, CallParamType::kF32, "acos"},
-                    BuiltinData{BuiltinType::kAcos, CallParamType::kF16, "acos"},
-                    BuiltinData{BuiltinType::kAsin, CallParamType::kF32, "asin"},
-                    BuiltinData{BuiltinType::kAsin, CallParamType::kF16, "asin"},
-                    BuiltinData{BuiltinType::kAtan, CallParamType::kF32, "atan"},
-                    BuiltinData{BuiltinType::kAtan, CallParamType::kF16, "atan"},
-                    BuiltinData{BuiltinType::kAtan2, CallParamType::kF32, "atan"},
-                    BuiltinData{BuiltinType::kAtan2, CallParamType::kF16, "atan"},
-                    BuiltinData{BuiltinType::kCeil, CallParamType::kF32, "ceil"},
-                    BuiltinData{BuiltinType::kCeil, CallParamType::kF16, "ceil"},
-                    BuiltinData{BuiltinType::kClamp, CallParamType::kF32, "clamp"},
-                    BuiltinData{BuiltinType::kClamp, CallParamType::kF16, "clamp"},
-                    BuiltinData{BuiltinType::kCos, CallParamType::kF32, "cos"},
-                    BuiltinData{BuiltinType::kCos, CallParamType::kF16, "cos"},
-                    BuiltinData{BuiltinType::kCosh, CallParamType::kF32, "cosh"},
-                    BuiltinData{BuiltinType::kCosh, CallParamType::kF16, "cosh"},
-                    BuiltinData{BuiltinType::kCross, CallParamType::kF32, "cross"},
-                    BuiltinData{BuiltinType::kCross, CallParamType::kF16, "cross"},
-                    BuiltinData{BuiltinType::kDistance, CallParamType::kF32, "distance"},
-                    BuiltinData{BuiltinType::kDistance, CallParamType::kF16, "distance"},
-                    BuiltinData{BuiltinType::kExp, CallParamType::kF32, "exp"},
-                    BuiltinData{BuiltinType::kExp, CallParamType::kF16, "exp"},
-                    BuiltinData{BuiltinType::kExp2, CallParamType::kF32, "exp2"},
-                    BuiltinData{BuiltinType::kExp2, CallParamType::kF16, "exp2"},
-                    BuiltinData{BuiltinType::kFaceForward, CallParamType::kF32, "faceforward"},
-                    BuiltinData{BuiltinType::kFaceForward, CallParamType::kF16, "faceforward"},
-                    BuiltinData{BuiltinType::kFloor, CallParamType::kF32, "floor"},
-                    BuiltinData{BuiltinType::kFloor, CallParamType::kF16, "floor"},
-                    BuiltinData{BuiltinType::kFma, CallParamType::kF32, "fma"},
-                    BuiltinData{BuiltinType::kFma, CallParamType::kF16, "fma"},
-                    BuiltinData{BuiltinType::kFract, CallParamType::kF32, "fract"},
-                    BuiltinData{BuiltinType::kFract, CallParamType::kF16, "fract"},
-                    BuiltinData{BuiltinType::kInverseSqrt, CallParamType::kF32, "inversesqrt"},
-                    BuiltinData{BuiltinType::kInverseSqrt, CallParamType::kF16, "inversesqrt"},
-                    BuiltinData{BuiltinType::kLdexp, CallParamType::kF32, "ldexp"},
-                    BuiltinData{BuiltinType::kLdexp, CallParamType::kF16, "ldexp"},
-                    BuiltinData{BuiltinType::kLength, CallParamType::kF32, "length"},
-                    BuiltinData{BuiltinType::kLength, CallParamType::kF16, "length"},
-                    BuiltinData{BuiltinType::kLog, CallParamType::kF32, "log"},
-                    BuiltinData{BuiltinType::kLog, CallParamType::kF16, "log"},
-                    BuiltinData{BuiltinType::kLog2, CallParamType::kF32, "log2"},
-                    BuiltinData{BuiltinType::kLog2, CallParamType::kF16, "log2"},
-                    BuiltinData{BuiltinType::kMax, CallParamType::kF32, "max"},
-                    BuiltinData{BuiltinType::kMax, CallParamType::kF16, "max"},
-                    BuiltinData{BuiltinType::kMin, CallParamType::kF32, "min"},
-                    BuiltinData{BuiltinType::kMin, CallParamType::kF16, "min"},
-                    BuiltinData{BuiltinType::kMix, CallParamType::kF32, "mix"},
-                    BuiltinData{BuiltinType::kMix, CallParamType::kF16, "mix"},
-                    BuiltinData{BuiltinType::kNormalize, CallParamType::kF32, "normalize"},
-                    BuiltinData{BuiltinType::kNormalize, CallParamType::kF16, "normalize"},
-                    BuiltinData{BuiltinType::kPow, CallParamType::kF32, "pow"},
-                    BuiltinData{BuiltinType::kPow, CallParamType::kF16, "pow"},
-                    BuiltinData{BuiltinType::kReflect, CallParamType::kF32, "reflect"},
-                    BuiltinData{BuiltinType::kReflect, CallParamType::kF16, "reflect"},
-                    BuiltinData{BuiltinType::kSign, CallParamType::kF32, "sign"},
-                    BuiltinData{BuiltinType::kSign, CallParamType::kF16, "sign"},
-                    BuiltinData{BuiltinType::kSin, CallParamType::kF32, "sin"},
-                    BuiltinData{BuiltinType::kSin, CallParamType::kF16, "sin"},
-                    BuiltinData{BuiltinType::kSinh, CallParamType::kF32, "sinh"},
-                    BuiltinData{BuiltinType::kSinh, CallParamType::kF16, "sinh"},
-                    BuiltinData{BuiltinType::kSmoothstep, CallParamType::kF32, "smoothstep"},
-                    BuiltinData{BuiltinType::kSmoothstep, CallParamType::kF16, "smoothstep"},
-                    BuiltinData{BuiltinType::kSqrt, CallParamType::kF32, "sqrt"},
-                    BuiltinData{BuiltinType::kSqrt, CallParamType::kF16, "sqrt"},
-                    BuiltinData{BuiltinType::kStep, CallParamType::kF32, "step"},
-                    BuiltinData{BuiltinType::kStep, CallParamType::kF16, "step"},
-                    BuiltinData{BuiltinType::kTan, CallParamType::kF32, "tan"},
-                    BuiltinData{BuiltinType::kTan, CallParamType::kF16, "tan"},
-                    BuiltinData{BuiltinType::kTanh, CallParamType::kF32, "tanh"},
-                    BuiltinData{BuiltinType::kTanh, CallParamType::kF16, "tanh"},
-                    BuiltinData{BuiltinType::kTrunc, CallParamType::kF32, "trunc"},
-                    BuiltinData{BuiltinType::kTrunc, CallParamType::kF16, "trunc"},
-                    /* Integer built-in */
-                    BuiltinData{BuiltinType::kAbs, CallParamType::kU32, "abs"},
-                    BuiltinData{BuiltinType::kClamp, CallParamType::kU32, "clamp"},
-                    BuiltinData{BuiltinType::kCountOneBits, CallParamType::kU32, "bitCount"},
-                    BuiltinData{BuiltinType::kMax, CallParamType::kU32, "max"},
-                    BuiltinData{BuiltinType::kMin, CallParamType::kU32, "min"},
-                    BuiltinData{BuiltinType::kReverseBits, CallParamType::kU32, "bitfieldReverse"},
-                    BuiltinData{BuiltinType::kRound, CallParamType::kU32, "round"},
-                    /* Matrix built-in */
-                    BuiltinData{BuiltinType::kDeterminant, CallParamType::kF32, "determinant"},
-                    BuiltinData{BuiltinType::kDeterminant, CallParamType::kF16, "determinant"},
-                    BuiltinData{BuiltinType::kTranspose, CallParamType::kF32, "transpose"},
-                    BuiltinData{BuiltinType::kTranspose, CallParamType::kF16, "transpose"},
-                    /* Vector built-in */
-                    BuiltinData{BuiltinType::kDot, CallParamType::kF32, "dot"},
-                    BuiltinData{BuiltinType::kDot, CallParamType::kF16, "dot"},
-                    /* Derivate built-in */
-                    BuiltinData{BuiltinType::kDpdx, CallParamType::kF32, "dFdx"},
-                    BuiltinData{BuiltinType::kDpdxCoarse, CallParamType::kF32, "dFdx"},
-                    BuiltinData{BuiltinType::kDpdxFine, CallParamType::kF32, "dFdx"},
-                    BuiltinData{BuiltinType::kDpdy, CallParamType::kF32, "dFdy"},
-                    BuiltinData{BuiltinType::kDpdyCoarse, CallParamType::kF32, "dFdy"},
-                    BuiltinData{BuiltinType::kDpdyFine, CallParamType::kF32, "dFdy"},
-                    BuiltinData{BuiltinType::kFwidth, CallParamType::kF32, "fwidth"},
-                    BuiltinData{BuiltinType::kFwidthCoarse, CallParamType::kF32, "fwidth"},
-                    BuiltinData{BuiltinType::kFwidthFine, CallParamType::kF32, "fwidth"}));
+    testing::
+        Values(/* Logical built-in */
+               BuiltinData{builtin::Function::kAll, CallParamType::kBool, "all"},
+               BuiltinData{builtin::Function::kAny, CallParamType::kBool, "any"},
+               /* Float built-in */
+               BuiltinData{builtin::Function::kAbs, CallParamType::kF32, "abs"},
+               BuiltinData{builtin::Function::kAbs, CallParamType::kF16, "abs"},
+               BuiltinData{builtin::Function::kAcos, CallParamType::kF32, "acos"},
+               BuiltinData{builtin::Function::kAcos, CallParamType::kF16, "acos"},
+               BuiltinData{builtin::Function::kAsin, CallParamType::kF32, "asin"},
+               BuiltinData{builtin::Function::kAsin, CallParamType::kF16, "asin"},
+               BuiltinData{builtin::Function::kAtan, CallParamType::kF32, "atan"},
+               BuiltinData{builtin::Function::kAtan, CallParamType::kF16, "atan"},
+               BuiltinData{builtin::Function::kAtan2, CallParamType::kF32, "atan"},
+               BuiltinData{builtin::Function::kAtan2, CallParamType::kF16, "atan"},
+               BuiltinData{builtin::Function::kCeil, CallParamType::kF32, "ceil"},
+               BuiltinData{builtin::Function::kCeil, CallParamType::kF16, "ceil"},
+               BuiltinData{builtin::Function::kClamp, CallParamType::kF32, "clamp"},
+               BuiltinData{builtin::Function::kClamp, CallParamType::kF16, "clamp"},
+               BuiltinData{builtin::Function::kCos, CallParamType::kF32, "cos"},
+               BuiltinData{builtin::Function::kCos, CallParamType::kF16, "cos"},
+               BuiltinData{builtin::Function::kCosh, CallParamType::kF32, "cosh"},
+               BuiltinData{builtin::Function::kCosh, CallParamType::kF16, "cosh"},
+               BuiltinData{builtin::Function::kCross, CallParamType::kF32, "cross"},
+               BuiltinData{builtin::Function::kCross, CallParamType::kF16, "cross"},
+               BuiltinData{builtin::Function::kDistance, CallParamType::kF32, "distance"},
+               BuiltinData{builtin::Function::kDistance, CallParamType::kF16, "distance"},
+               BuiltinData{builtin::Function::kExp, CallParamType::kF32, "exp"},
+               BuiltinData{builtin::Function::kExp, CallParamType::kF16, "exp"},
+               BuiltinData{builtin::Function::kExp2, CallParamType::kF32, "exp2"},
+               BuiltinData{builtin::Function::kExp2, CallParamType::kF16, "exp2"},
+               BuiltinData{builtin::Function::kFaceForward, CallParamType::kF32, "faceforward"},
+               BuiltinData{builtin::Function::kFaceForward, CallParamType::kF16, "faceforward"},
+               BuiltinData{builtin::Function::kFloor, CallParamType::kF32, "floor"},
+               BuiltinData{builtin::Function::kFloor, CallParamType::kF16, "floor"},
+               BuiltinData{builtin::Function::kFma, CallParamType::kF32, "fma"},
+               BuiltinData{builtin::Function::kFma, CallParamType::kF16, "fma"},
+               BuiltinData{builtin::Function::kFract, CallParamType::kF32, "fract"},
+               BuiltinData{builtin::Function::kFract, CallParamType::kF16, "fract"},
+               BuiltinData{builtin::Function::kInverseSqrt, CallParamType::kF32, "inversesqrt"},
+               BuiltinData{builtin::Function::kInverseSqrt, CallParamType::kF16, "inversesqrt"},
+               BuiltinData{builtin::Function::kLdexp, CallParamType::kF32, "ldexp"},
+               BuiltinData{builtin::Function::kLdexp, CallParamType::kF16, "ldexp"},
+               BuiltinData{builtin::Function::kLength, CallParamType::kF32, "length"},
+               BuiltinData{builtin::Function::kLength, CallParamType::kF16, "length"},
+               BuiltinData{builtin::Function::kLog, CallParamType::kF32, "log"},
+               BuiltinData{builtin::Function::kLog, CallParamType::kF16, "log"},
+               BuiltinData{builtin::Function::kLog2, CallParamType::kF32, "log2"},
+               BuiltinData{builtin::Function::kLog2, CallParamType::kF16, "log2"},
+               BuiltinData{builtin::Function::kMax, CallParamType::kF32, "max"},
+               BuiltinData{builtin::Function::kMax, CallParamType::kF16, "max"},
+               BuiltinData{builtin::Function::kMin, CallParamType::kF32, "min"},
+               BuiltinData{builtin::Function::kMin, CallParamType::kF16, "min"},
+               BuiltinData{builtin::Function::kMix, CallParamType::kF32, "mix"},
+               BuiltinData{builtin::Function::kMix, CallParamType::kF16, "mix"},
+               BuiltinData{builtin::Function::kNormalize, CallParamType::kF32, "normalize"},
+               BuiltinData{builtin::Function::kNormalize, CallParamType::kF16, "normalize"},
+               BuiltinData{builtin::Function::kPow, CallParamType::kF32, "pow"},
+               BuiltinData{builtin::Function::kPow, CallParamType::kF16, "pow"},
+               BuiltinData{builtin::Function::kReflect, CallParamType::kF32, "reflect"},
+               BuiltinData{builtin::Function::kReflect, CallParamType::kF16, "reflect"},
+               BuiltinData{builtin::Function::kSign, CallParamType::kF32, "sign"},
+               BuiltinData{builtin::Function::kSign, CallParamType::kF16, "sign"},
+               BuiltinData{builtin::Function::kSin, CallParamType::kF32, "sin"},
+               BuiltinData{builtin::Function::kSin, CallParamType::kF16, "sin"},
+               BuiltinData{builtin::Function::kSinh, CallParamType::kF32, "sinh"},
+               BuiltinData{builtin::Function::kSinh, CallParamType::kF16, "sinh"},
+               BuiltinData{builtin::Function::kSmoothstep, CallParamType::kF32, "smoothstep"},
+               BuiltinData{builtin::Function::kSmoothstep, CallParamType::kF16, "smoothstep"},
+               BuiltinData{builtin::Function::kSqrt, CallParamType::kF32, "sqrt"},
+               BuiltinData{builtin::Function::kSqrt, CallParamType::kF16, "sqrt"},
+               BuiltinData{builtin::Function::kStep, CallParamType::kF32, "step"},
+               BuiltinData{builtin::Function::kStep, CallParamType::kF16, "step"},
+               BuiltinData{builtin::Function::kTan, CallParamType::kF32, "tan"},
+               BuiltinData{builtin::Function::kTan, CallParamType::kF16, "tan"},
+               BuiltinData{builtin::Function::kTanh, CallParamType::kF32, "tanh"},
+               BuiltinData{builtin::Function::kTanh, CallParamType::kF16, "tanh"},
+               BuiltinData{builtin::Function::kTrunc, CallParamType::kF32, "trunc"},
+               BuiltinData{builtin::Function::kTrunc, CallParamType::kF16, "trunc"},
+               /* Integer built-in */
+               BuiltinData{builtin::Function::kAbs, CallParamType::kU32, "abs"},
+               BuiltinData{builtin::Function::kClamp, CallParamType::kU32, "clamp"},
+               BuiltinData{builtin::Function::kCountOneBits, CallParamType::kU32, "bitCount"},
+               BuiltinData{builtin::Function::kMax, CallParamType::kU32, "max"},
+               BuiltinData{builtin::Function::kMin, CallParamType::kU32, "min"},
+               BuiltinData{builtin::Function::kReverseBits, CallParamType::kU32, "bitfieldReverse"},
+               BuiltinData{builtin::Function::kRound, CallParamType::kU32, "round"},
+               /* Matrix built-in */
+               BuiltinData{builtin::Function::kDeterminant, CallParamType::kF32, "determinant"},
+               BuiltinData{builtin::Function::kDeterminant, CallParamType::kF16, "determinant"},
+               BuiltinData{builtin::Function::kTranspose, CallParamType::kF32, "transpose"},
+               BuiltinData{builtin::Function::kTranspose, CallParamType::kF16, "transpose"},
+               /* Vector built-in */
+               BuiltinData{builtin::Function::kDot, CallParamType::kF32, "dot"},
+               BuiltinData{builtin::Function::kDot, CallParamType::kF16, "dot"},
+               /* Derivate built-in */
+               BuiltinData{builtin::Function::kDpdx, CallParamType::kF32, "dFdx"},
+               BuiltinData{builtin::Function::kDpdxCoarse, CallParamType::kF32, "dFdx"},
+               BuiltinData{builtin::Function::kDpdxFine, CallParamType::kF32, "dFdx"},
+               BuiltinData{builtin::Function::kDpdy, CallParamType::kF32, "dFdy"},
+               BuiltinData{builtin::Function::kDpdyCoarse, CallParamType::kF32, "dFdy"},
+               BuiltinData{builtin::Function::kDpdyFine, CallParamType::kF32, "dFdy"},
+               BuiltinData{builtin::Function::kFwidth, CallParamType::kF32, "fwidth"},
+               BuiltinData{builtin::Function::kFwidthCoarse, CallParamType::kF32, "fwidth"},
+               BuiltinData{builtin::Function::kFwidthFine, CallParamType::kF32, "fwidth"}));
 
 TEST_F(GlslGeneratorImplTest_Builtin, Builtin_Call) {
     auto* call = Call("dot", "param1", "param2");
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 3acafe1..ada0399 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -966,25 +966,25 @@
     if (builtin->IsTexture()) {
         return EmitTextureCall(out, call, builtin);
     }
-    if (type == sem::BuiltinType::kSelect) {
+    if (type == builtin::Function::kSelect) {
         return EmitSelectCall(out, expr);
     }
-    if (type == sem::BuiltinType::kModf) {
+    if (type == builtin::Function::kModf) {
         return EmitModfCall(out, expr, builtin);
     }
-    if (type == sem::BuiltinType::kFrexp) {
+    if (type == builtin::Function::kFrexp) {
         return EmitFrexpCall(out, expr, builtin);
     }
-    if (type == sem::BuiltinType::kDegrees) {
+    if (type == builtin::Function::kDegrees) {
         return EmitDegreesCall(out, expr, builtin);
     }
-    if (type == sem::BuiltinType::kRadians) {
+    if (type == builtin::Function::kRadians) {
         return EmitRadiansCall(out, expr, builtin);
     }
-    if (type == sem::BuiltinType::kSign) {
+    if (type == builtin::Function::kSign) {
         return EmitSignCall(out, call, builtin);
     }
-    if (type == sem::BuiltinType::kQuantizeToF16) {
+    if (type == builtin::Function::kQuantizeToF16) {
         return EmitQuantizeToF16Call(out, expr, builtin);
     }
     if (builtin->IsDataPacking()) {
@@ -1011,7 +1011,7 @@
     // Handle single argument builtins that only accept and return uint (not int overload). We need
     // to explicitly cast the return value (we also cast the arg for good measure). See
     // crbug.com/tint/1550
-    if (type == sem::BuiltinType::kCountOneBits || type == sem::BuiltinType::kReverseBits) {
+    if (type == builtin::Function::kCountOneBits || type == builtin::Function::kReverseBits) {
         auto* arg = call->Arguments()[0];
         if (arg->Type()->UnwrapRef()->is_signed_integer_scalar_or_vector()) {
             out << "asint(" << name << "(asuint(";
@@ -1805,7 +1805,7 @@
                 if (i > 0) {
                     pre << ", ";
                 }
-                if (i == 1 && builtin->Type() == sem::BuiltinType::kAtomicSub) {
+                if (i == 1 && builtin->Type() == builtin::Function::kAtomicSub) {
                     // Sub uses InterlockedAdd with the operand negated.
                     pre << "-";
                 }
@@ -1824,7 +1824,7 @@
     };
 
     switch (builtin->Type()) {
-        case sem::BuiltinType::kAtomicLoad: {
+        case builtin::Function::kAtomicLoad: {
             // HLSL does not have an InterlockedLoad, so we emulate it with
             // InterlockedOr using 0 as the OR value
             auto pre = line();
@@ -1841,7 +1841,7 @@
             out << result;
             return true;
         }
-        case sem::BuiltinType::kAtomicStore: {
+        case builtin::Function::kAtomicStore: {
             // HLSL does not have an InterlockedStore, so we emulate it with
             // InterlockedExchange and discard the returned value
             {  // T result = 0;
@@ -1872,7 +1872,7 @@
             }
             return true;
         }
-        case sem::BuiltinType::kAtomicCompareExchangeWeak: {
+        case builtin::Function::kAtomicCompareExchangeWeak: {
             if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
                 return false;
             }
@@ -1921,26 +1921,26 @@
             return true;
         }
 
-        case sem::BuiltinType::kAtomicAdd:
-        case sem::BuiltinType::kAtomicSub:
+        case builtin::Function::kAtomicAdd:
+        case builtin::Function::kAtomicSub:
             return call("InterlockedAdd");
 
-        case sem::BuiltinType::kAtomicMax:
+        case builtin::Function::kAtomicMax:
             return call("InterlockedMax");
 
-        case sem::BuiltinType::kAtomicMin:
+        case builtin::Function::kAtomicMin:
             return call("InterlockedMin");
 
-        case sem::BuiltinType::kAtomicAnd:
+        case builtin::Function::kAtomicAnd:
             return call("InterlockedAnd");
 
-        case sem::BuiltinType::kAtomicOr:
+        case builtin::Function::kAtomicOr:
             return call("InterlockedOr");
 
-        case sem::BuiltinType::kAtomicXor:
+        case builtin::Function::kAtomicXor:
             return call("InterlockedXor");
 
-        case sem::BuiltinType::kAtomicExchange:
+        case builtin::Function::kAtomicExchange:
             return call("InterlockedExchange");
 
         default:
@@ -2114,21 +2114,21 @@
             uint32_t dims = 2;
             bool is_signed = false;
             uint32_t scale = 65535;
-            if (builtin->Type() == sem::BuiltinType::kPack4X8Snorm ||
-                builtin->Type() == sem::BuiltinType::kPack4X8Unorm) {
+            if (builtin->Type() == builtin::Function::kPack4X8Snorm ||
+                builtin->Type() == builtin::Function::kPack4X8Unorm) {
                 dims = 4;
                 scale = 255;
             }
-            if (builtin->Type() == sem::BuiltinType::kPack4X8Snorm ||
-                builtin->Type() == sem::BuiltinType::kPack2X16Snorm) {
+            if (builtin->Type() == builtin::Function::kPack4X8Snorm ||
+                builtin->Type() == builtin::Function::kPack2X16Snorm) {
                 is_signed = true;
                 scale = (scale - 1) / 2;
             }
             switch (builtin->Type()) {
-                case sem::BuiltinType::kPack4X8Snorm:
-                case sem::BuiltinType::kPack4X8Unorm:
-                case sem::BuiltinType::kPack2X16Snorm:
-                case sem::BuiltinType::kPack2X16Unorm: {
+                case builtin::Function::kPack4X8Snorm:
+                case builtin::Function::kPack4X8Unorm:
+                case builtin::Function::kPack2X16Snorm:
+                case builtin::Function::kPack2X16Unorm: {
                     {
                         auto l = line(b);
                         l << (is_signed ? "" : "u") << "int" << dims
@@ -2154,7 +2154,7 @@
                     }
                     break;
                 }
-                case sem::BuiltinType::kPack2X16Float: {
+                case builtin::Function::kPack2X16Float: {
                     line(b) << "uint2 i = f32tof16(" << params[0] << ");";
                     line(b) << "return i.x | (i.y << 16);";
                     break;
@@ -2177,19 +2177,19 @@
             uint32_t dims = 2;
             bool is_signed = false;
             uint32_t scale = 65535;
-            if (builtin->Type() == sem::BuiltinType::kUnpack4X8Snorm ||
-                builtin->Type() == sem::BuiltinType::kUnpack4X8Unorm) {
+            if (builtin->Type() == builtin::Function::kUnpack4X8Snorm ||
+                builtin->Type() == builtin::Function::kUnpack4X8Unorm) {
                 dims = 4;
                 scale = 255;
             }
-            if (builtin->Type() == sem::BuiltinType::kUnpack4X8Snorm ||
-                builtin->Type() == sem::BuiltinType::kUnpack2X16Snorm) {
+            if (builtin->Type() == builtin::Function::kUnpack4X8Snorm ||
+                builtin->Type() == builtin::Function::kUnpack2X16Snorm) {
                 is_signed = true;
                 scale = (scale - 1) / 2;
             }
             switch (builtin->Type()) {
-                case sem::BuiltinType::kUnpack4X8Snorm:
-                case sem::BuiltinType::kUnpack2X16Snorm: {
+                case builtin::Function::kUnpack4X8Snorm:
+                case builtin::Function::kUnpack2X16Snorm: {
                     line(b) << "int j = int(" << params[0] << ");";
                     {  // Perform sign extension on the converted values.
                         auto l = line(b);
@@ -2205,8 +2205,8 @@
                             << (is_signed ? "-1.0" : "0.0") << ", 1.0);";
                     break;
                 }
-                case sem::BuiltinType::kUnpack4X8Unorm:
-                case sem::BuiltinType::kUnpack2X16Unorm: {
+                case builtin::Function::kUnpack4X8Unorm:
+                case builtin::Function::kUnpack2X16Unorm: {
                     line(b) << "uint j = " << params[0] << ";";
                     {
                         auto l = line(b);
@@ -2222,7 +2222,7 @@
                     line(b) << "return float" << dims << "(i) / " << scale << ".0;";
                     break;
                 }
-                case sem::BuiltinType::kUnpack2X16Float:
+                case builtin::Function::kUnpack2X16Float:
                     line(b) << "uint i = " << params[0] << ";";
                     line(b) << "return f16tof32(uint2(i & 0xffff, i >> 16));";
                     break;
@@ -2244,11 +2244,11 @@
         out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
             std::string functionName;
             switch (builtin->Type()) {
-                case sem::BuiltinType::kDot4I8Packed:
+                case builtin::Function::kDot4I8Packed:
                     line(b) << "int accumulator = 0;";
                     functionName = "dot4add_i8packed";
                     break;
-                case sem::BuiltinType::kDot4U8Packed:
+                case builtin::Function::kDot4U8Packed:
                     line(b) << "uint accumulator = 0u;";
                     functionName = "dot4add_u8packed";
                     break;
@@ -2267,13 +2267,13 @@
 bool GeneratorImpl::EmitBarrierCall(utils::StringStream& out, const sem::Builtin* builtin) {
     // TODO(crbug.com/tint/661): Combine sequential barriers to a single
     // instruction.
-    if (builtin->Type() == sem::BuiltinType::kWorkgroupBarrier) {
+    if (builtin->Type() == builtin::Function::kWorkgroupBarrier) {
         out << "GroupMemoryBarrierWithGroupSync()";
-    } else if (builtin->Type() == sem::BuiltinType::kStorageBarrier) {
+    } else if (builtin->Type() == builtin::Function::kStorageBarrier) {
         out << "DeviceMemoryBarrierWithGroupSync()";
     } else {
         TINT_UNREACHABLE(Writer, diagnostics_)
-            << "unexpected barrier builtin type " << sem::str(builtin->Type());
+            << "unexpected barrier builtin type " << builtin::str(builtin->Type());
         return false;
     }
     return true;
@@ -2303,10 +2303,10 @@
     auto* texture_type = TypeOf(texture)->UnwrapRef()->As<type::Texture>();
 
     switch (builtin->Type()) {
-        case sem::BuiltinType::kTextureDimensions:
-        case sem::BuiltinType::kTextureNumLayers:
-        case sem::BuiltinType::kTextureNumLevels:
-        case sem::BuiltinType::kTextureNumSamples: {
+        case builtin::Function::kTextureDimensions:
+        case builtin::Function::kTextureNumLayers:
+        case builtin::Function::kTextureNumLevels:
+        case builtin::Function::kTextureNumSamples: {
             // All of these builtins use the GetDimensions() method on the texture
             bool is_ms =
                 texture_type->IsAnyOf<type::MultisampledTexture, type::DepthMultisampledTexture>();
@@ -2314,7 +2314,7 @@
             std::string swizzle;
 
             switch (builtin->Type()) {
-                case sem::BuiltinType::kTextureDimensions:
+                case builtin::Function::kTextureDimensions:
                     switch (texture_type->dim()) {
                         case type::TextureDimension::kNone:
                             TINT_ICE(Writer, diagnostics_) << "texture dimension is kNone";
@@ -2342,7 +2342,7 @@
                             break;
                     }
                     break;
-                case sem::BuiltinType::kTextureNumLayers:
+                case builtin::Function::kTextureNumLayers:
                     switch (texture_type->dim()) {
                         default:
                             TINT_ICE(Writer, diagnostics_) << "texture dimension is not arrayed";
@@ -2357,7 +2357,7 @@
                             break;
                     }
                     break;
-                case sem::BuiltinType::kTextureNumLevels:
+                case builtin::Function::kTextureNumLevels:
                     switch (texture_type->dim()) {
                         default:
                             TINT_ICE(Writer, diagnostics_)
@@ -2380,7 +2380,7 @@
                             break;
                     }
                     break;
-                case sem::BuiltinType::kTextureNumSamples:
+                case builtin::Function::kTextureNumSamples:
                     switch (texture_type->dim()) {
                         default:
                             TINT_ICE(Writer, diagnostics_)
@@ -2444,7 +2444,7 @@
                         return false;
                     }
                     pre << ", ";
-                } else if (builtin->Type() == sem::BuiltinType::kTextureNumLevels) {
+                } else if (builtin->Type() == builtin::Function::kTextureNumLevels) {
                     pre << "0, ";
                 }
 
@@ -2491,34 +2491,34 @@
     uint32_t hlsl_ret_width = 4u;
 
     switch (builtin->Type()) {
-        case sem::BuiltinType::kTextureSample:
+        case builtin::Function::kTextureSample:
             out << ".Sample(";
             break;
-        case sem::BuiltinType::kTextureSampleBias:
+        case builtin::Function::kTextureSampleBias:
             out << ".SampleBias(";
             break;
-        case sem::BuiltinType::kTextureSampleLevel:
+        case builtin::Function::kTextureSampleLevel:
             out << ".SampleLevel(";
             break;
-        case sem::BuiltinType::kTextureSampleGrad:
+        case builtin::Function::kTextureSampleGrad:
             out << ".SampleGrad(";
             break;
-        case sem::BuiltinType::kTextureSampleCompare:
+        case builtin::Function::kTextureSampleCompare:
             out << ".SampleCmp(";
             hlsl_ret_width = 1;
             break;
-        case sem::BuiltinType::kTextureSampleCompareLevel:
+        case builtin::Function::kTextureSampleCompareLevel:
             out << ".SampleCmpLevelZero(";
             hlsl_ret_width = 1;
             break;
-        case sem::BuiltinType::kTextureLoad:
+        case builtin::Function::kTextureLoad:
             out << ".Load(";
             // Multisampled textures do not support mip-levels.
             if (!texture_type->Is<type::MultisampledTexture>()) {
                 pack_level_in_coords = true;
             }
             break;
-        case sem::BuiltinType::kTextureGather:
+        case builtin::Function::kTextureGather:
             out << ".Gather";
             if (builtin->Parameters()[0]->Usage() == sem::ParameterUsage::kComponent) {
                 switch (call->Arguments()[0]->ConstantValue()->ValueAs<AInt>()) {
@@ -2538,10 +2538,10 @@
             }
             out << "(";
             break;
-        case sem::BuiltinType::kTextureGatherCompare:
+        case builtin::Function::kTextureGatherCompare:
             out << ".GatherCmp(";
             break;
-        case sem::BuiltinType::kTextureStore:
+        case builtin::Function::kTextureStore:
             out << "[";
             break;
         default:
@@ -2621,7 +2621,7 @@
         }
     }
 
-    if (builtin->Type() == sem::BuiltinType::kTextureStore) {
+    if (builtin->Type() == builtin::Function::kTextureStore) {
         out << "] = ";
         if (!EmitExpression(out, arg(Usage::kValue))) {
             return false;
@@ -2655,78 +2655,78 @@
 
 std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
     switch (builtin->Type()) {
-        case sem::BuiltinType::kAbs:
-        case sem::BuiltinType::kAcos:
-        case sem::BuiltinType::kAll:
-        case sem::BuiltinType::kAny:
-        case sem::BuiltinType::kAsin:
-        case sem::BuiltinType::kAtan:
-        case sem::BuiltinType::kAtan2:
-        case sem::BuiltinType::kCeil:
-        case sem::BuiltinType::kClamp:
-        case sem::BuiltinType::kCos:
-        case sem::BuiltinType::kCosh:
-        case sem::BuiltinType::kCross:
-        case sem::BuiltinType::kDeterminant:
-        case sem::BuiltinType::kDistance:
-        case sem::BuiltinType::kDot:
-        case sem::BuiltinType::kExp:
-        case sem::BuiltinType::kExp2:
-        case sem::BuiltinType::kFloor:
-        case sem::BuiltinType::kFrexp:
-        case sem::BuiltinType::kLdexp:
-        case sem::BuiltinType::kLength:
-        case sem::BuiltinType::kLog:
-        case sem::BuiltinType::kLog2:
-        case sem::BuiltinType::kMax:
-        case sem::BuiltinType::kMin:
-        case sem::BuiltinType::kModf:
-        case sem::BuiltinType::kNormalize:
-        case sem::BuiltinType::kPow:
-        case sem::BuiltinType::kReflect:
-        case sem::BuiltinType::kRefract:
-        case sem::BuiltinType::kRound:
-        case sem::BuiltinType::kSaturate:
-        case sem::BuiltinType::kSin:
-        case sem::BuiltinType::kSinh:
-        case sem::BuiltinType::kSqrt:
-        case sem::BuiltinType::kStep:
-        case sem::BuiltinType::kTan:
-        case sem::BuiltinType::kTanh:
-        case sem::BuiltinType::kTranspose:
-        case sem::BuiltinType::kTrunc:
+        case builtin::Function::kAbs:
+        case builtin::Function::kAcos:
+        case builtin::Function::kAll:
+        case builtin::Function::kAny:
+        case builtin::Function::kAsin:
+        case builtin::Function::kAtan:
+        case builtin::Function::kAtan2:
+        case builtin::Function::kCeil:
+        case builtin::Function::kClamp:
+        case builtin::Function::kCos:
+        case builtin::Function::kCosh:
+        case builtin::Function::kCross:
+        case builtin::Function::kDeterminant:
+        case builtin::Function::kDistance:
+        case builtin::Function::kDot:
+        case builtin::Function::kExp:
+        case builtin::Function::kExp2:
+        case builtin::Function::kFloor:
+        case builtin::Function::kFrexp:
+        case builtin::Function::kLdexp:
+        case builtin::Function::kLength:
+        case builtin::Function::kLog:
+        case builtin::Function::kLog2:
+        case builtin::Function::kMax:
+        case builtin::Function::kMin:
+        case builtin::Function::kModf:
+        case builtin::Function::kNormalize:
+        case builtin::Function::kPow:
+        case builtin::Function::kReflect:
+        case builtin::Function::kRefract:
+        case builtin::Function::kRound:
+        case builtin::Function::kSaturate:
+        case builtin::Function::kSin:
+        case builtin::Function::kSinh:
+        case builtin::Function::kSqrt:
+        case builtin::Function::kStep:
+        case builtin::Function::kTan:
+        case builtin::Function::kTanh:
+        case builtin::Function::kTranspose:
+        case builtin::Function::kTrunc:
             return builtin->str();
-        case sem::BuiltinType::kCountOneBits:  // uint
+        case builtin::Function::kCountOneBits:  // uint
             return "countbits";
-        case sem::BuiltinType::kDpdx:
+        case builtin::Function::kDpdx:
             return "ddx";
-        case sem::BuiltinType::kDpdxCoarse:
+        case builtin::Function::kDpdxCoarse:
             return "ddx_coarse";
-        case sem::BuiltinType::kDpdxFine:
+        case builtin::Function::kDpdxFine:
             return "ddx_fine";
-        case sem::BuiltinType::kDpdy:
+        case builtin::Function::kDpdy:
             return "ddy";
-        case sem::BuiltinType::kDpdyCoarse:
+        case builtin::Function::kDpdyCoarse:
             return "ddy_coarse";
-        case sem::BuiltinType::kDpdyFine:
+        case builtin::Function::kDpdyFine:
             return "ddy_fine";
-        case sem::BuiltinType::kFaceForward:
+        case builtin::Function::kFaceForward:
             return "faceforward";
-        case sem::BuiltinType::kFract:
+        case builtin::Function::kFract:
             return "frac";
-        case sem::BuiltinType::kFma:
+        case builtin::Function::kFma:
             return "mad";
-        case sem::BuiltinType::kFwidth:
-        case sem::BuiltinType::kFwidthCoarse:
-        case sem::BuiltinType::kFwidthFine:
+        case builtin::Function::kFwidth:
+        case builtin::Function::kFwidthCoarse:
+        case builtin::Function::kFwidthFine:
             return "fwidth";
-        case sem::BuiltinType::kInverseSqrt:
+        case builtin::Function::kInverseSqrt:
             return "rsqrt";
-        case sem::BuiltinType::kMix:
+        case builtin::Function::kMix:
             return "lerp";
-        case sem::BuiltinType::kReverseBits:  // uint
+        case builtin::Function::kReverseBits:  // uint
             return "reversebits";
-        case sem::BuiltinType::kSmoothstep:
+        case builtin::Function::kSmoothstep:
             return "smoothstep";
         default:
             diagnostics_.add_error(diag::System::Writer,
@@ -4346,7 +4346,7 @@
         TextBuffer b;
         TINT_DEFER(helpers_.Append(b));
 
-        auto fn_name = UniqueIdentifier(std::string("tint_") + sem::str(builtin->Type()));
+        auto fn_name = UniqueIdentifier(std::string("tint_") + builtin::str(builtin->Type()));
         std::vector<std::string> parameter_names;
         {
             auto decl = line(&b);
diff --git a/src/tint/writer/hlsl/generator_impl_builtin_test.cc b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
index 5054327..f473ac8 100644
--- a/src/tint/writer/hlsl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
@@ -26,7 +26,6 @@
 namespace tint::writer::hlsl {
 namespace {
 
-using BuiltinType = sem::BuiltinType;
 using HlslGeneratorImplTest_Builtin = TestHelper;
 
 enum class CallParamType {
@@ -37,7 +36,7 @@
 };
 
 struct BuiltinData {
-    BuiltinType builtin;
+    builtin::Function builtin;
     CallParamType type;
     const char* hlsl_name;
 };
@@ -61,85 +60,85 @@
     return out;
 }
 
-const ast::CallExpression* GenerateCall(BuiltinType builtin,
+const ast::CallExpression* GenerateCall(builtin::Function builtin,
                                         CallParamType type,
                                         ProgramBuilder* builder) {
     std::string name;
     utils::StringStream str;
     str << name << builtin;
     switch (builtin) {
-        case BuiltinType::kAcos:
-        case BuiltinType::kAsin:
-        case BuiltinType::kAtan:
-        case BuiltinType::kCeil:
-        case BuiltinType::kCos:
-        case BuiltinType::kCosh:
-        case BuiltinType::kDpdx:
-        case BuiltinType::kDpdxCoarse:
-        case BuiltinType::kDpdxFine:
-        case BuiltinType::kDpdy:
-        case BuiltinType::kDpdyCoarse:
-        case BuiltinType::kDpdyFine:
-        case BuiltinType::kExp:
-        case BuiltinType::kExp2:
-        case BuiltinType::kFloor:
-        case BuiltinType::kFract:
-        case BuiltinType::kFwidth:
-        case BuiltinType::kFwidthCoarse:
-        case BuiltinType::kFwidthFine:
-        case BuiltinType::kInverseSqrt:
-        case BuiltinType::kLength:
-        case BuiltinType::kLog:
-        case BuiltinType::kLog2:
-        case BuiltinType::kNormalize:
-        case BuiltinType::kRound:
-        case BuiltinType::kSin:
-        case BuiltinType::kSinh:
-        case BuiltinType::kSqrt:
-        case BuiltinType::kTan:
-        case BuiltinType::kTanh:
-        case BuiltinType::kTrunc:
+        case builtin::Function::kAcos:
+        case builtin::Function::kAsin:
+        case builtin::Function::kAtan:
+        case builtin::Function::kCeil:
+        case builtin::Function::kCos:
+        case builtin::Function::kCosh:
+        case builtin::Function::kDpdx:
+        case builtin::Function::kDpdxCoarse:
+        case builtin::Function::kDpdxFine:
+        case builtin::Function::kDpdy:
+        case builtin::Function::kDpdyCoarse:
+        case builtin::Function::kDpdyFine:
+        case builtin::Function::kExp:
+        case builtin::Function::kExp2:
+        case builtin::Function::kFloor:
+        case builtin::Function::kFract:
+        case builtin::Function::kFwidth:
+        case builtin::Function::kFwidthCoarse:
+        case builtin::Function::kFwidthFine:
+        case builtin::Function::kInverseSqrt:
+        case builtin::Function::kLength:
+        case builtin::Function::kLog:
+        case builtin::Function::kLog2:
+        case builtin::Function::kNormalize:
+        case builtin::Function::kRound:
+        case builtin::Function::kSin:
+        case builtin::Function::kSinh:
+        case builtin::Function::kSqrt:
+        case builtin::Function::kTan:
+        case builtin::Function::kTanh:
+        case builtin::Function::kTrunc:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2");
             } else {
                 return builder->Call(str.str(), "f2");
             }
-        case BuiltinType::kLdexp:
+        case builtin::Function::kLdexp:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "i2");
             } else {
                 return builder->Call(str.str(), "f2", "i2");
             }
-        case BuiltinType::kAtan2:
-        case BuiltinType::kDot:
-        case BuiltinType::kDistance:
-        case BuiltinType::kPow:
-        case BuiltinType::kReflect:
-        case BuiltinType::kStep:
+        case builtin::Function::kAtan2:
+        case builtin::Function::kDot:
+        case builtin::Function::kDistance:
+        case builtin::Function::kPow:
+        case builtin::Function::kReflect:
+        case builtin::Function::kStep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2");
             }
-        case BuiltinType::kCross:
+        case builtin::Function::kCross:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h3", "h3");
             } else {
                 return builder->Call(str.str(), "f3", "f3");
             }
-        case BuiltinType::kFma:
-        case BuiltinType::kMix:
-        case BuiltinType::kFaceForward:
-        case BuiltinType::kSmoothstep:
+        case builtin::Function::kFma:
+        case builtin::Function::kMix:
+        case builtin::Function::kFaceForward:
+        case builtin::Function::kSmoothstep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             }
-        case BuiltinType::kAll:
-        case BuiltinType::kAny:
+        case builtin::Function::kAll:
+        case builtin::Function::kAny:
             return builder->Call(str.str(), "b2");
-        case BuiltinType::kAbs:
+        case builtin::Function::kAbs:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2");
             } else if (type == CallParamType::kF16) {
@@ -147,11 +146,11 @@
             } else {
                 return builder->Call(str.str(), "u2");
             }
-        case BuiltinType::kCountOneBits:
-        case BuiltinType::kReverseBits:
+        case builtin::Function::kCountOneBits:
+        case builtin::Function::kReverseBits:
             return builder->Call(str.str(), "u2");
-        case BuiltinType::kMax:
-        case BuiltinType::kMin:
+        case builtin::Function::kMax:
+        case builtin::Function::kMin:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -159,7 +158,7 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2");
             }
-        case BuiltinType::kClamp:
+        case builtin::Function::kClamp:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -167,19 +166,19 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2", "u2");
             }
-        case BuiltinType::kSelect:
+        case builtin::Function::kSelect:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "b2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "b2");
             }
-        case BuiltinType::kDeterminant:
+        case builtin::Function::kDeterminant:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm2x2");
             } else {
                 return builder->Call(str.str(), "m2x2");
             }
-        case BuiltinType::kTranspose:
+        case builtin::Function::kTranspose:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm3x2");
             } else {
@@ -235,107 +234,112 @@
     HlslGeneratorImplTest_Builtin,
     HlslBuiltinTest,
     testing::Values(/* Logical built-in */
-                    BuiltinData{BuiltinType::kAll, CallParamType::kBool, "all"},
-                    BuiltinData{BuiltinType::kAny, CallParamType::kBool, "any"},
+                    BuiltinData{builtin::Function::kAll, CallParamType::kBool, "all"},
+                    BuiltinData{builtin::Function::kAny, CallParamType::kBool, "any"},
                     /* Float built-in */
-                    BuiltinData{BuiltinType::kAbs, CallParamType::kF32, "abs"},
-                    BuiltinData{BuiltinType::kAbs, CallParamType::kF16, "abs"},
-                    BuiltinData{BuiltinType::kAcos, CallParamType::kF32, "acos"},
-                    BuiltinData{BuiltinType::kAcos, CallParamType::kF16, "acos"},
-                    BuiltinData{BuiltinType::kAsin, CallParamType::kF32, "asin"},
-                    BuiltinData{BuiltinType::kAsin, CallParamType::kF16, "asin"},
-                    BuiltinData{BuiltinType::kAtan, CallParamType::kF32, "atan"},
-                    BuiltinData{BuiltinType::kAtan, CallParamType::kF16, "atan"},
-                    BuiltinData{BuiltinType::kAtan2, CallParamType::kF32, "atan2"},
-                    BuiltinData{BuiltinType::kAtan2, CallParamType::kF16, "atan2"},
-                    BuiltinData{BuiltinType::kCeil, CallParamType::kF32, "ceil"},
-                    BuiltinData{BuiltinType::kCeil, CallParamType::kF16, "ceil"},
-                    BuiltinData{BuiltinType::kClamp, CallParamType::kF32, "clamp"},
-                    BuiltinData{BuiltinType::kClamp, CallParamType::kF16, "clamp"},
-                    BuiltinData{BuiltinType::kCos, CallParamType::kF32, "cos"},
-                    BuiltinData{BuiltinType::kCos, CallParamType::kF16, "cos"},
-                    BuiltinData{BuiltinType::kCosh, CallParamType::kF32, "cosh"},
-                    BuiltinData{BuiltinType::kCosh, CallParamType::kF16, "cosh"},
-                    BuiltinData{BuiltinType::kCross, CallParamType::kF32, "cross"},
-                    BuiltinData{BuiltinType::kCross, CallParamType::kF16, "cross"},
-                    BuiltinData{BuiltinType::kDistance, CallParamType::kF32, "distance"},
-                    BuiltinData{BuiltinType::kDistance, CallParamType::kF16, "distance"},
-                    BuiltinData{BuiltinType::kExp, CallParamType::kF32, "exp"},
-                    BuiltinData{BuiltinType::kExp, CallParamType::kF16, "exp"},
-                    BuiltinData{BuiltinType::kExp2, CallParamType::kF32, "exp2"},
-                    BuiltinData{BuiltinType::kExp2, CallParamType::kF16, "exp2"},
-                    BuiltinData{BuiltinType::kFaceForward, CallParamType::kF32, "faceforward"},
-                    BuiltinData{BuiltinType::kFaceForward, CallParamType::kF16, "faceforward"},
-                    BuiltinData{BuiltinType::kFloor, CallParamType::kF32, "floor"},
-                    BuiltinData{BuiltinType::kFloor, CallParamType::kF16, "floor"},
-                    BuiltinData{BuiltinType::kFma, CallParamType::kF32, "mad"},
-                    BuiltinData{BuiltinType::kFma, CallParamType::kF16, "mad"},
-                    BuiltinData{BuiltinType::kFract, CallParamType::kF32, "frac"},
-                    BuiltinData{BuiltinType::kFract, CallParamType::kF16, "frac"},
-                    BuiltinData{BuiltinType::kInverseSqrt, CallParamType::kF32, "rsqrt"},
-                    BuiltinData{BuiltinType::kInverseSqrt, CallParamType::kF16, "rsqrt"},
-                    BuiltinData{BuiltinType::kLdexp, CallParamType::kF32, "ldexp"},
-                    BuiltinData{BuiltinType::kLdexp, CallParamType::kF16, "ldexp"},
-                    BuiltinData{BuiltinType::kLength, CallParamType::kF32, "length"},
-                    BuiltinData{BuiltinType::kLength, CallParamType::kF16, "length"},
-                    BuiltinData{BuiltinType::kLog, CallParamType::kF32, "log"},
-                    BuiltinData{BuiltinType::kLog, CallParamType::kF16, "log"},
-                    BuiltinData{BuiltinType::kLog2, CallParamType::kF32, "log2"},
-                    BuiltinData{BuiltinType::kLog2, CallParamType::kF16, "log2"},
-                    BuiltinData{BuiltinType::kMax, CallParamType::kF32, "max"},
-                    BuiltinData{BuiltinType::kMax, CallParamType::kF16, "max"},
-                    BuiltinData{BuiltinType::kMin, CallParamType::kF32, "min"},
-                    BuiltinData{BuiltinType::kMin, CallParamType::kF16, "min"},
-                    BuiltinData{BuiltinType::kMix, CallParamType::kF32, "lerp"},
-                    BuiltinData{BuiltinType::kMix, CallParamType::kF16, "lerp"},
-                    BuiltinData{BuiltinType::kNormalize, CallParamType::kF32, "normalize"},
-                    BuiltinData{BuiltinType::kNormalize, CallParamType::kF16, "normalize"},
-                    BuiltinData{BuiltinType::kPow, CallParamType::kF32, "pow"},
-                    BuiltinData{BuiltinType::kPow, CallParamType::kF16, "pow"},
-                    BuiltinData{BuiltinType::kReflect, CallParamType::kF32, "reflect"},
-                    BuiltinData{BuiltinType::kReflect, CallParamType::kF16, "reflect"},
-                    BuiltinData{BuiltinType::kSin, CallParamType::kF32, "sin"},
-                    BuiltinData{BuiltinType::kSin, CallParamType::kF16, "sin"},
-                    BuiltinData{BuiltinType::kSinh, CallParamType::kF32, "sinh"},
-                    BuiltinData{BuiltinType::kSinh, CallParamType::kF16, "sinh"},
-                    BuiltinData{BuiltinType::kSmoothstep, CallParamType::kF32, "smoothstep"},
-                    BuiltinData{BuiltinType::kSmoothstep, CallParamType::kF16, "smoothstep"},
-                    BuiltinData{BuiltinType::kSqrt, CallParamType::kF32, "sqrt"},
-                    BuiltinData{BuiltinType::kSqrt, CallParamType::kF16, "sqrt"},
-                    BuiltinData{BuiltinType::kStep, CallParamType::kF32, "step"},
-                    BuiltinData{BuiltinType::kStep, CallParamType::kF16, "step"},
-                    BuiltinData{BuiltinType::kTan, CallParamType::kF32, "tan"},
-                    BuiltinData{BuiltinType::kTan, CallParamType::kF16, "tan"},
-                    BuiltinData{BuiltinType::kTanh, CallParamType::kF32, "tanh"},
-                    BuiltinData{BuiltinType::kTanh, CallParamType::kF16, "tanh"},
-                    BuiltinData{BuiltinType::kTrunc, CallParamType::kF32, "trunc"},
-                    BuiltinData{BuiltinType::kTrunc, CallParamType::kF16, "trunc"},
+                    BuiltinData{builtin::Function::kAbs, CallParamType::kF32, "abs"},
+                    BuiltinData{builtin::Function::kAbs, CallParamType::kF16, "abs"},
+                    BuiltinData{builtin::Function::kAcos, CallParamType::kF32, "acos"},
+                    BuiltinData{builtin::Function::kAcos, CallParamType::kF16, "acos"},
+                    BuiltinData{builtin::Function::kAsin, CallParamType::kF32, "asin"},
+                    BuiltinData{builtin::Function::kAsin, CallParamType::kF16, "asin"},
+                    BuiltinData{builtin::Function::kAtan, CallParamType::kF32, "atan"},
+                    BuiltinData{builtin::Function::kAtan, CallParamType::kF16, "atan"},
+                    BuiltinData{builtin::Function::kAtan2, CallParamType::kF32, "atan2"},
+                    BuiltinData{builtin::Function::kAtan2, CallParamType::kF16, "atan2"},
+                    BuiltinData{builtin::Function::kCeil, CallParamType::kF32, "ceil"},
+                    BuiltinData{builtin::Function::kCeil, CallParamType::kF16, "ceil"},
+                    BuiltinData{builtin::Function::kClamp, CallParamType::kF32, "clamp"},
+                    BuiltinData{builtin::Function::kClamp, CallParamType::kF16, "clamp"},
+                    BuiltinData{builtin::Function::kCos, CallParamType::kF32, "cos"},
+                    BuiltinData{builtin::Function::kCos, CallParamType::kF16, "cos"},
+                    BuiltinData{builtin::Function::kCosh, CallParamType::kF32, "cosh"},
+                    BuiltinData{builtin::Function::kCosh, CallParamType::kF16, "cosh"},
+                    BuiltinData{builtin::Function::kCross, CallParamType::kF32, "cross"},
+                    BuiltinData{builtin::Function::kCross, CallParamType::kF16, "cross"},
+                    BuiltinData{builtin::Function::kDistance, CallParamType::kF32, "distance"},
+                    BuiltinData{builtin::Function::kDistance, CallParamType::kF16, "distance"},
+                    BuiltinData{builtin::Function::kExp, CallParamType::kF32, "exp"},
+                    BuiltinData{builtin::Function::kExp, CallParamType::kF16, "exp"},
+                    BuiltinData{builtin::Function::kExp2, CallParamType::kF32, "exp2"},
+                    BuiltinData{builtin::Function::kExp2, CallParamType::kF16, "exp2"},
+                    BuiltinData{builtin::Function::kFaceForward, CallParamType::kF32,
+                                "faceforward"},
+                    BuiltinData{builtin::Function::kFaceForward, CallParamType::kF16,
+                                "faceforward"},
+                    BuiltinData{builtin::Function::kFloor, CallParamType::kF32, "floor"},
+                    BuiltinData{builtin::Function::kFloor, CallParamType::kF16, "floor"},
+                    BuiltinData{builtin::Function::kFma, CallParamType::kF32, "mad"},
+                    BuiltinData{builtin::Function::kFma, CallParamType::kF16, "mad"},
+                    BuiltinData{builtin::Function::kFract, CallParamType::kF32, "frac"},
+                    BuiltinData{builtin::Function::kFract, CallParamType::kF16, "frac"},
+                    BuiltinData{builtin::Function::kInverseSqrt, CallParamType::kF32, "rsqrt"},
+                    BuiltinData{builtin::Function::kInverseSqrt, CallParamType::kF16, "rsqrt"},
+                    BuiltinData{builtin::Function::kLdexp, CallParamType::kF32, "ldexp"},
+                    BuiltinData{builtin::Function::kLdexp, CallParamType::kF16, "ldexp"},
+                    BuiltinData{builtin::Function::kLength, CallParamType::kF32, "length"},
+                    BuiltinData{builtin::Function::kLength, CallParamType::kF16, "length"},
+                    BuiltinData{builtin::Function::kLog, CallParamType::kF32, "log"},
+                    BuiltinData{builtin::Function::kLog, CallParamType::kF16, "log"},
+                    BuiltinData{builtin::Function::kLog2, CallParamType::kF32, "log2"},
+                    BuiltinData{builtin::Function::kLog2, CallParamType::kF16, "log2"},
+                    BuiltinData{builtin::Function::kMax, CallParamType::kF32, "max"},
+                    BuiltinData{builtin::Function::kMax, CallParamType::kF16, "max"},
+                    BuiltinData{builtin::Function::kMin, CallParamType::kF32, "min"},
+                    BuiltinData{builtin::Function::kMin, CallParamType::kF16, "min"},
+                    BuiltinData{builtin::Function::kMix, CallParamType::kF32, "lerp"},
+                    BuiltinData{builtin::Function::kMix, CallParamType::kF16, "lerp"},
+                    BuiltinData{builtin::Function::kNormalize, CallParamType::kF32, "normalize"},
+                    BuiltinData{builtin::Function::kNormalize, CallParamType::kF16, "normalize"},
+                    BuiltinData{builtin::Function::kPow, CallParamType::kF32, "pow"},
+                    BuiltinData{builtin::Function::kPow, CallParamType::kF16, "pow"},
+                    BuiltinData{builtin::Function::kReflect, CallParamType::kF32, "reflect"},
+                    BuiltinData{builtin::Function::kReflect, CallParamType::kF16, "reflect"},
+                    BuiltinData{builtin::Function::kSin, CallParamType::kF32, "sin"},
+                    BuiltinData{builtin::Function::kSin, CallParamType::kF16, "sin"},
+                    BuiltinData{builtin::Function::kSinh, CallParamType::kF32, "sinh"},
+                    BuiltinData{builtin::Function::kSinh, CallParamType::kF16, "sinh"},
+                    BuiltinData{builtin::Function::kSmoothstep, CallParamType::kF32, "smoothstep"},
+                    BuiltinData{builtin::Function::kSmoothstep, CallParamType::kF16, "smoothstep"},
+                    BuiltinData{builtin::Function::kSqrt, CallParamType::kF32, "sqrt"},
+                    BuiltinData{builtin::Function::kSqrt, CallParamType::kF16, "sqrt"},
+                    BuiltinData{builtin::Function::kStep, CallParamType::kF32, "step"},
+                    BuiltinData{builtin::Function::kStep, CallParamType::kF16, "step"},
+                    BuiltinData{builtin::Function::kTan, CallParamType::kF32, "tan"},
+                    BuiltinData{builtin::Function::kTan, CallParamType::kF16, "tan"},
+                    BuiltinData{builtin::Function::kTanh, CallParamType::kF32, "tanh"},
+                    BuiltinData{builtin::Function::kTanh, CallParamType::kF16, "tanh"},
+                    BuiltinData{builtin::Function::kTrunc, CallParamType::kF32, "trunc"},
+                    BuiltinData{builtin::Function::kTrunc, CallParamType::kF16, "trunc"},
                     /* Integer built-in */
-                    BuiltinData{BuiltinType::kAbs, CallParamType::kU32, "abs"},
-                    BuiltinData{BuiltinType::kClamp, CallParamType::kU32, "clamp"},
-                    BuiltinData{BuiltinType::kCountOneBits, CallParamType::kU32, "countbits"},
-                    BuiltinData{BuiltinType::kMax, CallParamType::kU32, "max"},
-                    BuiltinData{BuiltinType::kMin, CallParamType::kU32, "min"},
-                    BuiltinData{BuiltinType::kReverseBits, CallParamType::kU32, "reversebits"},
-                    BuiltinData{BuiltinType::kRound, CallParamType::kU32, "round"},
+                    BuiltinData{builtin::Function::kAbs, CallParamType::kU32, "abs"},
+                    BuiltinData{builtin::Function::kClamp, CallParamType::kU32, "clamp"},
+                    BuiltinData{builtin::Function::kCountOneBits, CallParamType::kU32, "countbits"},
+                    BuiltinData{builtin::Function::kMax, CallParamType::kU32, "max"},
+                    BuiltinData{builtin::Function::kMin, CallParamType::kU32, "min"},
+                    BuiltinData{builtin::Function::kReverseBits, CallParamType::kU32,
+                                "reversebits"},
+                    BuiltinData{builtin::Function::kRound, CallParamType::kU32, "round"},
                     /* Matrix built-in */
-                    BuiltinData{BuiltinType::kDeterminant, CallParamType::kF32, "determinant"},
-                    BuiltinData{BuiltinType::kDeterminant, CallParamType::kF16, "determinant"},
-                    BuiltinData{BuiltinType::kTranspose, CallParamType::kF32, "transpose"},
-                    BuiltinData{BuiltinType::kTranspose, CallParamType::kF16, "transpose"},
+                    BuiltinData{builtin::Function::kDeterminant, CallParamType::kF32,
+                                "determinant"},
+                    BuiltinData{builtin::Function::kDeterminant, CallParamType::kF16,
+                                "determinant"},
+                    BuiltinData{builtin::Function::kTranspose, CallParamType::kF32, "transpose"},
+                    BuiltinData{builtin::Function::kTranspose, CallParamType::kF16, "transpose"},
                     /* Vector built-in */
-                    BuiltinData{BuiltinType::kDot, CallParamType::kF32, "dot"},
-                    BuiltinData{BuiltinType::kDot, CallParamType::kF16, "dot"},
+                    BuiltinData{builtin::Function::kDot, CallParamType::kF32, "dot"},
+                    BuiltinData{builtin::Function::kDot, CallParamType::kF16, "dot"},
                     /* Derivate built-in */
-                    BuiltinData{BuiltinType::kDpdx, CallParamType::kF32, "ddx"},
-                    BuiltinData{BuiltinType::kDpdxCoarse, CallParamType::kF32, "ddx_coarse"},
-                    BuiltinData{BuiltinType::kDpdxFine, CallParamType::kF32, "ddx_fine"},
-                    BuiltinData{BuiltinType::kDpdy, CallParamType::kF32, "ddy"},
-                    BuiltinData{BuiltinType::kDpdyCoarse, CallParamType::kF32, "ddy_coarse"},
-                    BuiltinData{BuiltinType::kDpdyFine, CallParamType::kF32, "ddy_fine"},
-                    BuiltinData{BuiltinType::kFwidth, CallParamType::kF32, "fwidth"},
-                    BuiltinData{BuiltinType::kFwidthCoarse, CallParamType::kF32, "fwidth"},
-                    BuiltinData{BuiltinType::kFwidthFine, CallParamType::kF32, "fwidth"}));
+                    BuiltinData{builtin::Function::kDpdx, CallParamType::kF32, "ddx"},
+                    BuiltinData{builtin::Function::kDpdxCoarse, CallParamType::kF32, "ddx_coarse"},
+                    BuiltinData{builtin::Function::kDpdxFine, CallParamType::kF32, "ddx_fine"},
+                    BuiltinData{builtin::Function::kDpdy, CallParamType::kF32, "ddy"},
+                    BuiltinData{builtin::Function::kDpdyCoarse, CallParamType::kF32, "ddy_coarse"},
+                    BuiltinData{builtin::Function::kDpdyFine, CallParamType::kF32, "ddy_fine"},
+                    BuiltinData{builtin::Function::kFwidth, CallParamType::kF32, "fwidth"},
+                    BuiltinData{builtin::Function::kFwidthCoarse, CallParamType::kF32, "fwidth"},
+                    BuiltinData{builtin::Function::kFwidthFine, CallParamType::kF32, "fwidth"}));
 
 TEST_F(HlslGeneratorImplTest_Builtin, Builtin_Call) {
     auto* call = Call("dot", "param1", "param2");
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index 5c9e11b..92bdb96 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -699,20 +699,20 @@
     auto name = generate_builtin_name(builtin);
 
     switch (builtin->Type()) {
-        case sem::BuiltinType::kDot:
+        case builtin::Function::kDot:
             return EmitDotCall(out, expr, builtin);
-        case sem::BuiltinType::kModf:
+        case builtin::Function::kModf:
             return EmitModfCall(out, expr, builtin);
-        case sem::BuiltinType::kFrexp:
+        case builtin::Function::kFrexp:
             return EmitFrexpCall(out, expr, builtin);
-        case sem::BuiltinType::kDegrees:
+        case builtin::Function::kDegrees:
             return EmitDegreesCall(out, expr, builtin);
-        case sem::BuiltinType::kRadians:
+        case builtin::Function::kRadians:
             return EmitRadiansCall(out, expr, builtin);
 
-        case sem::BuiltinType::kPack2X16Float:
-        case sem::BuiltinType::kUnpack2X16Float: {
-            if (builtin->Type() == sem::BuiltinType::kPack2X16Float) {
+        case builtin::Function::kPack2X16Float:
+        case builtin::Function::kUnpack2X16Float: {
+            if (builtin->Type() == builtin::Function::kPack2X16Float) {
                 out << "as_type<uint>(half2(";
             } else {
                 out << "float2(as_type<half2>(";
@@ -723,7 +723,7 @@
             out << "))";
             return true;
         }
-        case sem::BuiltinType::kQuantizeToF16: {
+        case builtin::Function::kQuantizeToF16: {
             std::string width = "";
             if (auto* vec = builtin->ReturnType()->As<type::Vector>()) {
                 width = std::to_string(vec->Width());
@@ -737,16 +737,16 @@
         }
         // TODO(crbug.com/tint/661): Combine sequential barriers to a single
         // instruction.
-        case sem::BuiltinType::kStorageBarrier: {
+        case builtin::Function::kStorageBarrier: {
             out << "threadgroup_barrier(mem_flags::mem_device)";
             return true;
         }
-        case sem::BuiltinType::kWorkgroupBarrier: {
+        case builtin::Function::kWorkgroupBarrier: {
             out << "threadgroup_barrier(mem_flags::mem_threadgroup)";
             return true;
         }
 
-        case sem::BuiltinType::kLength: {
+        case builtin::Function::kLength: {
             auto* sem = builder_.Sem().GetVal(expr->args[0]);
             if (sem->Type()->UnwrapRef()->is_scalar()) {
                 // Emulate scalar overload using fabs(x).
@@ -755,7 +755,7 @@
             break;
         }
 
-        case sem::BuiltinType::kDistance: {
+        case builtin::Function::kDistance: {
             auto* sem = builder_.Sem().GetVal(expr->args[0]);
             if (sem->Type()->UnwrapRef()->is_scalar()) {
                 // Emulate scalar overload using fabs(x - y);
@@ -896,37 +896,37 @@
     };
 
     switch (builtin->Type()) {
-        case sem::BuiltinType::kAtomicLoad:
+        case builtin::Function::kAtomicLoad:
             return call("atomic_load_explicit", true);
 
-        case sem::BuiltinType::kAtomicStore:
+        case builtin::Function::kAtomicStore:
             return call("atomic_store_explicit", true);
 
-        case sem::BuiltinType::kAtomicAdd:
+        case builtin::Function::kAtomicAdd:
             return call("atomic_fetch_add_explicit", true);
 
-        case sem::BuiltinType::kAtomicSub:
+        case builtin::Function::kAtomicSub:
             return call("atomic_fetch_sub_explicit", true);
 
-        case sem::BuiltinType::kAtomicMax:
+        case builtin::Function::kAtomicMax:
             return call("atomic_fetch_max_explicit", true);
 
-        case sem::BuiltinType::kAtomicMin:
+        case builtin::Function::kAtomicMin:
             return call("atomic_fetch_min_explicit", true);
 
-        case sem::BuiltinType::kAtomicAnd:
+        case builtin::Function::kAtomicAnd:
             return call("atomic_fetch_and_explicit", true);
 
-        case sem::BuiltinType::kAtomicOr:
+        case builtin::Function::kAtomicOr:
             return call("atomic_fetch_or_explicit", true);
 
-        case sem::BuiltinType::kAtomicXor:
+        case builtin::Function::kAtomicXor:
             return call("atomic_fetch_xor_explicit", true);
 
-        case sem::BuiltinType::kAtomicExchange:
+        case builtin::Function::kAtomicExchange:
             return call("atomic_exchange_explicit", true);
 
-        case sem::BuiltinType::kAtomicCompareExchangeWeak: {
+        case builtin::Function::kAtomicCompareExchangeWeak: {
             auto* ptr_ty = TypeOf(expr->args[0])->UnwrapRef()->As<type::Pointer>();
             auto sc = ptr_ty->AddressSpace();
             auto* str = builtin->ReturnType()->As<sem::Struct>();
@@ -1041,7 +1041,7 @@
     bool level_is_constant_zero = texture_type->dim() == type::TextureDimension::k1d;
 
     switch (builtin->Type()) {
-        case sem::BuiltinType::kTextureDimensions: {
+        case builtin::Function::kTextureDimensions: {
             std::vector<const char*> dims;
             switch (texture_type->dim()) {
                 case type::TextureDimension::kNone:
@@ -1094,21 +1094,21 @@
             }
             return true;
         }
-        case sem::BuiltinType::kTextureNumLayers: {
+        case builtin::Function::kTextureNumLayers: {
             if (!texture_expr()) {
                 return false;
             }
             out << ".get_array_size()";
             return true;
         }
-        case sem::BuiltinType::kTextureNumLevels: {
+        case builtin::Function::kTextureNumLevels: {
             if (!texture_expr()) {
                 return false;
             }
             out << ".get_num_mip_levels()";
             return true;
         }
-        case sem::BuiltinType::kTextureNumSamples: {
+        case builtin::Function::kTextureNumSamples: {
             if (!texture_expr()) {
                 return false;
             }
@@ -1126,27 +1126,27 @@
     bool lod_param_is_named = true;
 
     switch (builtin->Type()) {
-        case sem::BuiltinType::kTextureSample:
-        case sem::BuiltinType::kTextureSampleBias:
-        case sem::BuiltinType::kTextureSampleLevel:
-        case sem::BuiltinType::kTextureSampleGrad:
+        case builtin::Function::kTextureSample:
+        case builtin::Function::kTextureSampleBias:
+        case builtin::Function::kTextureSampleLevel:
+        case builtin::Function::kTextureSampleGrad:
             out << ".sample(";
             break;
-        case sem::BuiltinType::kTextureSampleCompare:
-        case sem::BuiltinType::kTextureSampleCompareLevel:
+        case builtin::Function::kTextureSampleCompare:
+        case builtin::Function::kTextureSampleCompareLevel:
             out << ".sample_compare(";
             break;
-        case sem::BuiltinType::kTextureGather:
+        case builtin::Function::kTextureGather:
             out << ".gather(";
             break;
-        case sem::BuiltinType::kTextureGatherCompare:
+        case builtin::Function::kTextureGatherCompare:
             out << ".gather_compare(";
             break;
-        case sem::BuiltinType::kTextureLoad:
+        case builtin::Function::kTextureLoad:
             out << ".read(";
             lod_param_is_named = false;
             break;
-        case sem::BuiltinType::kTextureStore:
+        case builtin::Function::kTextureStore:
             out << ".write(";
             break;
         default:
@@ -1223,7 +1223,7 @@
             out << ")";
         }
     }
-    if (builtin->Type() == sem::BuiltinType::kTextureSampleCompareLevel) {
+    if (builtin->Type() == builtin::Function::kTextureSampleCompareLevel) {
         maybe_write_comma();
         out << "level(0)";
     }
@@ -1430,143 +1430,143 @@
 std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
     std::string out = "";
     switch (builtin->Type()) {
-        case sem::BuiltinType::kAcos:
-        case sem::BuiltinType::kAcosh:
-        case sem::BuiltinType::kAll:
-        case sem::BuiltinType::kAny:
-        case sem::BuiltinType::kAsin:
-        case sem::BuiltinType::kAsinh:
-        case sem::BuiltinType::kAtanh:
-        case sem::BuiltinType::kAtan:
-        case sem::BuiltinType::kAtan2:
-        case sem::BuiltinType::kCeil:
-        case sem::BuiltinType::kCos:
-        case sem::BuiltinType::kCosh:
-        case sem::BuiltinType::kCross:
-        case sem::BuiltinType::kDeterminant:
-        case sem::BuiltinType::kDistance:
-        case sem::BuiltinType::kDot:
-        case sem::BuiltinType::kExp:
-        case sem::BuiltinType::kExp2:
-        case sem::BuiltinType::kFloor:
-        case sem::BuiltinType::kFma:
-        case sem::BuiltinType::kFract:
-        case sem::BuiltinType::kFrexp:
-        case sem::BuiltinType::kLength:
-        case sem::BuiltinType::kLdexp:
-        case sem::BuiltinType::kLog:
-        case sem::BuiltinType::kLog2:
-        case sem::BuiltinType::kMix:
-        case sem::BuiltinType::kModf:
-        case sem::BuiltinType::kNormalize:
-        case sem::BuiltinType::kPow:
-        case sem::BuiltinType::kReflect:
-        case sem::BuiltinType::kRefract:
-        case sem::BuiltinType::kSaturate:
-        case sem::BuiltinType::kSelect:
-        case sem::BuiltinType::kSin:
-        case sem::BuiltinType::kSinh:
-        case sem::BuiltinType::kSqrt:
-        case sem::BuiltinType::kStep:
-        case sem::BuiltinType::kTan:
-        case sem::BuiltinType::kTanh:
-        case sem::BuiltinType::kTranspose:
-        case sem::BuiltinType::kTrunc:
-        case sem::BuiltinType::kSign:
-        case sem::BuiltinType::kClamp:
+        case builtin::Function::kAcos:
+        case builtin::Function::kAcosh:
+        case builtin::Function::kAll:
+        case builtin::Function::kAny:
+        case builtin::Function::kAsin:
+        case builtin::Function::kAsinh:
+        case builtin::Function::kAtanh:
+        case builtin::Function::kAtan:
+        case builtin::Function::kAtan2:
+        case builtin::Function::kCeil:
+        case builtin::Function::kCos:
+        case builtin::Function::kCosh:
+        case builtin::Function::kCross:
+        case builtin::Function::kDeterminant:
+        case builtin::Function::kDistance:
+        case builtin::Function::kDot:
+        case builtin::Function::kExp:
+        case builtin::Function::kExp2:
+        case builtin::Function::kFloor:
+        case builtin::Function::kFma:
+        case builtin::Function::kFract:
+        case builtin::Function::kFrexp:
+        case builtin::Function::kLength:
+        case builtin::Function::kLdexp:
+        case builtin::Function::kLog:
+        case builtin::Function::kLog2:
+        case builtin::Function::kMix:
+        case builtin::Function::kModf:
+        case builtin::Function::kNormalize:
+        case builtin::Function::kPow:
+        case builtin::Function::kReflect:
+        case builtin::Function::kRefract:
+        case builtin::Function::kSaturate:
+        case builtin::Function::kSelect:
+        case builtin::Function::kSin:
+        case builtin::Function::kSinh:
+        case builtin::Function::kSqrt:
+        case builtin::Function::kStep:
+        case builtin::Function::kTan:
+        case builtin::Function::kTanh:
+        case builtin::Function::kTranspose:
+        case builtin::Function::kTrunc:
+        case builtin::Function::kSign:
+        case builtin::Function::kClamp:
             out += builtin->str();
             break;
-        case sem::BuiltinType::kAbs:
+        case builtin::Function::kAbs:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 out += "fabs";
             } else {
                 out += "abs";
             }
             break;
-        case sem::BuiltinType::kCountLeadingZeros:
+        case builtin::Function::kCountLeadingZeros:
             out += "clz";
             break;
-        case sem::BuiltinType::kCountOneBits:
+        case builtin::Function::kCountOneBits:
             out += "popcount";
             break;
-        case sem::BuiltinType::kCountTrailingZeros:
+        case builtin::Function::kCountTrailingZeros:
             out += "ctz";
             break;
-        case sem::BuiltinType::kDpdx:
-        case sem::BuiltinType::kDpdxCoarse:
-        case sem::BuiltinType::kDpdxFine:
+        case builtin::Function::kDpdx:
+        case builtin::Function::kDpdxCoarse:
+        case builtin::Function::kDpdxFine:
             out += "dfdx";
             break;
-        case sem::BuiltinType::kDpdy:
-        case sem::BuiltinType::kDpdyCoarse:
-        case sem::BuiltinType::kDpdyFine:
+        case builtin::Function::kDpdy:
+        case builtin::Function::kDpdyCoarse:
+        case builtin::Function::kDpdyFine:
             out += "dfdy";
             break;
-        case sem::BuiltinType::kExtractBits:
+        case builtin::Function::kExtractBits:
             out += "extract_bits";
             break;
-        case sem::BuiltinType::kInsertBits:
+        case builtin::Function::kInsertBits:
             out += "insert_bits";
             break;
-        case sem::BuiltinType::kFwidth:
-        case sem::BuiltinType::kFwidthCoarse:
-        case sem::BuiltinType::kFwidthFine:
+        case builtin::Function::kFwidth:
+        case builtin::Function::kFwidthCoarse:
+        case builtin::Function::kFwidthFine:
             out += "fwidth";
             break;
-        case sem::BuiltinType::kMax:
+        case builtin::Function::kMax:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 out += "fmax";
             } else {
                 out += "max";
             }
             break;
-        case sem::BuiltinType::kMin:
+        case builtin::Function::kMin:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 out += "fmin";
             } else {
                 out += "min";
             }
             break;
-        case sem::BuiltinType::kFaceForward:
+        case builtin::Function::kFaceForward:
             out += "faceforward";
             break;
-        case sem::BuiltinType::kPack4X8Snorm:
+        case builtin::Function::kPack4X8Snorm:
             out += "pack_float_to_snorm4x8";
             break;
-        case sem::BuiltinType::kPack4X8Unorm:
+        case builtin::Function::kPack4X8Unorm:
             out += "pack_float_to_unorm4x8";
             break;
-        case sem::BuiltinType::kPack2X16Snorm:
+        case builtin::Function::kPack2X16Snorm:
             out += "pack_float_to_snorm2x16";
             break;
-        case sem::BuiltinType::kPack2X16Unorm:
+        case builtin::Function::kPack2X16Unorm:
             out += "pack_float_to_unorm2x16";
             break;
-        case sem::BuiltinType::kReverseBits:
+        case builtin::Function::kReverseBits:
             out += "reverse_bits";
             break;
-        case sem::BuiltinType::kRound:
+        case builtin::Function::kRound:
             out += "rint";
             break;
-        case sem::BuiltinType::kSmoothstep:
+        case builtin::Function::kSmoothstep:
             out += "smoothstep";
             break;
-        case sem::BuiltinType::kInverseSqrt:
+        case builtin::Function::kInverseSqrt:
             out += "rsqrt";
             break;
-        case sem::BuiltinType::kUnpack4X8Snorm:
+        case builtin::Function::kUnpack4X8Snorm:
             out += "unpack_snorm4x8_to_float";
             break;
-        case sem::BuiltinType::kUnpack4X8Unorm:
+        case builtin::Function::kUnpack4X8Unorm:
             out += "unpack_unorm4x8_to_float";
             break;
-        case sem::BuiltinType::kUnpack2X16Snorm:
+        case builtin::Function::kUnpack2X16Snorm:
             out += "unpack_snorm2x16_to_float";
             break;
-        case sem::BuiltinType::kUnpack2X16Unorm:
+        case builtin::Function::kUnpack2X16Unorm:
             out += "unpack_unorm2x16_to_float";
             break;
-        case sem::BuiltinType::kArrayLength:
+        case builtin::Function::kArrayLength:
             diagnostics_.add_error(
                 diag::System::Writer,
                 "Unable to translate builtin: " + std::string(builtin->str()) +
@@ -3258,7 +3258,7 @@
         TextBuffer b;
         TINT_DEFER(helpers_.Append(b));
 
-        auto fn_name = UniqueIdentifier(std::string("tint_") + sem::str(builtin->Type()));
+        auto fn_name = UniqueIdentifier(std::string("tint_") + builtin::str(builtin->Type()));
         std::vector<std::string> parameter_names;
         {
             auto decl = line(&b);
diff --git a/src/tint/writer/msl/generator_impl_builtin_test.cc b/src/tint/writer/msl/generator_impl_builtin_test.cc
index 08a2d25..6c70abe 100644
--- a/src/tint/writer/msl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/msl/generator_impl_builtin_test.cc
@@ -22,8 +22,6 @@
 namespace tint::writer::msl {
 namespace {
 
-using BuiltinType = sem::BuiltinType;
-
 using MslGeneratorImplTest = TestHelper;
 
 enum class CallParamType {
@@ -34,7 +32,7 @@
 };
 
 struct BuiltinData {
-    BuiltinType builtin;
+    builtin::Function builtin;
     CallParamType type;
     const char* msl_name;
 };
@@ -58,88 +56,88 @@
     return out;
 }
 
-const ast::CallExpression* GenerateCall(BuiltinType builtin,
+const ast::CallExpression* GenerateCall(builtin::Function builtin,
                                         CallParamType type,
                                         ProgramBuilder* builder) {
     std::string name;
     utils::StringStream str;
     str << name << builtin;
     switch (builtin) {
-        case BuiltinType::kAcos:
-        case BuiltinType::kAsin:
-        case BuiltinType::kAtan:
-        case BuiltinType::kCeil:
-        case BuiltinType::kCos:
-        case BuiltinType::kCosh:
-        case BuiltinType::kDpdx:
-        case BuiltinType::kDpdxCoarse:
-        case BuiltinType::kDpdxFine:
-        case BuiltinType::kDpdy:
-        case BuiltinType::kDpdyCoarse:
-        case BuiltinType::kDpdyFine:
-        case BuiltinType::kExp:
-        case BuiltinType::kExp2:
-        case BuiltinType::kFloor:
-        case BuiltinType::kFract:
-        case BuiltinType::kFwidth:
-        case BuiltinType::kFwidthCoarse:
-        case BuiltinType::kFwidthFine:
-        case BuiltinType::kInverseSqrt:
-        case BuiltinType::kLength:
-        case BuiltinType::kLog:
-        case BuiltinType::kLog2:
-        case BuiltinType::kNormalize:
-        case BuiltinType::kRound:
-        case BuiltinType::kSin:
-        case BuiltinType::kSinh:
-        case BuiltinType::kSqrt:
-        case BuiltinType::kTan:
-        case BuiltinType::kTanh:
-        case BuiltinType::kTrunc:
-        case BuiltinType::kSign:
+        case builtin::Function::kAcos:
+        case builtin::Function::kAsin:
+        case builtin::Function::kAtan:
+        case builtin::Function::kCeil:
+        case builtin::Function::kCos:
+        case builtin::Function::kCosh:
+        case builtin::Function::kDpdx:
+        case builtin::Function::kDpdxCoarse:
+        case builtin::Function::kDpdxFine:
+        case builtin::Function::kDpdy:
+        case builtin::Function::kDpdyCoarse:
+        case builtin::Function::kDpdyFine:
+        case builtin::Function::kExp:
+        case builtin::Function::kExp2:
+        case builtin::Function::kFloor:
+        case builtin::Function::kFract:
+        case builtin::Function::kFwidth:
+        case builtin::Function::kFwidthCoarse:
+        case builtin::Function::kFwidthFine:
+        case builtin::Function::kInverseSqrt:
+        case builtin::Function::kLength:
+        case builtin::Function::kLog:
+        case builtin::Function::kLog2:
+        case builtin::Function::kNormalize:
+        case builtin::Function::kRound:
+        case builtin::Function::kSin:
+        case builtin::Function::kSinh:
+        case builtin::Function::kSqrt:
+        case builtin::Function::kTan:
+        case builtin::Function::kTanh:
+        case builtin::Function::kTrunc:
+        case builtin::Function::kSign:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2");
             } else {
                 return builder->Call(str.str(), "f2");
             }
-        case BuiltinType::kLdexp:
+        case builtin::Function::kLdexp:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "i2");
             } else {
                 return builder->Call(str.str(), "f2", "i2");
             }
-        case BuiltinType::kAtan2:
-        case BuiltinType::kDot:
-        case BuiltinType::kDistance:
-        case BuiltinType::kPow:
-        case BuiltinType::kReflect:
-        case BuiltinType::kStep:
+        case builtin::Function::kAtan2:
+        case builtin::Function::kDot:
+        case builtin::Function::kDistance:
+        case builtin::Function::kPow:
+        case builtin::Function::kReflect:
+        case builtin::Function::kStep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2");
             }
-        case BuiltinType::kStorageBarrier:
+        case builtin::Function::kStorageBarrier:
             return builder->Call(str.str());
-        case BuiltinType::kCross:
+        case builtin::Function::kCross:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h3", "h3");
             } else {
                 return builder->Call(str.str(), "f3", "f3");
             }
-        case BuiltinType::kFma:
-        case BuiltinType::kMix:
-        case BuiltinType::kFaceForward:
-        case BuiltinType::kSmoothstep:
+        case builtin::Function::kFma:
+        case builtin::Function::kMix:
+        case builtin::Function::kFaceForward:
+        case builtin::Function::kSmoothstep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             }
-        case BuiltinType::kAll:
-        case BuiltinType::kAny:
+        case builtin::Function::kAll:
+        case builtin::Function::kAny:
             return builder->Call(str.str(), "b2");
-        case BuiltinType::kAbs:
+        case builtin::Function::kAbs:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2");
             } else if (type == CallParamType::kF16) {
@@ -147,17 +145,17 @@
             } else {
                 return builder->Call(str.str(), "u2");
             }
-        case BuiltinType::kCountLeadingZeros:
-        case BuiltinType::kCountOneBits:
-        case BuiltinType::kCountTrailingZeros:
-        case BuiltinType::kReverseBits:
+        case builtin::Function::kCountLeadingZeros:
+        case builtin::Function::kCountOneBits:
+        case builtin::Function::kCountTrailingZeros:
+        case builtin::Function::kReverseBits:
             return builder->Call(str.str(), "u2");
-        case BuiltinType::kExtractBits:
+        case builtin::Function::kExtractBits:
             return builder->Call(str.str(), "u2", "u1", "u1");
-        case BuiltinType::kInsertBits:
+        case builtin::Function::kInsertBits:
             return builder->Call(str.str(), "u2", "u2", "u1", "u1");
-        case BuiltinType::kMax:
-        case BuiltinType::kMin:
+        case builtin::Function::kMax:
+        case builtin::Function::kMin:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -165,7 +163,7 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2");
             }
-        case BuiltinType::kClamp:
+        case builtin::Function::kClamp:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -173,32 +171,32 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2", "u2");
             }
-        case BuiltinType::kSelect:
+        case builtin::Function::kSelect:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "b2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "b2");
             }
-        case BuiltinType::kDeterminant:
+        case builtin::Function::kDeterminant:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm2x2");
             } else {
                 return builder->Call(str.str(), "m2x2");
             }
-        case BuiltinType::kPack2X16Snorm:
-        case BuiltinType::kPack2X16Unorm:
+        case builtin::Function::kPack2X16Snorm:
+        case builtin::Function::kPack2X16Unorm:
             return builder->Call(str.str(), "f2");
-        case BuiltinType::kPack4X8Snorm:
-        case BuiltinType::kPack4X8Unorm:
+        case builtin::Function::kPack4X8Snorm:
+        case builtin::Function::kPack4X8Unorm:
             return builder->Call(str.str(), "f4");
-        case BuiltinType::kUnpack4X8Snorm:
-        case BuiltinType::kUnpack4X8Unorm:
-        case BuiltinType::kUnpack2X16Snorm:
-        case BuiltinType::kUnpack2X16Unorm:
+        case builtin::Function::kUnpack4X8Snorm:
+        case builtin::Function::kUnpack4X8Unorm:
+        case builtin::Function::kUnpack2X16Snorm:
+        case builtin::Function::kUnpack2X16Unorm:
             return builder->Call(str.str(), "u1");
-        case BuiltinType::kWorkgroupBarrier:
+        case builtin::Function::kWorkgroupBarrier:
             return builder->Call(str.str());
-        case BuiltinType::kTranspose:
+        case builtin::Function::kTranspose:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm3x2");
             } else {
@@ -254,120 +252,126 @@
     MslBuiltinTest,
     testing::Values(
         /* Logical built-in */
-        BuiltinData{BuiltinType::kAll, CallParamType::kBool, "all"},
-        BuiltinData{BuiltinType::kAny, CallParamType::kBool, "any"},
-        BuiltinData{BuiltinType::kSelect, CallParamType::kF32, "select"},
+        BuiltinData{builtin::Function::kAll, CallParamType::kBool, "all"},
+        BuiltinData{builtin::Function::kAny, CallParamType::kBool, "any"},
+        BuiltinData{builtin::Function::kSelect, CallParamType::kF32, "select"},
         /* Float built-in */
-        BuiltinData{BuiltinType::kAbs, CallParamType::kF32, "fabs"},
-        BuiltinData{BuiltinType::kAbs, CallParamType::kF16, "fabs"},
-        BuiltinData{BuiltinType::kAcos, CallParamType::kF32, "acos"},
-        BuiltinData{BuiltinType::kAcos, CallParamType::kF16, "acos"},
-        BuiltinData{BuiltinType::kAsin, CallParamType::kF32, "asin"},
-        BuiltinData{BuiltinType::kAsin, CallParamType::kF16, "asin"},
-        BuiltinData{BuiltinType::kAtan, CallParamType::kF32, "atan"},
-        BuiltinData{BuiltinType::kAtan, CallParamType::kF16, "atan"},
-        BuiltinData{BuiltinType::kAtan2, CallParamType::kF32, "atan2"},
-        BuiltinData{BuiltinType::kAtan2, CallParamType::kF16, "atan2"},
-        BuiltinData{BuiltinType::kCeil, CallParamType::kF32, "ceil"},
-        BuiltinData{BuiltinType::kCeil, CallParamType::kF16, "ceil"},
-        BuiltinData{BuiltinType::kClamp, CallParamType::kF32, "clamp"},
-        BuiltinData{BuiltinType::kClamp, CallParamType::kF16, "clamp"},
-        BuiltinData{BuiltinType::kCos, CallParamType::kF32, "cos"},
-        BuiltinData{BuiltinType::kCos, CallParamType::kF16, "cos"},
-        BuiltinData{BuiltinType::kCosh, CallParamType::kF32, "cosh"},
-        BuiltinData{BuiltinType::kCosh, CallParamType::kF16, "cosh"},
-        BuiltinData{BuiltinType::kCross, CallParamType::kF32, "cross"},
-        BuiltinData{BuiltinType::kCross, CallParamType::kF16, "cross"},
-        BuiltinData{BuiltinType::kDistance, CallParamType::kF32, "distance"},
-        BuiltinData{BuiltinType::kDistance, CallParamType::kF16, "distance"},
-        BuiltinData{BuiltinType::kExp, CallParamType::kF32, "exp"},
-        BuiltinData{BuiltinType::kExp, CallParamType::kF16, "exp"},
-        BuiltinData{BuiltinType::kExp2, CallParamType::kF32, "exp2"},
-        BuiltinData{BuiltinType::kExp2, CallParamType::kF16, "exp2"},
-        BuiltinData{BuiltinType::kFaceForward, CallParamType::kF32, "faceforward"},
-        BuiltinData{BuiltinType::kFaceForward, CallParamType::kF16, "faceforward"},
-        BuiltinData{BuiltinType::kFloor, CallParamType::kF32, "floor"},
-        BuiltinData{BuiltinType::kFloor, CallParamType::kF16, "floor"},
-        BuiltinData{BuiltinType::kFma, CallParamType::kF32, "fma"},
-        BuiltinData{BuiltinType::kFma, CallParamType::kF16, "fma"},
-        BuiltinData{BuiltinType::kFract, CallParamType::kF32, "fract"},
-        BuiltinData{BuiltinType::kFract, CallParamType::kF16, "fract"},
-        BuiltinData{BuiltinType::kInverseSqrt, CallParamType::kF32, "rsqrt"},
-        BuiltinData{BuiltinType::kInverseSqrt, CallParamType::kF16, "rsqrt"},
-        BuiltinData{BuiltinType::kLdexp, CallParamType::kF32, "ldexp"},
-        BuiltinData{BuiltinType::kLdexp, CallParamType::kF16, "ldexp"},
-        BuiltinData{BuiltinType::kLength, CallParamType::kF32, "length"},
-        BuiltinData{BuiltinType::kLength, CallParamType::kF16, "length"},
-        BuiltinData{BuiltinType::kLog, CallParamType::kF32, "log"},
-        BuiltinData{BuiltinType::kLog, CallParamType::kF16, "log"},
-        BuiltinData{BuiltinType::kLog2, CallParamType::kF32, "log2"},
-        BuiltinData{BuiltinType::kLog2, CallParamType::kF16, "log2"},
-        BuiltinData{BuiltinType::kMax, CallParamType::kF32, "fmax"},
-        BuiltinData{BuiltinType::kMax, CallParamType::kF16, "fmax"},
-        BuiltinData{BuiltinType::kMin, CallParamType::kF32, "fmin"},
-        BuiltinData{BuiltinType::kMin, CallParamType::kF16, "fmin"},
-        BuiltinData{BuiltinType::kNormalize, CallParamType::kF32, "normalize"},
-        BuiltinData{BuiltinType::kNormalize, CallParamType::kF16, "normalize"},
-        BuiltinData{BuiltinType::kPow, CallParamType::kF32, "pow"},
-        BuiltinData{BuiltinType::kPow, CallParamType::kF16, "pow"},
-        BuiltinData{BuiltinType::kReflect, CallParamType::kF32, "reflect"},
-        BuiltinData{BuiltinType::kReflect, CallParamType::kF16, "reflect"},
-        BuiltinData{BuiltinType::kSign, CallParamType::kF32, "sign"},
-        BuiltinData{BuiltinType::kSign, CallParamType::kF16, "sign"},
-        BuiltinData{BuiltinType::kSin, CallParamType::kF32, "sin"},
-        BuiltinData{BuiltinType::kSin, CallParamType::kF16, "sin"},
-        BuiltinData{BuiltinType::kSinh, CallParamType::kF32, "sinh"},
-        BuiltinData{BuiltinType::kSinh, CallParamType::kF16, "sinh"},
-        BuiltinData{BuiltinType::kSmoothstep, CallParamType::kF32, "smoothstep"},
-        BuiltinData{BuiltinType::kSmoothstep, CallParamType::kF16, "smoothstep"},
-        BuiltinData{BuiltinType::kSqrt, CallParamType::kF32, "sqrt"},
-        BuiltinData{BuiltinType::kSqrt, CallParamType::kF16, "sqrt"},
-        BuiltinData{BuiltinType::kStep, CallParamType::kF32, "step"},
-        BuiltinData{BuiltinType::kStep, CallParamType::kF16, "step"},
-        BuiltinData{BuiltinType::kTan, CallParamType::kF32, "tan"},
-        BuiltinData{BuiltinType::kTan, CallParamType::kF16, "tan"},
-        BuiltinData{BuiltinType::kTanh, CallParamType::kF32, "tanh"},
-        BuiltinData{BuiltinType::kTanh, CallParamType::kF16, "tanh"},
-        BuiltinData{BuiltinType::kTrunc, CallParamType::kF32, "trunc"},
-        BuiltinData{BuiltinType::kTrunc, CallParamType::kF16, "trunc"},
+        BuiltinData{builtin::Function::kAbs, CallParamType::kF32, "fabs"},
+        BuiltinData{builtin::Function::kAbs, CallParamType::kF16, "fabs"},
+        BuiltinData{builtin::Function::kAcos, CallParamType::kF32, "acos"},
+        BuiltinData{builtin::Function::kAcos, CallParamType::kF16, "acos"},
+        BuiltinData{builtin::Function::kAsin, CallParamType::kF32, "asin"},
+        BuiltinData{builtin::Function::kAsin, CallParamType::kF16, "asin"},
+        BuiltinData{builtin::Function::kAtan, CallParamType::kF32, "atan"},
+        BuiltinData{builtin::Function::kAtan, CallParamType::kF16, "atan"},
+        BuiltinData{builtin::Function::kAtan2, CallParamType::kF32, "atan2"},
+        BuiltinData{builtin::Function::kAtan2, CallParamType::kF16, "atan2"},
+        BuiltinData{builtin::Function::kCeil, CallParamType::kF32, "ceil"},
+        BuiltinData{builtin::Function::kCeil, CallParamType::kF16, "ceil"},
+        BuiltinData{builtin::Function::kClamp, CallParamType::kF32, "clamp"},
+        BuiltinData{builtin::Function::kClamp, CallParamType::kF16, "clamp"},
+        BuiltinData{builtin::Function::kCos, CallParamType::kF32, "cos"},
+        BuiltinData{builtin::Function::kCos, CallParamType::kF16, "cos"},
+        BuiltinData{builtin::Function::kCosh, CallParamType::kF32, "cosh"},
+        BuiltinData{builtin::Function::kCosh, CallParamType::kF16, "cosh"},
+        BuiltinData{builtin::Function::kCross, CallParamType::kF32, "cross"},
+        BuiltinData{builtin::Function::kCross, CallParamType::kF16, "cross"},
+        BuiltinData{builtin::Function::kDistance, CallParamType::kF32, "distance"},
+        BuiltinData{builtin::Function::kDistance, CallParamType::kF16, "distance"},
+        BuiltinData{builtin::Function::kExp, CallParamType::kF32, "exp"},
+        BuiltinData{builtin::Function::kExp, CallParamType::kF16, "exp"},
+        BuiltinData{builtin::Function::kExp2, CallParamType::kF32, "exp2"},
+        BuiltinData{builtin::Function::kExp2, CallParamType::kF16, "exp2"},
+        BuiltinData{builtin::Function::kFaceForward, CallParamType::kF32, "faceforward"},
+        BuiltinData{builtin::Function::kFaceForward, CallParamType::kF16, "faceforward"},
+        BuiltinData{builtin::Function::kFloor, CallParamType::kF32, "floor"},
+        BuiltinData{builtin::Function::kFloor, CallParamType::kF16, "floor"},
+        BuiltinData{builtin::Function::kFma, CallParamType::kF32, "fma"},
+        BuiltinData{builtin::Function::kFma, CallParamType::kF16, "fma"},
+        BuiltinData{builtin::Function::kFract, CallParamType::kF32, "fract"},
+        BuiltinData{builtin::Function::kFract, CallParamType::kF16, "fract"},
+        BuiltinData{builtin::Function::kInverseSqrt, CallParamType::kF32, "rsqrt"},
+        BuiltinData{builtin::Function::kInverseSqrt, CallParamType::kF16, "rsqrt"},
+        BuiltinData{builtin::Function::kLdexp, CallParamType::kF32, "ldexp"},
+        BuiltinData{builtin::Function::kLdexp, CallParamType::kF16, "ldexp"},
+        BuiltinData{builtin::Function::kLength, CallParamType::kF32, "length"},
+        BuiltinData{builtin::Function::kLength, CallParamType::kF16, "length"},
+        BuiltinData{builtin::Function::kLog, CallParamType::kF32, "log"},
+        BuiltinData{builtin::Function::kLog, CallParamType::kF16, "log"},
+        BuiltinData{builtin::Function::kLog2, CallParamType::kF32, "log2"},
+        BuiltinData{builtin::Function::kLog2, CallParamType::kF16, "log2"},
+        BuiltinData{builtin::Function::kMax, CallParamType::kF32, "fmax"},
+        BuiltinData{builtin::Function::kMax, CallParamType::kF16, "fmax"},
+        BuiltinData{builtin::Function::kMin, CallParamType::kF32, "fmin"},
+        BuiltinData{builtin::Function::kMin, CallParamType::kF16, "fmin"},
+        BuiltinData{builtin::Function::kNormalize, CallParamType::kF32, "normalize"},
+        BuiltinData{builtin::Function::kNormalize, CallParamType::kF16, "normalize"},
+        BuiltinData{builtin::Function::kPow, CallParamType::kF32, "pow"},
+        BuiltinData{builtin::Function::kPow, CallParamType::kF16, "pow"},
+        BuiltinData{builtin::Function::kReflect, CallParamType::kF32, "reflect"},
+        BuiltinData{builtin::Function::kReflect, CallParamType::kF16, "reflect"},
+        BuiltinData{builtin::Function::kSign, CallParamType::kF32, "sign"},
+        BuiltinData{builtin::Function::kSign, CallParamType::kF16, "sign"},
+        BuiltinData{builtin::Function::kSin, CallParamType::kF32, "sin"},
+        BuiltinData{builtin::Function::kSin, CallParamType::kF16, "sin"},
+        BuiltinData{builtin::Function::kSinh, CallParamType::kF32, "sinh"},
+        BuiltinData{builtin::Function::kSinh, CallParamType::kF16, "sinh"},
+        BuiltinData{builtin::Function::kSmoothstep, CallParamType::kF32, "smoothstep"},
+        BuiltinData{builtin::Function::kSmoothstep, CallParamType::kF16, "smoothstep"},
+        BuiltinData{builtin::Function::kSqrt, CallParamType::kF32, "sqrt"},
+        BuiltinData{builtin::Function::kSqrt, CallParamType::kF16, "sqrt"},
+        BuiltinData{builtin::Function::kStep, CallParamType::kF32, "step"},
+        BuiltinData{builtin::Function::kStep, CallParamType::kF16, "step"},
+        BuiltinData{builtin::Function::kTan, CallParamType::kF32, "tan"},
+        BuiltinData{builtin::Function::kTan, CallParamType::kF16, "tan"},
+        BuiltinData{builtin::Function::kTanh, CallParamType::kF32, "tanh"},
+        BuiltinData{builtin::Function::kTanh, CallParamType::kF16, "tanh"},
+        BuiltinData{builtin::Function::kTrunc, CallParamType::kF32, "trunc"},
+        BuiltinData{builtin::Function::kTrunc, CallParamType::kF16, "trunc"},
         /* Integer built-in */
-        BuiltinData{BuiltinType::kAbs, CallParamType::kU32, "abs"},
-        BuiltinData{BuiltinType::kClamp, CallParamType::kU32, "clamp"},
-        BuiltinData{BuiltinType::kCountLeadingZeros, CallParamType::kU32, "clz"},
-        BuiltinData{BuiltinType::kCountOneBits, CallParamType::kU32, "popcount"},
-        BuiltinData{BuiltinType::kCountTrailingZeros, CallParamType::kU32, "ctz"},
-        BuiltinData{BuiltinType::kExtractBits, CallParamType::kU32, "extract_bits"},
-        BuiltinData{BuiltinType::kInsertBits, CallParamType::kU32, "insert_bits"},
-        BuiltinData{BuiltinType::kMax, CallParamType::kU32, "max"},
-        BuiltinData{BuiltinType::kMin, CallParamType::kU32, "min"},
-        BuiltinData{BuiltinType::kReverseBits, CallParamType::kU32, "reverse_bits"},
-        BuiltinData{BuiltinType::kRound, CallParamType::kU32, "rint"},
+        BuiltinData{builtin::Function::kAbs, CallParamType::kU32, "abs"},
+        BuiltinData{builtin::Function::kClamp, CallParamType::kU32, "clamp"},
+        BuiltinData{builtin::Function::kCountLeadingZeros, CallParamType::kU32, "clz"},
+        BuiltinData{builtin::Function::kCountOneBits, CallParamType::kU32, "popcount"},
+        BuiltinData{builtin::Function::kCountTrailingZeros, CallParamType::kU32, "ctz"},
+        BuiltinData{builtin::Function::kExtractBits, CallParamType::kU32, "extract_bits"},
+        BuiltinData{builtin::Function::kInsertBits, CallParamType::kU32, "insert_bits"},
+        BuiltinData{builtin::Function::kMax, CallParamType::kU32, "max"},
+        BuiltinData{builtin::Function::kMin, CallParamType::kU32, "min"},
+        BuiltinData{builtin::Function::kReverseBits, CallParamType::kU32, "reverse_bits"},
+        BuiltinData{builtin::Function::kRound, CallParamType::kU32, "rint"},
         /* Matrix built-in */
-        BuiltinData{BuiltinType::kDeterminant, CallParamType::kF32, "determinant"},
-        BuiltinData{BuiltinType::kTranspose, CallParamType::kF32, "transpose"},
+        BuiltinData{builtin::Function::kDeterminant, CallParamType::kF32, "determinant"},
+        BuiltinData{builtin::Function::kTranspose, CallParamType::kF32, "transpose"},
         /* Vector built-in */
-        BuiltinData{BuiltinType::kDot, CallParamType::kF32, "dot"},
+        BuiltinData{builtin::Function::kDot, CallParamType::kF32, "dot"},
         /* Derivate built-in */
-        BuiltinData{BuiltinType::kDpdx, CallParamType::kF32, "dfdx"},
-        BuiltinData{BuiltinType::kDpdxCoarse, CallParamType::kF32, "dfdx"},
-        BuiltinData{BuiltinType::kDpdxFine, CallParamType::kF32, "dfdx"},
-        BuiltinData{BuiltinType::kDpdy, CallParamType::kF32, "dfdy"},
-        BuiltinData{BuiltinType::kDpdyCoarse, CallParamType::kF32, "dfdy"},
-        BuiltinData{BuiltinType::kDpdyFine, CallParamType::kF32, "dfdy"},
-        BuiltinData{BuiltinType::kFwidth, CallParamType::kF32, "fwidth"},
-        BuiltinData{BuiltinType::kFwidthCoarse, CallParamType::kF32, "fwidth"},
-        BuiltinData{BuiltinType::kFwidthFine, CallParamType::kF32, "fwidth"},
+        BuiltinData{builtin::Function::kDpdx, CallParamType::kF32, "dfdx"},
+        BuiltinData{builtin::Function::kDpdxCoarse, CallParamType::kF32, "dfdx"},
+        BuiltinData{builtin::Function::kDpdxFine, CallParamType::kF32, "dfdx"},
+        BuiltinData{builtin::Function::kDpdy, CallParamType::kF32, "dfdy"},
+        BuiltinData{builtin::Function::kDpdyCoarse, CallParamType::kF32, "dfdy"},
+        BuiltinData{builtin::Function::kDpdyFine, CallParamType::kF32, "dfdy"},
+        BuiltinData{builtin::Function::kFwidth, CallParamType::kF32, "fwidth"},
+        BuiltinData{builtin::Function::kFwidthCoarse, CallParamType::kF32, "fwidth"},
+        BuiltinData{builtin::Function::kFwidthFine, CallParamType::kF32, "fwidth"},
         /* Data packing builtin */
-        BuiltinData{BuiltinType::kPack4X8Snorm, CallParamType::kF32, "pack_float_to_snorm4x8"},
-        BuiltinData{BuiltinType::kPack4X8Unorm, CallParamType::kF32, "pack_float_to_unorm4x8"},
-        BuiltinData{BuiltinType::kPack2X16Snorm, CallParamType::kF32, "pack_float_to_snorm2x16"},
-        BuiltinData{BuiltinType::kPack2X16Unorm, CallParamType::kF32, "pack_float_to_unorm2x16"},
+        BuiltinData{builtin::Function::kPack4X8Snorm, CallParamType::kF32,
+                    "pack_float_to_snorm4x8"},
+        BuiltinData{builtin::Function::kPack4X8Unorm, CallParamType::kF32,
+                    "pack_float_to_unorm4x8"},
+        BuiltinData{builtin::Function::kPack2X16Snorm, CallParamType::kF32,
+                    "pack_float_to_snorm2x16"},
+        BuiltinData{builtin::Function::kPack2X16Unorm, CallParamType::kF32,
+                    "pack_float_to_unorm2x16"},
         /* Data unpacking builtin */
-        BuiltinData{BuiltinType::kUnpack4X8Snorm, CallParamType::kU32, "unpack_snorm4x8_to_float"},
-        BuiltinData{BuiltinType::kUnpack4X8Unorm, CallParamType::kU32, "unpack_unorm4x8_to_float"},
-        BuiltinData{BuiltinType::kUnpack2X16Snorm, CallParamType::kU32,
+        BuiltinData{builtin::Function::kUnpack4X8Snorm, CallParamType::kU32,
+                    "unpack_snorm4x8_to_float"},
+        BuiltinData{builtin::Function::kUnpack4X8Unorm, CallParamType::kU32,
+                    "unpack_unorm4x8_to_float"},
+        BuiltinData{builtin::Function::kUnpack2X16Snorm, CallParamType::kU32,
                     "unpack_snorm2x16_to_float"},
-        BuiltinData{BuiltinType::kUnpack2X16Unorm, CallParamType::kU32,
+        BuiltinData{builtin::Function::kUnpack2X16Unorm, CallParamType::kU32,
                     "unpack_unorm2x16_to_float"}));
 
 TEST_F(MslGeneratorImplTest, Builtin_Call) {
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index 40f98d8..ae14acd 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -56,8 +56,6 @@
 namespace tint::writer::spirv {
 namespace {
 
-using BuiltinType = sem::BuiltinType;
-
 const char kGLSLstd450[] = "GLSL.std.450";
 
 uint32_t size_of(const InstructionList& instructions) {
@@ -102,23 +100,23 @@
 
 uint32_t builtin_to_glsl_method(const sem::Builtin* builtin) {
     switch (builtin->Type()) {
-        case BuiltinType::kAcos:
+        case builtin::Function::kAcos:
             return GLSLstd450Acos;
-        case BuiltinType::kAcosh:
+        case builtin::Function::kAcosh:
             return GLSLstd450Acosh;
-        case BuiltinType::kAsin:
+        case builtin::Function::kAsin:
             return GLSLstd450Asin;
-        case BuiltinType::kAsinh:
+        case builtin::Function::kAsinh:
             return GLSLstd450Asinh;
-        case BuiltinType::kAtan:
+        case builtin::Function::kAtan:
             return GLSLstd450Atan;
-        case BuiltinType::kAtan2:
+        case builtin::Function::kAtan2:
             return GLSLstd450Atan2;
-        case BuiltinType::kAtanh:
+        case builtin::Function::kAtanh:
             return GLSLstd450Atanh;
-        case BuiltinType::kCeil:
+        case builtin::Function::kCeil:
             return GLSLstd450Ceil;
-        case BuiltinType::kClamp:
+        case builtin::Function::kClamp:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 return GLSLstd450NClamp;
             } else if (builtin->ReturnType()->is_unsigned_integer_scalar_or_vector()) {
@@ -126,43 +124,43 @@
             } else {
                 return GLSLstd450SClamp;
             }
-        case BuiltinType::kCos:
+        case builtin::Function::kCos:
             return GLSLstd450Cos;
-        case BuiltinType::kCosh:
+        case builtin::Function::kCosh:
             return GLSLstd450Cosh;
-        case BuiltinType::kCross:
+        case builtin::Function::kCross:
             return GLSLstd450Cross;
-        case BuiltinType::kDegrees:
+        case builtin::Function::kDegrees:
             return GLSLstd450Degrees;
-        case BuiltinType::kDeterminant:
+        case builtin::Function::kDeterminant:
             return GLSLstd450Determinant;
-        case BuiltinType::kDistance:
+        case builtin::Function::kDistance:
             return GLSLstd450Distance;
-        case BuiltinType::kExp:
+        case builtin::Function::kExp:
             return GLSLstd450Exp;
-        case BuiltinType::kExp2:
+        case builtin::Function::kExp2:
             return GLSLstd450Exp2;
-        case BuiltinType::kFaceForward:
+        case builtin::Function::kFaceForward:
             return GLSLstd450FaceForward;
-        case BuiltinType::kFloor:
+        case builtin::Function::kFloor:
             return GLSLstd450Floor;
-        case BuiltinType::kFma:
+        case builtin::Function::kFma:
             return GLSLstd450Fma;
-        case BuiltinType::kFract:
+        case builtin::Function::kFract:
             return GLSLstd450Fract;
-        case BuiltinType::kFrexp:
+        case builtin::Function::kFrexp:
             return GLSLstd450FrexpStruct;
-        case BuiltinType::kInverseSqrt:
+        case builtin::Function::kInverseSqrt:
             return GLSLstd450InverseSqrt;
-        case BuiltinType::kLdexp:
+        case builtin::Function::kLdexp:
             return GLSLstd450Ldexp;
-        case BuiltinType::kLength:
+        case builtin::Function::kLength:
             return GLSLstd450Length;
-        case BuiltinType::kLog:
+        case builtin::Function::kLog:
             return GLSLstd450Log;
-        case BuiltinType::kLog2:
+        case builtin::Function::kLog2:
             return GLSLstd450Log2;
-        case BuiltinType::kMax:
+        case builtin::Function::kMax:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 return GLSLstd450NMax;
             } else if (builtin->ReturnType()->is_unsigned_integer_scalar_or_vector()) {
@@ -170,7 +168,7 @@
             } else {
                 return GLSLstd450SMax;
             }
-        case BuiltinType::kMin:
+        case builtin::Function::kMin:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 return GLSLstd450NMin;
             } else if (builtin->ReturnType()->is_unsigned_integer_scalar_or_vector()) {
@@ -178,63 +176,63 @@
             } else {
                 return GLSLstd450SMin;
             }
-        case BuiltinType::kMix:
+        case builtin::Function::kMix:
             return GLSLstd450FMix;
-        case BuiltinType::kModf:
+        case builtin::Function::kModf:
             return GLSLstd450ModfStruct;
-        case BuiltinType::kNormalize:
+        case builtin::Function::kNormalize:
             return GLSLstd450Normalize;
-        case BuiltinType::kPack4X8Snorm:
+        case builtin::Function::kPack4X8Snorm:
             return GLSLstd450PackSnorm4x8;
-        case BuiltinType::kPack4X8Unorm:
+        case builtin::Function::kPack4X8Unorm:
             return GLSLstd450PackUnorm4x8;
-        case BuiltinType::kPack2X16Snorm:
+        case builtin::Function::kPack2X16Snorm:
             return GLSLstd450PackSnorm2x16;
-        case BuiltinType::kPack2X16Unorm:
+        case builtin::Function::kPack2X16Unorm:
             return GLSLstd450PackUnorm2x16;
-        case BuiltinType::kPack2X16Float:
+        case builtin::Function::kPack2X16Float:
             return GLSLstd450PackHalf2x16;
-        case BuiltinType::kPow:
+        case builtin::Function::kPow:
             return GLSLstd450Pow;
-        case BuiltinType::kRadians:
+        case builtin::Function::kRadians:
             return GLSLstd450Radians;
-        case BuiltinType::kReflect:
+        case builtin::Function::kReflect:
             return GLSLstd450Reflect;
-        case BuiltinType::kRefract:
+        case builtin::Function::kRefract:
             return GLSLstd450Refract;
-        case BuiltinType::kRound:
+        case builtin::Function::kRound:
             return GLSLstd450RoundEven;
-        case BuiltinType::kSign:
+        case builtin::Function::kSign:
             if (builtin->ReturnType()->is_signed_integer_scalar_or_vector()) {
                 return GLSLstd450SSign;
             } else {
                 return GLSLstd450FSign;
             }
-        case BuiltinType::kSin:
+        case builtin::Function::kSin:
             return GLSLstd450Sin;
-        case BuiltinType::kSinh:
+        case builtin::Function::kSinh:
             return GLSLstd450Sinh;
-        case BuiltinType::kSmoothstep:
+        case builtin::Function::kSmoothstep:
             return GLSLstd450SmoothStep;
-        case BuiltinType::kSqrt:
+        case builtin::Function::kSqrt:
             return GLSLstd450Sqrt;
-        case BuiltinType::kStep:
+        case builtin::Function::kStep:
             return GLSLstd450Step;
-        case BuiltinType::kTan:
+        case builtin::Function::kTan:
             return GLSLstd450Tan;
-        case BuiltinType::kTanh:
+        case builtin::Function::kTanh:
             return GLSLstd450Tanh;
-        case BuiltinType::kTrunc:
+        case builtin::Function::kTrunc:
             return GLSLstd450Trunc;
-        case BuiltinType::kUnpack4X8Snorm:
+        case builtin::Function::kUnpack4X8Snorm:
             return GLSLstd450UnpackSnorm4x8;
-        case BuiltinType::kUnpack4X8Unorm:
+        case builtin::Function::kUnpack4X8Unorm:
             return GLSLstd450UnpackUnorm4x8;
-        case BuiltinType::kUnpack2X16Snorm:
+        case builtin::Function::kUnpack2X16Snorm:
             return GLSLstd450UnpackSnorm2x16;
-        case BuiltinType::kUnpack2X16Unorm:
+        case builtin::Function::kUnpack2X16Unorm:
             return GLSLstd450UnpackUnorm2x16;
-        case BuiltinType::kUnpack2X16Float:
+        case builtin::Function::kUnpack2X16Float:
             return GLSLstd450UnpackHalf2x16;
         default:
             break;
@@ -2363,21 +2361,21 @@
     };
 
     switch (builtin->Type()) {
-        case BuiltinType::kAny:
+        case builtin::Function::kAny:
             if (builtin->Parameters()[0]->Type()->Is<type::Bool>()) {
                 // any(v: bool) just resolves to v.
                 return get_arg_as_value_id(0);
             }
             op = spv::Op::OpAny;
             break;
-        case BuiltinType::kAll:
+        case builtin::Function::kAll:
             if (builtin->Parameters()[0]->Type()->Is<type::Bool>()) {
                 // all(v: bool) just resolves to v.
                 return get_arg_as_value_id(0);
             }
             op = spv::Op::OpAll;
             break;
-        case BuiltinType::kArrayLength: {
+        case builtin::Function::kArrayLength: {
             auto* address_of = call->Arguments()[0]->Declaration()->As<ast::UnaryOpExpression>();
             if (!address_of || address_of->op != ast::UnaryOp::kAddressOf) {
                 error_ = "arrayLength() expected pointer to member access, got " +
@@ -2414,10 +2412,10 @@
             }
             return result_id;
         }
-        case BuiltinType::kCountOneBits:
+        case builtin::Function::kCountOneBits:
             op = spv::Op::OpBitCount;
             break;
-        case BuiltinType::kDot: {
+        case builtin::Function::kDot: {
             op = spv::Op::OpDot;
             auto* vec_ty = builtin->Parameters()[0]->Type()->As<type::Vector>();
             if (vec_ty->type()->is_integer_scalar()) {
@@ -2458,42 +2456,42 @@
             }
             break;
         }
-        case BuiltinType::kDpdx:
+        case builtin::Function::kDpdx:
             op = spv::Op::OpDPdx;
             break;
-        case BuiltinType::kDpdxCoarse:
+        case builtin::Function::kDpdxCoarse:
             op = spv::Op::OpDPdxCoarse;
             break;
-        case BuiltinType::kDpdxFine:
+        case builtin::Function::kDpdxFine:
             op = spv::Op::OpDPdxFine;
             break;
-        case BuiltinType::kDpdy:
+        case builtin::Function::kDpdy:
             op = spv::Op::OpDPdy;
             break;
-        case BuiltinType::kDpdyCoarse:
+        case builtin::Function::kDpdyCoarse:
             op = spv::Op::OpDPdyCoarse;
             break;
-        case BuiltinType::kDpdyFine:
+        case builtin::Function::kDpdyFine:
             op = spv::Op::OpDPdyFine;
             break;
-        case BuiltinType::kExtractBits:
+        case builtin::Function::kExtractBits:
             op = builtin->Parameters()[0]->Type()->is_unsigned_integer_scalar_or_vector()
                      ? spv::Op::OpBitFieldUExtract
                      : spv::Op::OpBitFieldSExtract;
             break;
-        case BuiltinType::kFwidth:
+        case builtin::Function::kFwidth:
             op = spv::Op::OpFwidth;
             break;
-        case BuiltinType::kFwidthCoarse:
+        case builtin::Function::kFwidthCoarse:
             op = spv::Op::OpFwidthCoarse;
             break;
-        case BuiltinType::kFwidthFine:
+        case builtin::Function::kFwidthFine:
             op = spv::Op::OpFwidthFine;
             break;
-        case BuiltinType::kInsertBits:
+        case builtin::Function::kInsertBits:
             op = spv::Op::OpBitFieldInsert;
             break;
-        case BuiltinType::kMix: {
+        case builtin::Function::kMix: {
             auto std450 = Operand(GetGLSLstd450Import());
 
             auto a_id = get_arg_as_value_id(0);
@@ -2520,13 +2518,13 @@
             }
             return result_id;
         }
-        case BuiltinType::kQuantizeToF16:
+        case builtin::Function::kQuantizeToF16:
             op = spv::Op::OpQuantizeToF16;
             break;
-        case BuiltinType::kReverseBits:
+        case builtin::Function::kReverseBits:
             op = spv::Op::OpBitReverse;
             break;
-        case BuiltinType::kSelect: {
+        case builtin::Function::kSelect: {
             // Note: Argument order is different in WGSL and SPIR-V
             auto cond_id = get_arg_as_value_id(2);
             auto true_id = get_arg_as_value_id(1);
@@ -2558,10 +2556,10 @@
             }
             return result_id;
         }
-        case BuiltinType::kTranspose:
+        case builtin::Function::kTranspose:
             op = spv::Op::OpTranspose;
             break;
-        case BuiltinType::kAbs:
+        case builtin::Function::kAbs:
             if (builtin->ReturnType()->is_unsigned_integer_scalar_or_vector()) {
                 // abs() only operates on *signed* integers.
                 // This is a no-op for unsigned integers.
@@ -2573,7 +2571,7 @@
                 glsl_std450(GLSLstd450SAbs);
             }
             break;
-        case BuiltinType::kDot4I8Packed: {
+        case builtin::Function::kDot4I8Packed: {
             auto first_param_id = get_arg_as_value_id(0);
             auto second_param_id = get_arg_as_value_id(1);
             if (!push_function_inst(spv::Op::OpSDotKHR,
@@ -2585,7 +2583,7 @@
             }
             return result_id;
         }
-        case BuiltinType::kDot4U8Packed: {
+        case builtin::Function::kDot4U8Packed: {
             auto first_param_id = get_arg_as_value_id(0);
             auto second_param_id = get_arg_as_value_id(1);
             if (!push_function_inst(spv::Op::OpUDotKHR,
@@ -2788,7 +2786,7 @@
     };
 
     switch (builtin->Type()) {
-        case BuiltinType::kTextureDimensions: {
+        case builtin::Function::kTextureDimensions: {
             // Number of returned elements from OpImageQuerySize[Lod] may not match
             // those of textureDimensions().
             // This might be due to an extra vector scalar describing the number of
@@ -2833,7 +2831,7 @@
             }
             break;
         }
-        case BuiltinType::kTextureNumLayers: {
+        case builtin::Function::kTextureNumLayers: {
             uint32_t spirv_dims = 0;
             switch (texture_type->dim()) {
                 default:
@@ -2863,19 +2861,19 @@
             }
             break;
         }
-        case BuiltinType::kTextureNumLevels: {
+        case builtin::Function::kTextureNumLevels: {
             op = spv::Op::OpImageQueryLevels;
             append_result_type_and_id_to_spirv_params();
             spirv_params.emplace_back(gen_arg(Usage::kTexture));
             break;
         }
-        case BuiltinType::kTextureNumSamples: {
+        case builtin::Function::kTextureNumSamples: {
             op = spv::Op::OpImageQuerySamples;
             append_result_type_and_id_to_spirv_params();
             spirv_params.emplace_back(gen_arg(Usage::kTexture));
             break;
         }
-        case BuiltinType::kTextureLoad: {
+        case builtin::Function::kTextureLoad: {
             op = texture_type->Is<type::StorageTexture>() ? spv::Op::OpImageRead
                                                           : spv::Op::OpImageFetch;
             append_result_type_and_id_to_spirv_params_for_read();
@@ -2895,7 +2893,7 @@
 
             break;
         }
-        case BuiltinType::kTextureStore: {
+        case builtin::Function::kTextureStore: {
             op = spv::Op::OpImageWrite;
             spirv_params.emplace_back(gen_arg(Usage::kTexture));
             if (!append_coords_to_spirv_params()) {
@@ -2904,7 +2902,7 @@
             spirv_params.emplace_back(gen_arg(Usage::kValue));
             break;
         }
-        case BuiltinType::kTextureGather: {
+        case builtin::Function::kTextureGather: {
             op = spv::Op::OpImageGather;
             append_result_type_and_id_to_spirv_params();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2918,7 +2916,7 @@
             }
             break;
         }
-        case BuiltinType::kTextureGatherCompare: {
+        case builtin::Function::kTextureGatherCompare: {
             op = spv::Op::OpImageDrefGather;
             append_result_type_and_id_to_spirv_params();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2927,7 +2925,7 @@
             spirv_params.emplace_back(gen_arg(Usage::kDepthRef));
             break;
         }
-        case BuiltinType::kTextureSample: {
+        case builtin::Function::kTextureSample: {
             op = spv::Op::OpImageSampleImplicitLod;
             append_result_type_and_id_to_spirv_params_for_read();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2935,7 +2933,7 @@
             }
             break;
         }
-        case BuiltinType::kTextureSampleBias: {
+        case builtin::Function::kTextureSampleBias: {
             op = spv::Op::OpImageSampleImplicitLod;
             append_result_type_and_id_to_spirv_params_for_read();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2945,7 +2943,7 @@
                 ImageOperand{SpvImageOperandsBiasMask, gen_arg(Usage::kBias)});
             break;
         }
-        case BuiltinType::kTextureSampleLevel: {
+        case builtin::Function::kTextureSampleLevel: {
             op = spv::Op::OpImageSampleExplicitLod;
             append_result_type_and_id_to_spirv_params_for_read();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2970,7 +2968,7 @@
             image_operands.emplace_back(ImageOperand{SpvImageOperandsLodMask, level});
             break;
         }
-        case BuiltinType::kTextureSampleGrad: {
+        case builtin::Function::kTextureSampleGrad: {
             op = spv::Op::OpImageSampleExplicitLod;
             append_result_type_and_id_to_spirv_params_for_read();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2982,7 +2980,7 @@
                 ImageOperand{SpvImageOperandsGradMask, gen_arg(Usage::kDdy)});
             break;
         }
-        case BuiltinType::kTextureSampleCompare: {
+        case builtin::Function::kTextureSampleCompare: {
             op = spv::Op::OpImageSampleDrefImplicitLod;
             append_result_type_and_id_to_spirv_params();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2991,7 +2989,7 @@
             spirv_params.emplace_back(gen_arg(Usage::kDepthRef));
             break;
         }
-        case BuiltinType::kTextureSampleCompareLevel: {
+        case builtin::Function::kTextureSampleCompareLevel: {
             op = spv::Op::OpImageSampleDrefExplicitLod;
             append_result_type_and_id_to_spirv_params();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -3046,19 +3044,19 @@
 
     // TODO(crbug.com/tint/661): Combine sequential barriers to a single
     // instruction.
-    if (builtin->Type() == sem::BuiltinType::kWorkgroupBarrier) {
+    if (builtin->Type() == builtin::Function::kWorkgroupBarrier) {
         execution = static_cast<uint32_t>(spv::Scope::Workgroup);
         memory = static_cast<uint32_t>(spv::Scope::Workgroup);
         semantics = static_cast<uint32_t>(spv::MemorySemanticsMask::AcquireRelease) |
                     static_cast<uint32_t>(spv::MemorySemanticsMask::WorkgroupMemory);
-    } else if (builtin->Type() == sem::BuiltinType::kStorageBarrier) {
+    } else if (builtin->Type() == builtin::Function::kStorageBarrier) {
         execution = static_cast<uint32_t>(spv::Scope::Workgroup);
         memory = static_cast<uint32_t>(spv::Scope::Workgroup);
         semantics = static_cast<uint32_t>(spv::MemorySemanticsMask::AcquireRelease) |
                     static_cast<uint32_t>(spv::MemorySemanticsMask::UniformMemory);
     } else {
         error_ = "unexpected barrier builtin type ";
-        error_ += sem::str(builtin->Type());
+        error_ += builtin::str(builtin->Type());
         return false;
     }
 
@@ -3128,7 +3126,7 @@
     Operand semantics = Operand(semantics_id);
 
     switch (builtin->Type()) {
-        case sem::BuiltinType::kAtomicLoad:
+        case builtin::Function::kAtomicLoad:
             return push_function_inst(spv::Op::OpAtomicLoad, {
                                                                  result_type,
                                                                  result_id,
@@ -3136,14 +3134,14 @@
                                                                  memory,
                                                                  semantics,
                                                              });
-        case sem::BuiltinType::kAtomicStore:
+        case builtin::Function::kAtomicStore:
             return push_function_inst(spv::Op::OpAtomicStore, {
                                                                   pointer,
                                                                   memory,
                                                                   semantics,
                                                                   value,
                                                               });
-        case sem::BuiltinType::kAtomicAdd:
+        case builtin::Function::kAtomicAdd:
             return push_function_inst(spv::Op::OpAtomicIAdd, {
                                                                  result_type,
                                                                  result_id,
@@ -3152,7 +3150,7 @@
                                                                  semantics,
                                                                  value,
                                                              });
-        case sem::BuiltinType::kAtomicSub:
+        case builtin::Function::kAtomicSub:
             return push_function_inst(spv::Op::OpAtomicISub, {
                                                                  result_type,
                                                                  result_id,
@@ -3161,7 +3159,7 @@
                                                                  semantics,
                                                                  value,
                                                              });
-        case sem::BuiltinType::kAtomicMax:
+        case builtin::Function::kAtomicMax:
             return push_function_inst(
                 is_value_signed() ? spv::Op::OpAtomicSMax : spv::Op::OpAtomicUMax, {
                                                                                        result_type,
@@ -3171,7 +3169,7 @@
                                                                                        semantics,
                                                                                        value,
                                                                                    });
-        case sem::BuiltinType::kAtomicMin:
+        case builtin::Function::kAtomicMin:
             return push_function_inst(
                 is_value_signed() ? spv::Op::OpAtomicSMin : spv::Op::OpAtomicUMin, {
                                                                                        result_type,
@@ -3181,7 +3179,7 @@
                                                                                        semantics,
                                                                                        value,
                                                                                    });
-        case sem::BuiltinType::kAtomicAnd:
+        case builtin::Function::kAtomicAnd:
             return push_function_inst(spv::Op::OpAtomicAnd, {
                                                                 result_type,
                                                                 result_id,
@@ -3190,7 +3188,7 @@
                                                                 semantics,
                                                                 value,
                                                             });
-        case sem::BuiltinType::kAtomicOr:
+        case builtin::Function::kAtomicOr:
             return push_function_inst(spv::Op::OpAtomicOr, {
                                                                result_type,
                                                                result_id,
@@ -3199,7 +3197,7 @@
                                                                semantics,
                                                                value,
                                                            });
-        case sem::BuiltinType::kAtomicXor:
+        case builtin::Function::kAtomicXor:
             return push_function_inst(spv::Op::OpAtomicXor, {
                                                                 result_type,
                                                                 result_id,
@@ -3208,7 +3206,7 @@
                                                                 semantics,
                                                                 value,
                                                             });
-        case sem::BuiltinType::kAtomicExchange:
+        case builtin::Function::kAtomicExchange:
             return push_function_inst(spv::Op::OpAtomicExchange, {
                                                                      result_type,
                                                                      result_id,
@@ -3217,7 +3215,7 @@
                                                                      semantics,
                                                                      value,
                                                                  });
-        case sem::BuiltinType::kAtomicCompareExchangeWeak: {
+        case builtin::Function::kAtomicCompareExchangeWeak: {
             auto comparator = GenerateExpression(call->Arguments()[1]);
             if (comparator == 0) {
                 return false;