[tint] Rename core::Function to BuiltinFn

Also do a pass of the codebase to use BuiltinFn consistently.
There's poor naming between builtin-functions, builtin-types, and
builtin-values.

Change-Id: I9100d2e35d485f3b398c2ae3b852b63d0705c40e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/152542
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/lang/core/BUILD.bazel b/src/tint/lang/core/BUILD.bazel
index 8f69c1d..76b7de4 100644
--- a/src/tint/lang/core/BUILD.bazel
+++ b/src/tint/lang/core/BUILD.bazel
@@ -31,8 +31,8 @@
     "attribute.cc",
     "binary_op.cc",
     "builtin.cc",
+    "builtin_fn.cc",
     "builtin_value.cc",
-    "function.cc",
     "interpolation_sampling.cc",
     "interpolation_type.cc",
     "number.cc",
@@ -46,10 +46,10 @@
     "attribute.h",
     "binary_op.h",
     "builtin.h",
+    "builtin_fn.h",
     "builtin_value.h",
     "evaluation_stage.h",
     "fluent_types.h",
-    "function.h",
     "interpolation.h",
     "interpolation_sampling.h",
     "interpolation_type.h",
diff --git a/src/tint/lang/core/BUILD.cmake b/src/tint/lang/core/BUILD.cmake
index 5e02dac..9ce2fe3 100644
--- a/src/tint/lang/core/BUILD.cmake
+++ b/src/tint/lang/core/BUILD.cmake
@@ -41,12 +41,12 @@
   lang/core/binary_op.h
   lang/core/builtin.cc
   lang/core/builtin.h
+  lang/core/builtin_fn.cc
+  lang/core/builtin_fn.h
   lang/core/builtin_value.cc
   lang/core/builtin_value.h
   lang/core/evaluation_stage.h
   lang/core/fluent_types.h
-  lang/core/function.cc
-  lang/core/function.h
   lang/core/interpolation.h
   lang/core/interpolation_sampling.cc
   lang/core/interpolation_sampling.h
diff --git a/src/tint/lang/core/BUILD.gn b/src/tint/lang/core/BUILD.gn
index c096493..8922c2a 100644
--- a/src/tint/lang/core/BUILD.gn
+++ b/src/tint/lang/core/BUILD.gn
@@ -41,12 +41,12 @@
     "binary_op.h",
     "builtin.cc",
     "builtin.h",
+    "builtin_fn.cc",
+    "builtin_fn.h",
     "builtin_value.cc",
     "builtin_value.h",
     "evaluation_stage.h",
     "fluent_types.h",
-    "function.cc",
-    "function.h",
     "interpolation.h",
     "interpolation_sampling.cc",
     "interpolation_sampling.h",
diff --git a/src/tint/lang/core/builtin_fn.cc b/src/tint/lang/core/builtin_fn.cc
new file mode 100644
index 0000000..c74963f
--- /dev/null
+++ b/src/tint/lang/core/builtin_fn.cc
@@ -0,0 +1,713 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by 'tools/src/cmd/gen' using the template:
+//   src/tint/lang/core/builtin_fn.cc.tmpl
+//
+// To regenerate run: './tools/run gen'
+//
+//                       Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/lang/core/builtin_fn.h"
+
+namespace tint::core {
+
+BuiltinFn ParseBuiltinFn(std::string_view name) {
+    if (name == "abs") {
+        return BuiltinFn::kAbs;
+    }
+    if (name == "acos") {
+        return BuiltinFn::kAcos;
+    }
+    if (name == "acosh") {
+        return BuiltinFn::kAcosh;
+    }
+    if (name == "all") {
+        return BuiltinFn::kAll;
+    }
+    if (name == "any") {
+        return BuiltinFn::kAny;
+    }
+    if (name == "arrayLength") {
+        return BuiltinFn::kArrayLength;
+    }
+    if (name == "asin") {
+        return BuiltinFn::kAsin;
+    }
+    if (name == "asinh") {
+        return BuiltinFn::kAsinh;
+    }
+    if (name == "atan") {
+        return BuiltinFn::kAtan;
+    }
+    if (name == "atan2") {
+        return BuiltinFn::kAtan2;
+    }
+    if (name == "atanh") {
+        return BuiltinFn::kAtanh;
+    }
+    if (name == "ceil") {
+        return BuiltinFn::kCeil;
+    }
+    if (name == "clamp") {
+        return BuiltinFn::kClamp;
+    }
+    if (name == "cos") {
+        return BuiltinFn::kCos;
+    }
+    if (name == "cosh") {
+        return BuiltinFn::kCosh;
+    }
+    if (name == "countLeadingZeros") {
+        return BuiltinFn::kCountLeadingZeros;
+    }
+    if (name == "countOneBits") {
+        return BuiltinFn::kCountOneBits;
+    }
+    if (name == "countTrailingZeros") {
+        return BuiltinFn::kCountTrailingZeros;
+    }
+    if (name == "cross") {
+        return BuiltinFn::kCross;
+    }
+    if (name == "degrees") {
+        return BuiltinFn::kDegrees;
+    }
+    if (name == "determinant") {
+        return BuiltinFn::kDeterminant;
+    }
+    if (name == "distance") {
+        return BuiltinFn::kDistance;
+    }
+    if (name == "dot") {
+        return BuiltinFn::kDot;
+    }
+    if (name == "dot4I8Packed") {
+        return BuiltinFn::kDot4I8Packed;
+    }
+    if (name == "dot4U8Packed") {
+        return BuiltinFn::kDot4U8Packed;
+    }
+    if (name == "dpdx") {
+        return BuiltinFn::kDpdx;
+    }
+    if (name == "dpdxCoarse") {
+        return BuiltinFn::kDpdxCoarse;
+    }
+    if (name == "dpdxFine") {
+        return BuiltinFn::kDpdxFine;
+    }
+    if (name == "dpdy") {
+        return BuiltinFn::kDpdy;
+    }
+    if (name == "dpdyCoarse") {
+        return BuiltinFn::kDpdyCoarse;
+    }
+    if (name == "dpdyFine") {
+        return BuiltinFn::kDpdyFine;
+    }
+    if (name == "exp") {
+        return BuiltinFn::kExp;
+    }
+    if (name == "exp2") {
+        return BuiltinFn::kExp2;
+    }
+    if (name == "extractBits") {
+        return BuiltinFn::kExtractBits;
+    }
+    if (name == "faceForward") {
+        return BuiltinFn::kFaceForward;
+    }
+    if (name == "firstLeadingBit") {
+        return BuiltinFn::kFirstLeadingBit;
+    }
+    if (name == "firstTrailingBit") {
+        return BuiltinFn::kFirstTrailingBit;
+    }
+    if (name == "floor") {
+        return BuiltinFn::kFloor;
+    }
+    if (name == "fma") {
+        return BuiltinFn::kFma;
+    }
+    if (name == "fract") {
+        return BuiltinFn::kFract;
+    }
+    if (name == "frexp") {
+        return BuiltinFn::kFrexp;
+    }
+    if (name == "fwidth") {
+        return BuiltinFn::kFwidth;
+    }
+    if (name == "fwidthCoarse") {
+        return BuiltinFn::kFwidthCoarse;
+    }
+    if (name == "fwidthFine") {
+        return BuiltinFn::kFwidthFine;
+    }
+    if (name == "insertBits") {
+        return BuiltinFn::kInsertBits;
+    }
+    if (name == "inverseSqrt") {
+        return BuiltinFn::kInverseSqrt;
+    }
+    if (name == "ldexp") {
+        return BuiltinFn::kLdexp;
+    }
+    if (name == "length") {
+        return BuiltinFn::kLength;
+    }
+    if (name == "log") {
+        return BuiltinFn::kLog;
+    }
+    if (name == "log2") {
+        return BuiltinFn::kLog2;
+    }
+    if (name == "max") {
+        return BuiltinFn::kMax;
+    }
+    if (name == "min") {
+        return BuiltinFn::kMin;
+    }
+    if (name == "mix") {
+        return BuiltinFn::kMix;
+    }
+    if (name == "modf") {
+        return BuiltinFn::kModf;
+    }
+    if (name == "normalize") {
+        return BuiltinFn::kNormalize;
+    }
+    if (name == "pack2x16float") {
+        return BuiltinFn::kPack2X16Float;
+    }
+    if (name == "pack2x16snorm") {
+        return BuiltinFn::kPack2X16Snorm;
+    }
+    if (name == "pack2x16unorm") {
+        return BuiltinFn::kPack2X16Unorm;
+    }
+    if (name == "pack4x8snorm") {
+        return BuiltinFn::kPack4X8Snorm;
+    }
+    if (name == "pack4x8unorm") {
+        return BuiltinFn::kPack4X8Unorm;
+    }
+    if (name == "pow") {
+        return BuiltinFn::kPow;
+    }
+    if (name == "quantizeToF16") {
+        return BuiltinFn::kQuantizeToF16;
+    }
+    if (name == "radians") {
+        return BuiltinFn::kRadians;
+    }
+    if (name == "reflect") {
+        return BuiltinFn::kReflect;
+    }
+    if (name == "refract") {
+        return BuiltinFn::kRefract;
+    }
+    if (name == "reverseBits") {
+        return BuiltinFn::kReverseBits;
+    }
+    if (name == "round") {
+        return BuiltinFn::kRound;
+    }
+    if (name == "saturate") {
+        return BuiltinFn::kSaturate;
+    }
+    if (name == "select") {
+        return BuiltinFn::kSelect;
+    }
+    if (name == "sign") {
+        return BuiltinFn::kSign;
+    }
+    if (name == "sin") {
+        return BuiltinFn::kSin;
+    }
+    if (name == "sinh") {
+        return BuiltinFn::kSinh;
+    }
+    if (name == "smoothstep") {
+        return BuiltinFn::kSmoothstep;
+    }
+    if (name == "sqrt") {
+        return BuiltinFn::kSqrt;
+    }
+    if (name == "step") {
+        return BuiltinFn::kStep;
+    }
+    if (name == "storageBarrier") {
+        return BuiltinFn::kStorageBarrier;
+    }
+    if (name == "tan") {
+        return BuiltinFn::kTan;
+    }
+    if (name == "tanh") {
+        return BuiltinFn::kTanh;
+    }
+    if (name == "transpose") {
+        return BuiltinFn::kTranspose;
+    }
+    if (name == "trunc") {
+        return BuiltinFn::kTrunc;
+    }
+    if (name == "unpack2x16float") {
+        return BuiltinFn::kUnpack2X16Float;
+    }
+    if (name == "unpack2x16snorm") {
+        return BuiltinFn::kUnpack2X16Snorm;
+    }
+    if (name == "unpack2x16unorm") {
+        return BuiltinFn::kUnpack2X16Unorm;
+    }
+    if (name == "unpack4x8snorm") {
+        return BuiltinFn::kUnpack4X8Snorm;
+    }
+    if (name == "unpack4x8unorm") {
+        return BuiltinFn::kUnpack4X8Unorm;
+    }
+    if (name == "workgroupBarrier") {
+        return BuiltinFn::kWorkgroupBarrier;
+    }
+    if (name == "workgroupUniformLoad") {
+        return BuiltinFn::kWorkgroupUniformLoad;
+    }
+    if (name == "textureBarrier") {
+        return BuiltinFn::kTextureBarrier;
+    }
+    if (name == "textureDimensions") {
+        return BuiltinFn::kTextureDimensions;
+    }
+    if (name == "textureGather") {
+        return BuiltinFn::kTextureGather;
+    }
+    if (name == "textureGatherCompare") {
+        return BuiltinFn::kTextureGatherCompare;
+    }
+    if (name == "textureNumLayers") {
+        return BuiltinFn::kTextureNumLayers;
+    }
+    if (name == "textureNumLevels") {
+        return BuiltinFn::kTextureNumLevels;
+    }
+    if (name == "textureNumSamples") {
+        return BuiltinFn::kTextureNumSamples;
+    }
+    if (name == "textureSample") {
+        return BuiltinFn::kTextureSample;
+    }
+    if (name == "textureSampleBias") {
+        return BuiltinFn::kTextureSampleBias;
+    }
+    if (name == "textureSampleCompare") {
+        return BuiltinFn::kTextureSampleCompare;
+    }
+    if (name == "textureSampleCompareLevel") {
+        return BuiltinFn::kTextureSampleCompareLevel;
+    }
+    if (name == "textureSampleGrad") {
+        return BuiltinFn::kTextureSampleGrad;
+    }
+    if (name == "textureSampleLevel") {
+        return BuiltinFn::kTextureSampleLevel;
+    }
+    if (name == "textureSampleBaseClampToEdge") {
+        return BuiltinFn::kTextureSampleBaseClampToEdge;
+    }
+    if (name == "textureStore") {
+        return BuiltinFn::kTextureStore;
+    }
+    if (name == "textureLoad") {
+        return BuiltinFn::kTextureLoad;
+    }
+    if (name == "atomicLoad") {
+        return BuiltinFn::kAtomicLoad;
+    }
+    if (name == "atomicStore") {
+        return BuiltinFn::kAtomicStore;
+    }
+    if (name == "atomicAdd") {
+        return BuiltinFn::kAtomicAdd;
+    }
+    if (name == "atomicSub") {
+        return BuiltinFn::kAtomicSub;
+    }
+    if (name == "atomicMax") {
+        return BuiltinFn::kAtomicMax;
+    }
+    if (name == "atomicMin") {
+        return BuiltinFn::kAtomicMin;
+    }
+    if (name == "atomicAnd") {
+        return BuiltinFn::kAtomicAnd;
+    }
+    if (name == "atomicOr") {
+        return BuiltinFn::kAtomicOr;
+    }
+    if (name == "atomicXor") {
+        return BuiltinFn::kAtomicXor;
+    }
+    if (name == "atomicExchange") {
+        return BuiltinFn::kAtomicExchange;
+    }
+    if (name == "atomicCompareExchangeWeak") {
+        return BuiltinFn::kAtomicCompareExchangeWeak;
+    }
+    if (name == "subgroupBallot") {
+        return BuiltinFn::kSubgroupBallot;
+    }
+    if (name == "subgroupBroadcast") {
+        return BuiltinFn::kSubgroupBroadcast;
+    }
+    if (name == "_tint_materialize") {
+        return BuiltinFn::kTintMaterialize;
+    }
+    return BuiltinFn::kNone;
+}
+
+const char* str(BuiltinFn i) {
+    switch (i) {
+        case BuiltinFn::kNone:
+            return "<none>";
+        case BuiltinFn::kAbs:
+            return "abs";
+        case BuiltinFn::kAcos:
+            return "acos";
+        case BuiltinFn::kAcosh:
+            return "acosh";
+        case BuiltinFn::kAll:
+            return "all";
+        case BuiltinFn::kAny:
+            return "any";
+        case BuiltinFn::kArrayLength:
+            return "arrayLength";
+        case BuiltinFn::kAsin:
+            return "asin";
+        case BuiltinFn::kAsinh:
+            return "asinh";
+        case BuiltinFn::kAtan:
+            return "atan";
+        case BuiltinFn::kAtan2:
+            return "atan2";
+        case BuiltinFn::kAtanh:
+            return "atanh";
+        case BuiltinFn::kCeil:
+            return "ceil";
+        case BuiltinFn::kClamp:
+            return "clamp";
+        case BuiltinFn::kCos:
+            return "cos";
+        case BuiltinFn::kCosh:
+            return "cosh";
+        case BuiltinFn::kCountLeadingZeros:
+            return "countLeadingZeros";
+        case BuiltinFn::kCountOneBits:
+            return "countOneBits";
+        case BuiltinFn::kCountTrailingZeros:
+            return "countTrailingZeros";
+        case BuiltinFn::kCross:
+            return "cross";
+        case BuiltinFn::kDegrees:
+            return "degrees";
+        case BuiltinFn::kDeterminant:
+            return "determinant";
+        case BuiltinFn::kDistance:
+            return "distance";
+        case BuiltinFn::kDot:
+            return "dot";
+        case BuiltinFn::kDot4I8Packed:
+            return "dot4I8Packed";
+        case BuiltinFn::kDot4U8Packed:
+            return "dot4U8Packed";
+        case BuiltinFn::kDpdx:
+            return "dpdx";
+        case BuiltinFn::kDpdxCoarse:
+            return "dpdxCoarse";
+        case BuiltinFn::kDpdxFine:
+            return "dpdxFine";
+        case BuiltinFn::kDpdy:
+            return "dpdy";
+        case BuiltinFn::kDpdyCoarse:
+            return "dpdyCoarse";
+        case BuiltinFn::kDpdyFine:
+            return "dpdyFine";
+        case BuiltinFn::kExp:
+            return "exp";
+        case BuiltinFn::kExp2:
+            return "exp2";
+        case BuiltinFn::kExtractBits:
+            return "extractBits";
+        case BuiltinFn::kFaceForward:
+            return "faceForward";
+        case BuiltinFn::kFirstLeadingBit:
+            return "firstLeadingBit";
+        case BuiltinFn::kFirstTrailingBit:
+            return "firstTrailingBit";
+        case BuiltinFn::kFloor:
+            return "floor";
+        case BuiltinFn::kFma:
+            return "fma";
+        case BuiltinFn::kFract:
+            return "fract";
+        case BuiltinFn::kFrexp:
+            return "frexp";
+        case BuiltinFn::kFwidth:
+            return "fwidth";
+        case BuiltinFn::kFwidthCoarse:
+            return "fwidthCoarse";
+        case BuiltinFn::kFwidthFine:
+            return "fwidthFine";
+        case BuiltinFn::kInsertBits:
+            return "insertBits";
+        case BuiltinFn::kInverseSqrt:
+            return "inverseSqrt";
+        case BuiltinFn::kLdexp:
+            return "ldexp";
+        case BuiltinFn::kLength:
+            return "length";
+        case BuiltinFn::kLog:
+            return "log";
+        case BuiltinFn::kLog2:
+            return "log2";
+        case BuiltinFn::kMax:
+            return "max";
+        case BuiltinFn::kMin:
+            return "min";
+        case BuiltinFn::kMix:
+            return "mix";
+        case BuiltinFn::kModf:
+            return "modf";
+        case BuiltinFn::kNormalize:
+            return "normalize";
+        case BuiltinFn::kPack2X16Float:
+            return "pack2x16float";
+        case BuiltinFn::kPack2X16Snorm:
+            return "pack2x16snorm";
+        case BuiltinFn::kPack2X16Unorm:
+            return "pack2x16unorm";
+        case BuiltinFn::kPack4X8Snorm:
+            return "pack4x8snorm";
+        case BuiltinFn::kPack4X8Unorm:
+            return "pack4x8unorm";
+        case BuiltinFn::kPow:
+            return "pow";
+        case BuiltinFn::kQuantizeToF16:
+            return "quantizeToF16";
+        case BuiltinFn::kRadians:
+            return "radians";
+        case BuiltinFn::kReflect:
+            return "reflect";
+        case BuiltinFn::kRefract:
+            return "refract";
+        case BuiltinFn::kReverseBits:
+            return "reverseBits";
+        case BuiltinFn::kRound:
+            return "round";
+        case BuiltinFn::kSaturate:
+            return "saturate";
+        case BuiltinFn::kSelect:
+            return "select";
+        case BuiltinFn::kSign:
+            return "sign";
+        case BuiltinFn::kSin:
+            return "sin";
+        case BuiltinFn::kSinh:
+            return "sinh";
+        case BuiltinFn::kSmoothstep:
+            return "smoothstep";
+        case BuiltinFn::kSqrt:
+            return "sqrt";
+        case BuiltinFn::kStep:
+            return "step";
+        case BuiltinFn::kStorageBarrier:
+            return "storageBarrier";
+        case BuiltinFn::kTan:
+            return "tan";
+        case BuiltinFn::kTanh:
+            return "tanh";
+        case BuiltinFn::kTranspose:
+            return "transpose";
+        case BuiltinFn::kTrunc:
+            return "trunc";
+        case BuiltinFn::kUnpack2X16Float:
+            return "unpack2x16float";
+        case BuiltinFn::kUnpack2X16Snorm:
+            return "unpack2x16snorm";
+        case BuiltinFn::kUnpack2X16Unorm:
+            return "unpack2x16unorm";
+        case BuiltinFn::kUnpack4X8Snorm:
+            return "unpack4x8snorm";
+        case BuiltinFn::kUnpack4X8Unorm:
+            return "unpack4x8unorm";
+        case BuiltinFn::kWorkgroupBarrier:
+            return "workgroupBarrier";
+        case BuiltinFn::kWorkgroupUniformLoad:
+            return "workgroupUniformLoad";
+        case BuiltinFn::kTextureBarrier:
+            return "textureBarrier";
+        case BuiltinFn::kTextureDimensions:
+            return "textureDimensions";
+        case BuiltinFn::kTextureGather:
+            return "textureGather";
+        case BuiltinFn::kTextureGatherCompare:
+            return "textureGatherCompare";
+        case BuiltinFn::kTextureNumLayers:
+            return "textureNumLayers";
+        case BuiltinFn::kTextureNumLevels:
+            return "textureNumLevels";
+        case BuiltinFn::kTextureNumSamples:
+            return "textureNumSamples";
+        case BuiltinFn::kTextureSample:
+            return "textureSample";
+        case BuiltinFn::kTextureSampleBias:
+            return "textureSampleBias";
+        case BuiltinFn::kTextureSampleCompare:
+            return "textureSampleCompare";
+        case BuiltinFn::kTextureSampleCompareLevel:
+            return "textureSampleCompareLevel";
+        case BuiltinFn::kTextureSampleGrad:
+            return "textureSampleGrad";
+        case BuiltinFn::kTextureSampleLevel:
+            return "textureSampleLevel";
+        case BuiltinFn::kTextureSampleBaseClampToEdge:
+            return "textureSampleBaseClampToEdge";
+        case BuiltinFn::kTextureStore:
+            return "textureStore";
+        case BuiltinFn::kTextureLoad:
+            return "textureLoad";
+        case BuiltinFn::kAtomicLoad:
+            return "atomicLoad";
+        case BuiltinFn::kAtomicStore:
+            return "atomicStore";
+        case BuiltinFn::kAtomicAdd:
+            return "atomicAdd";
+        case BuiltinFn::kAtomicSub:
+            return "atomicSub";
+        case BuiltinFn::kAtomicMax:
+            return "atomicMax";
+        case BuiltinFn::kAtomicMin:
+            return "atomicMin";
+        case BuiltinFn::kAtomicAnd:
+            return "atomicAnd";
+        case BuiltinFn::kAtomicOr:
+            return "atomicOr";
+        case BuiltinFn::kAtomicXor:
+            return "atomicXor";
+        case BuiltinFn::kAtomicExchange:
+            return "atomicExchange";
+        case BuiltinFn::kAtomicCompareExchangeWeak:
+            return "atomicCompareExchangeWeak";
+        case BuiltinFn::kSubgroupBallot:
+            return "subgroupBallot";
+        case BuiltinFn::kSubgroupBroadcast:
+            return "subgroupBroadcast";
+        case BuiltinFn::kTintMaterialize:
+            return "_tint_materialize";
+    }
+    return "<unknown>";
+}
+
+bool IsCoarseDerivative(BuiltinFn f) {
+    return f == BuiltinFn::kDpdxCoarse || f == BuiltinFn::kDpdyCoarse ||
+           f == BuiltinFn::kFwidthCoarse;
+}
+
+bool IsFineDerivative(BuiltinFn f) {
+    return f == BuiltinFn::kDpdxFine || f == BuiltinFn::kDpdyFine || f == BuiltinFn::kFwidthFine;
+}
+
+bool IsDerivative(BuiltinFn f) {
+    return f == BuiltinFn::kDpdx || f == BuiltinFn::kDpdy || f == BuiltinFn::kFwidth ||
+           IsCoarseDerivative(f) || IsFineDerivative(f);
+}
+
+bool IsTexture(BuiltinFn f) {
+    return IsImageQuery(f) ||                                //
+           f == BuiltinFn::kTextureGather ||                 //
+           f == BuiltinFn::kTextureGatherCompare ||          //
+           f == BuiltinFn::kTextureLoad ||                   //
+           f == BuiltinFn::kTextureSample ||                 //
+           f == BuiltinFn::kTextureSampleBaseClampToEdge ||  //
+           f == BuiltinFn::kTextureSampleBias ||             //
+           f == BuiltinFn::kTextureSampleCompare ||          //
+           f == BuiltinFn::kTextureSampleCompareLevel ||     //
+           f == BuiltinFn::kTextureSampleGrad ||             //
+           f == BuiltinFn::kTextureSampleLevel ||            //
+           f == BuiltinFn::kTextureStore;
+}
+
+bool IsImageQuery(BuiltinFn f) {
+    return f == BuiltinFn::kTextureDimensions || f == BuiltinFn::kTextureNumLayers ||
+           f == BuiltinFn::kTextureNumLevels || f == BuiltinFn::kTextureNumSamples;
+}
+
+bool IsDataPacking(BuiltinFn f) {
+    return f == BuiltinFn::kPack4X8Snorm || f == BuiltinFn::kPack4X8Unorm ||
+           f == BuiltinFn::kPack2X16Snorm || f == BuiltinFn::kPack2X16Unorm ||
+           f == BuiltinFn::kPack2X16Float;
+}
+
+bool IsDataUnpacking(BuiltinFn f) {
+    return f == BuiltinFn::kUnpack4X8Snorm || f == BuiltinFn::kUnpack4X8Unorm ||
+           f == BuiltinFn::kUnpack2X16Snorm || f == BuiltinFn::kUnpack2X16Unorm ||
+           f == BuiltinFn::kUnpack2X16Float;
+}
+
+bool IsBarrier(BuiltinFn f) {
+    return f == BuiltinFn::kWorkgroupBarrier || f == BuiltinFn::kStorageBarrier ||
+           f == BuiltinFn::kTextureBarrier;
+}
+
+bool IsAtomic(BuiltinFn f) {
+    return f == BuiltinFn::kAtomicLoad || f == BuiltinFn::kAtomicStore ||
+           f == BuiltinFn::kAtomicAdd || f == BuiltinFn::kAtomicSub || f == BuiltinFn::kAtomicMax ||
+           f == BuiltinFn::kAtomicMin || f == BuiltinFn::kAtomicAnd || f == BuiltinFn::kAtomicOr ||
+           f == BuiltinFn::kAtomicXor || f == BuiltinFn::kAtomicExchange ||
+           f == BuiltinFn::kAtomicCompareExchangeWeak;
+}
+
+bool IsDP4a(BuiltinFn f) {
+    return f == BuiltinFn::kDot4I8Packed || f == BuiltinFn::kDot4U8Packed;
+}
+
+bool IsSubgroup(BuiltinFn f) {
+    return f == BuiltinFn::kSubgroupBallot || f == BuiltinFn::kSubgroupBroadcast;
+}
+
+bool HasSideEffects(BuiltinFn f) {
+    switch (f) {
+        case BuiltinFn::kAtomicAdd:
+        case BuiltinFn::kAtomicAnd:
+        case BuiltinFn::kAtomicCompareExchangeWeak:
+        case BuiltinFn::kAtomicExchange:
+        case BuiltinFn::kAtomicMax:
+        case BuiltinFn::kAtomicMin:
+        case BuiltinFn::kAtomicOr:
+        case BuiltinFn::kAtomicStore:
+        case BuiltinFn::kAtomicSub:
+        case BuiltinFn::kAtomicXor:
+        case BuiltinFn::kTextureStore:
+        case BuiltinFn::kWorkgroupUniformLoad:
+            return true;
+        default:
+            break;
+    }
+    return false;
+}
+
+}  // namespace tint::core
diff --git a/src/tint/lang/core/builtin_fn.cc.tmpl b/src/tint/lang/core/builtin_fn.cc.tmpl
new file mode 100644
index 0000000..5a0d100
--- /dev/null
+++ b/src/tint/lang/core/builtin_fn.cc.tmpl
@@ -0,0 +1,132 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate builtin_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
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- $I := LoadIntrinsics "src/tint/lang/core/core.def" -}}
+#include "src/tint/lang/core/builtin_fn.h"
+
+namespace tint::core {
+
+BuiltinFn ParseBuiltinFn(std::string_view name) {
+{{- range $I.Sem.Builtins  }}
+    if (name == "{{.Name}}") {
+        return BuiltinFn::k{{PascalCase .Name}};
+    }
+{{- end  }}
+    return BuiltinFn::kNone;
+}
+
+const char* str(BuiltinFn i) {
+    switch (i) {
+        case BuiltinFn::kNone:
+            return "<none>";
+{{- range $I.Sem.Builtins  }}
+        case BuiltinFn::k{{PascalCase .Name}}:
+            return "{{.Name}}";
+{{- end  }}
+    }
+    return "<unknown>";
+}
+
+bool IsCoarseDerivative(BuiltinFn f) {
+    return f == BuiltinFn::kDpdxCoarse || f == BuiltinFn::kDpdyCoarse ||
+           f == BuiltinFn::kFwidthCoarse;
+}
+
+bool IsFineDerivative(BuiltinFn f) {
+    return f == BuiltinFn::kDpdxFine || f == BuiltinFn::kDpdyFine ||
+           f == BuiltinFn::kFwidthFine;
+}
+
+bool IsDerivative(BuiltinFn f) {
+    return f == BuiltinFn::kDpdx || f == BuiltinFn::kDpdy ||
+           f == BuiltinFn::kFwidth || IsCoarseDerivative(f) ||
+           IsFineDerivative(f);
+}
+
+bool IsTexture(BuiltinFn f) {
+    return IsImageQuery(f) ||                                //
+           f == BuiltinFn::kTextureGather ||                 //
+           f == BuiltinFn::kTextureGatherCompare ||          //
+           f == BuiltinFn::kTextureLoad ||                   //
+           f == BuiltinFn::kTextureSample ||                 //
+           f == BuiltinFn::kTextureSampleBaseClampToEdge ||  //
+           f == BuiltinFn::kTextureSampleBias ||             //
+           f == BuiltinFn::kTextureSampleCompare ||          //
+           f == BuiltinFn::kTextureSampleCompareLevel ||     //
+           f == BuiltinFn::kTextureSampleGrad ||             //
+           f == BuiltinFn::kTextureSampleLevel ||            //
+           f == BuiltinFn::kTextureStore;
+}
+
+bool IsImageQuery(BuiltinFn f) {
+    return f == BuiltinFn::kTextureDimensions ||
+           f == BuiltinFn::kTextureNumLayers || f == BuiltinFn::kTextureNumLevels ||
+           f == BuiltinFn::kTextureNumSamples;
+}
+
+bool IsDataPacking(BuiltinFn f) {
+    return f == BuiltinFn::kPack4X8Snorm || f == BuiltinFn::kPack4X8Unorm ||
+           f == BuiltinFn::kPack2X16Snorm || f == BuiltinFn::kPack2X16Unorm ||
+           f == BuiltinFn::kPack2X16Float;
+}
+
+bool IsDataUnpacking(BuiltinFn f) {
+    return f == BuiltinFn::kUnpack4X8Snorm || f == BuiltinFn::kUnpack4X8Unorm ||
+           f == BuiltinFn::kUnpack2X16Snorm || f == BuiltinFn::kUnpack2X16Unorm ||
+           f == BuiltinFn::kUnpack2X16Float;
+}
+
+bool IsBarrier(BuiltinFn f) {
+    return f == BuiltinFn::kWorkgroupBarrier || f == BuiltinFn::kStorageBarrier ||
+           f == BuiltinFn::kTextureBarrier;
+}
+
+bool IsAtomic(BuiltinFn f) {
+    return f == BuiltinFn::kAtomicLoad || f == BuiltinFn::kAtomicStore ||
+           f == BuiltinFn::kAtomicAdd || f == BuiltinFn::kAtomicSub ||
+           f == BuiltinFn::kAtomicMax || f == BuiltinFn::kAtomicMin ||
+           f == BuiltinFn::kAtomicAnd || f == BuiltinFn::kAtomicOr ||
+           f == BuiltinFn::kAtomicXor || f == BuiltinFn::kAtomicExchange ||
+           f == BuiltinFn::kAtomicCompareExchangeWeak;
+}
+
+bool IsDP4a(BuiltinFn f) {
+    return f == BuiltinFn::kDot4I8Packed || f == BuiltinFn::kDot4U8Packed;
+}
+
+bool IsSubgroup(BuiltinFn f) {
+    return f == BuiltinFn::kSubgroupBallot || f == BuiltinFn::kSubgroupBroadcast;
+}
+
+bool HasSideEffects(BuiltinFn f) {
+    switch (f) {
+        case BuiltinFn::kAtomicAdd:
+        case BuiltinFn::kAtomicAnd:
+        case BuiltinFn::kAtomicCompareExchangeWeak:
+        case BuiltinFn::kAtomicExchange:
+        case BuiltinFn::kAtomicMax:
+        case BuiltinFn::kAtomicMin:
+        case BuiltinFn::kAtomicOr:
+        case BuiltinFn::kAtomicStore:
+        case BuiltinFn::kAtomicSub:
+        case BuiltinFn::kAtomicXor:
+        case BuiltinFn::kTextureStore:
+        case BuiltinFn::kWorkgroupUniformLoad:
+            return true;
+        default:
+            break;
+    }
+    return false;
+}
+
+}  // namespace tint::core
diff --git a/src/tint/lang/core/function.h b/src/tint/lang/core/builtin_fn.h
similarity index 64%
rename from src/tint/lang/core/function.h
rename to src/tint/lang/core/builtin_fn.h
index e9b52fa..5e58b5e 100644
--- a/src/tint/lang/core/function.h
+++ b/src/tint/lang/core/builtin_fn.h
@@ -14,15 +14,15 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by 'tools/src/cmd/gen' using the template:
-//   src/tint/lang/core/function.h.tmpl
+//   src/tint/lang/core/builtin_fn.h.tmpl
 //
 // To regenerate run: './tools/run gen'
 //
 //                       Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#ifndef SRC_TINT_LANG_CORE_FUNCTION_H_
-#define SRC_TINT_LANG_CORE_FUNCTION_H_
+#ifndef SRC_TINT_LANG_CORE_BUILTIN_FN_H_
+#define SRC_TINT_LANG_CORE_BUILTIN_FN_H_
 
 #include <cstdint>
 #include <string>
@@ -33,7 +33,7 @@
 namespace tint::core {
 
 /// Enumerator of all builtin functions
-enum class Function : uint8_t {
+enum class BuiltinFn : uint8_t {
     kAbs,
     kAcos,
     kAcosh,
@@ -154,146 +154,146 @@
     kNone,
 };
 
-/// Matches the Function by name
+/// Matches the BuiltinFn by name
 /// @param name the builtin name to parse
-/// @returns the parsed Function, or Function::kNone if `name` did not
+/// @returns the parsed BuiltinFn, or BuiltinFn::kNone if `name` did not
 /// match any builtin function.
-Function ParseFunction(std::string_view name);
+BuiltinFn ParseBuiltinFn(std::string_view name);
 
 /// @returns the name of the builtin function type. The spelling, including
 /// case, matches the name in the WGSL spec.
-const char* str(Function i);
+const char* str(BuiltinFn i);
 
 /// Emits the name of the builtin function type. The spelling, including case,
 /// matches the name in the WGSL spec.
 template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
-auto& operator<<(STREAM& o, Function i) {
+auto& operator<<(STREAM& o, BuiltinFn i) {
     return o << str(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::kTextureBarrier,
-    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::kSubgroupBallot,
-    Function::kSubgroupBroadcast,
-    Function::kTintMaterialize,
+constexpr BuiltinFn kBuiltinFns[] = {
+    BuiltinFn::kAbs,
+    BuiltinFn::kAcos,
+    BuiltinFn::kAcosh,
+    BuiltinFn::kAll,
+    BuiltinFn::kAny,
+    BuiltinFn::kArrayLength,
+    BuiltinFn::kAsin,
+    BuiltinFn::kAsinh,
+    BuiltinFn::kAtan,
+    BuiltinFn::kAtan2,
+    BuiltinFn::kAtanh,
+    BuiltinFn::kCeil,
+    BuiltinFn::kClamp,
+    BuiltinFn::kCos,
+    BuiltinFn::kCosh,
+    BuiltinFn::kCountLeadingZeros,
+    BuiltinFn::kCountOneBits,
+    BuiltinFn::kCountTrailingZeros,
+    BuiltinFn::kCross,
+    BuiltinFn::kDegrees,
+    BuiltinFn::kDeterminant,
+    BuiltinFn::kDistance,
+    BuiltinFn::kDot,
+    BuiltinFn::kDot4I8Packed,
+    BuiltinFn::kDot4U8Packed,
+    BuiltinFn::kDpdx,
+    BuiltinFn::kDpdxCoarse,
+    BuiltinFn::kDpdxFine,
+    BuiltinFn::kDpdy,
+    BuiltinFn::kDpdyCoarse,
+    BuiltinFn::kDpdyFine,
+    BuiltinFn::kExp,
+    BuiltinFn::kExp2,
+    BuiltinFn::kExtractBits,
+    BuiltinFn::kFaceForward,
+    BuiltinFn::kFirstLeadingBit,
+    BuiltinFn::kFirstTrailingBit,
+    BuiltinFn::kFloor,
+    BuiltinFn::kFma,
+    BuiltinFn::kFract,
+    BuiltinFn::kFrexp,
+    BuiltinFn::kFwidth,
+    BuiltinFn::kFwidthCoarse,
+    BuiltinFn::kFwidthFine,
+    BuiltinFn::kInsertBits,
+    BuiltinFn::kInverseSqrt,
+    BuiltinFn::kLdexp,
+    BuiltinFn::kLength,
+    BuiltinFn::kLog,
+    BuiltinFn::kLog2,
+    BuiltinFn::kMax,
+    BuiltinFn::kMin,
+    BuiltinFn::kMix,
+    BuiltinFn::kModf,
+    BuiltinFn::kNormalize,
+    BuiltinFn::kPack2X16Float,
+    BuiltinFn::kPack2X16Snorm,
+    BuiltinFn::kPack2X16Unorm,
+    BuiltinFn::kPack4X8Snorm,
+    BuiltinFn::kPack4X8Unorm,
+    BuiltinFn::kPow,
+    BuiltinFn::kQuantizeToF16,
+    BuiltinFn::kRadians,
+    BuiltinFn::kReflect,
+    BuiltinFn::kRefract,
+    BuiltinFn::kReverseBits,
+    BuiltinFn::kRound,
+    BuiltinFn::kSaturate,
+    BuiltinFn::kSelect,
+    BuiltinFn::kSign,
+    BuiltinFn::kSin,
+    BuiltinFn::kSinh,
+    BuiltinFn::kSmoothstep,
+    BuiltinFn::kSqrt,
+    BuiltinFn::kStep,
+    BuiltinFn::kStorageBarrier,
+    BuiltinFn::kTan,
+    BuiltinFn::kTanh,
+    BuiltinFn::kTranspose,
+    BuiltinFn::kTrunc,
+    BuiltinFn::kUnpack2X16Float,
+    BuiltinFn::kUnpack2X16Snorm,
+    BuiltinFn::kUnpack2X16Unorm,
+    BuiltinFn::kUnpack4X8Snorm,
+    BuiltinFn::kUnpack4X8Unorm,
+    BuiltinFn::kWorkgroupBarrier,
+    BuiltinFn::kWorkgroupUniformLoad,
+    BuiltinFn::kTextureBarrier,
+    BuiltinFn::kTextureDimensions,
+    BuiltinFn::kTextureGather,
+    BuiltinFn::kTextureGatherCompare,
+    BuiltinFn::kTextureNumLayers,
+    BuiltinFn::kTextureNumLevels,
+    BuiltinFn::kTextureNumSamples,
+    BuiltinFn::kTextureSample,
+    BuiltinFn::kTextureSampleBias,
+    BuiltinFn::kTextureSampleCompare,
+    BuiltinFn::kTextureSampleCompareLevel,
+    BuiltinFn::kTextureSampleGrad,
+    BuiltinFn::kTextureSampleLevel,
+    BuiltinFn::kTextureSampleBaseClampToEdge,
+    BuiltinFn::kTextureStore,
+    BuiltinFn::kTextureLoad,
+    BuiltinFn::kAtomicLoad,
+    BuiltinFn::kAtomicStore,
+    BuiltinFn::kAtomicAdd,
+    BuiltinFn::kAtomicSub,
+    BuiltinFn::kAtomicMax,
+    BuiltinFn::kAtomicMin,
+    BuiltinFn::kAtomicAnd,
+    BuiltinFn::kAtomicOr,
+    BuiltinFn::kAtomicXor,
+    BuiltinFn::kAtomicExchange,
+    BuiltinFn::kAtomicCompareExchangeWeak,
+    BuiltinFn::kSubgroupBallot,
+    BuiltinFn::kSubgroupBroadcast,
+    BuiltinFn::kTintMaterialize,
 };
 
 /// All builtin function names
-constexpr const char* kFunctionStrings[] = {
+constexpr const char* kBuiltinFnStrings[] = {
     "abs",
     "acos",
     "acosh",
@@ -416,63 +416,63 @@
 /// Determines if the given `f` is a coarse derivative.
 /// @param f the builtin type
 /// @returns true if the given derivative is coarse.
-bool IsCoarseDerivativeBuiltin(Function f);
+bool IsCoarseDerivative(BuiltinFn f);
 
 /// Determines if the given `f` is a fine derivative.
 /// @param f the builtin type
 /// @returns true if the given derivative is fine.
-bool IsFineDerivativeBuiltin(Function f);
+bool IsFineDerivative(BuiltinFn f);
 
 /// Determine if the given `f` is a derivative builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is a derivative builtin
-bool IsDerivativeBuiltin(Function f);
+bool IsDerivative(BuiltinFn f);
 
 /// Determines if the given `f` is a texture operation builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is a texture operation builtin
-bool IsTextureBuiltin(Function f);
+bool IsTexture(BuiltinFn f);
 
 /// Determines if the given `f` is an image query builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is an image query builtin
-bool IsImageQueryBuiltin(Function f);
+bool IsImageQuery(BuiltinFn f);
 
 /// Determines if the given `f` is a data packing builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is a data packing builtin
-bool IsDataPackingBuiltin(Function f);
+bool IsDataPacking(BuiltinFn f);
 
 /// Determines if the given `f` is a data unpacking builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is a data unpacking builtin
-bool IsDataUnpackingBuiltin(Function f);
+bool IsDataUnpacking(BuiltinFn f);
 
 /// Determines if the given `f` is a barrier builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is a barrier builtin
-bool IsBarrierBuiltin(Function f);
+bool IsBarrier(BuiltinFn f);
 
 /// Determines if the given `f` is an atomic builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is an atomic builtin
-bool IsAtomicBuiltin(Function f);
+bool IsAtomic(BuiltinFn f);
 
 /// Determines if the given `f` is a DP4a builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is a DP4a builtin
-bool IsDP4aBuiltin(Function f);
+bool IsDP4a(BuiltinFn f);
 
 /// Determines if the given `f` is a subgroup builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is a subgroup builtin
-bool IsSubgroupBuiltin(Function f);
+bool IsSubgroup(BuiltinFn f);
 
 /// Determines if the given `f` may have side-effects (i.e. writes to at least one of its inputs)
 /// @returns true if intrinsic may have side-effects
-bool HasSideEffects(Function f);
+bool HasSideEffects(BuiltinFn f);
 
 }  // namespace tint::core
 // \endcond
 
-#endif  // SRC_TINT_LANG_CORE_FUNCTION_H_
+#endif  // SRC_TINT_LANG_CORE_BUILTIN_FN_H_
diff --git a/src/tint/lang/core/function.h.tmpl b/src/tint/lang/core/builtin_fn.h.tmpl
similarity index 75%
rename from src/tint/lang/core/function.h.tmpl
rename to src/tint/lang/core/builtin_fn.h.tmpl
index 546b385..3a10674 100644
--- a/src/tint/lang/core/function.h.tmpl
+++ b/src/tint/lang/core/builtin_fn.h.tmpl
@@ -1,6 +1,6 @@
 {{- /*
 --------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate function.h
+Template file for use with tools/src/cmd/gen to generate builtin_function.h
 
 To update the generated file, run:
     ./tools/run gen
@@ -13,8 +13,8 @@
 
 {{- $I := LoadIntrinsics "src/tint/lang/core/core.def" -}}
 
-#ifndef SRC_TINT_LANG_CORE_FUNCTION_H_
-#define SRC_TINT_LANG_CORE_FUNCTION_H_
+#ifndef SRC_TINT_LANG_CORE_BUILTIN_FN_H_
+#define SRC_TINT_LANG_CORE_BUILTIN_FN_H_
 
 #include <cstdint>
 #include <string>
@@ -25,39 +25,39 @@
 namespace tint::core {
 
 /// Enumerator of all builtin functions
-enum class Function : uint8_t {
+enum class BuiltinFn : uint8_t {
 {{- range $I.Sem.Builtins }}
     k{{PascalCase .Name}},
 {{- end }}
     kNone,
 };
 
-/// Matches the Function by name
+/// Matches the BuiltinFn by name
 /// @param name the builtin name to parse
-/// @returns the parsed Function, or Function::kNone if `name` did not
+/// @returns the parsed BuiltinFn, or BuiltinFn::kNone if `name` did not
 /// match any builtin function.
-Function ParseFunction(std::string_view name);
+BuiltinFn ParseBuiltinFn(std::string_view name);
 
 /// @returns the name of the builtin function type. The spelling, including
 /// case, matches the name in the WGSL spec.
-const char* str(Function i);
+const char* str(BuiltinFn i);
 
 /// Emits the name of the builtin function type. The spelling, including case,
 /// matches the name in the WGSL spec.
 template <typename STREAM, typename = traits::EnableIfIsOStream<STREAM>>
-auto& operator<<(STREAM& o, Function i) {
+auto& operator<<(STREAM& o, BuiltinFn i) {
   return o << str(i);
 }
 
 /// All builtin functions
-constexpr Function kFunctions[] = {
+constexpr BuiltinFn kBuiltinFns[] = {
 {{- range $I.Sem.Builtins }}
-    Function::k{{PascalCase .Name}},
+    BuiltinFn::k{{PascalCase .Name}},
 {{- end }}
 };
 
 /// All builtin function names
-constexpr const char* kFunctionStrings[] = {
+constexpr const char* kBuiltinFnStrings[] = {
 {{- range $I.Sem.Builtins }}
     "{{.Name}}",
 {{- end }}
@@ -66,63 +66,63 @@
 /// Determines if the given `f` is a coarse derivative.
 /// @param f the builtin type
 /// @returns true if the given derivative is coarse.
-bool IsCoarseDerivativeBuiltin(Function f);
+bool IsCoarseDerivative(BuiltinFn f);
 
 /// Determines if the given `f` is a fine derivative.
 /// @param f the builtin type
 /// @returns true if the given derivative is fine.
-bool IsFineDerivativeBuiltin(Function f);
+bool IsFineDerivative(BuiltinFn f);
 
 /// Determine if the given `f` is a derivative builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is a derivative builtin
-bool IsDerivativeBuiltin(Function f);
+bool IsDerivative(BuiltinFn f);
 
 /// Determines if the given `f` is a texture operation builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is a texture operation builtin
-bool IsTextureBuiltin(Function f);
+bool IsTexture(BuiltinFn f);
 
 /// Determines if the given `f` is an image query builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is an image query builtin
-bool IsImageQueryBuiltin(Function f);
+bool IsImageQuery(BuiltinFn f);
 
 /// Determines if the given `f` is a data packing builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is a data packing builtin
-bool IsDataPackingBuiltin(Function f);
+bool IsDataPacking(BuiltinFn f);
 
 /// Determines if the given `f` is a data unpacking builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is a data unpacking builtin
-bool IsDataUnpackingBuiltin(Function f);
+bool IsDataUnpacking(BuiltinFn f);
 
 /// Determines if the given `f` is a barrier builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is a barrier builtin
-bool IsBarrierBuiltin(Function f);
+bool IsBarrier(BuiltinFn f);
 
 /// Determines if the given `f` is an atomic builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is an atomic builtin
-bool IsAtomicBuiltin(Function f);
+bool IsAtomic(BuiltinFn f);
 
 /// Determines if the given `f` is a DP4a builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is a DP4a builtin
-bool IsDP4aBuiltin(Function f);
+bool IsDP4a(BuiltinFn f);
 
 /// Determines if the given `f` is a subgroup builtin.
 /// @param f the builtin type
 /// @returns true if the given `f` is a subgroup builtin
-bool IsSubgroupBuiltin(Function f);
+bool IsSubgroup(BuiltinFn f);
 
 /// Determines if the given `f` may have side-effects (i.e. writes to at least one of its inputs)
 /// @returns true if intrinsic may have side-effects
-bool HasSideEffects(Function f);
+bool HasSideEffects(BuiltinFn f);
 
 }  // namespace tint::core
 // \endcond
 
-#endif  // SRC_TINT_LANG_CORE_FUNCTION_H_
+#endif  // SRC_TINT_LANG_CORE_BUILTIN_FN_H_
diff --git a/src/tint/lang/core/constant/eval_builtin_test.cc b/src/tint/lang/core/constant/eval_builtin_test.cc
index 6a31120..cca292d 100644
--- a/src/tint/lang/core/constant/eval_builtin_test.cc
+++ b/src/tint/lang/core/constant/eval_builtin_test.cc
@@ -139,7 +139,7 @@
     return Case{std::move(args), std::move(err)};
 }
 
-using ConstEvalBuiltinTest = ConstEvalTestWithParam<std::tuple<core::Function, Case>>;
+using ConstEvalBuiltinTest = ConstEvalTestWithParam<std::tuple<core::BuiltinFn, Case>>;
 
 TEST_P(ConstEvalBuiltinTest, Test) {
     Enable(wgsl::Extension::kF16);
@@ -186,7 +186,7 @@
 
 INSTANTIATE_TEST_SUITE_P(MixedAbstractArgs_Atan2,
                          ConstEvalBuiltinTest,
-                         testing::Combine(testing::Values(core::Function::kAtan2),
+                         testing::Combine(testing::Values(core::BuiltinFn::kAtan2),
                                           testing::ValuesIn(std::vector{
                                               C({0.0_a, 1_a}, AFloat{0}),
                                               C({0_a, 1.0_a}, AFloat{0}),
@@ -196,7 +196,7 @@
 
 INSTANTIATE_TEST_SUITE_P(MixedAbstractArgs_Max,
                          ConstEvalBuiltinTest,
-                         testing::Combine(testing::Values(core::Function::kMax),
+                         testing::Combine(testing::Values(core::BuiltinFn::kMax),
                                           testing::ValuesIn(std::vector{
                                               // AbstractInt first, AbstractFloat second
                                               C({1_a, 2.0_a}, AFloat{2}),
@@ -247,7 +247,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Abs,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kAbs),
+    testing::Combine(testing::Values(core::BuiltinFn::kAbs),
                      testing::ValuesIn(Concat(AbsCases<AInt>(),  //
                                               AbsCases<i32>(),
                                               AbsCases<u32>(),
@@ -282,7 +282,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     All,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kAll), testing::ValuesIn(AllCases())));
+    testing::Combine(testing::Values(core::BuiltinFn::kAll), testing::ValuesIn(AllCases())));
 
 static std::vector<Case> AnyCases() {
     return {
@@ -311,7 +311,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Any,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kAny), testing::ValuesIn(AnyCases())));
+    testing::Combine(testing::Values(core::BuiltinFn::kAny), testing::ValuesIn(AnyCases())));
 
 template <typename T>
 std::vector<Case> Atan2Cases() {
@@ -346,7 +346,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Atan2,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kAtan2),
+    testing::Combine(testing::Values(core::BuiltinFn::kAtan2),
                      testing::ValuesIn(Concat(Atan2Cases<AFloat>(),  //
                                               Atan2Cases<f32>(),
                                               Atan2Cases<f16>()))));
@@ -367,7 +367,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Atan,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kAtan),
+    testing::Combine(testing::Values(core::BuiltinFn::kAtan),
                      testing::ValuesIn(Concat(AtanCases<AFloat>(),  //
                                               AtanCases<f32>(),
                                               AtanCases<f16>()))));
@@ -392,7 +392,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Atanh,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kAtanh),
+    testing::Combine(testing::Values(core::BuiltinFn::kAtanh),
                      testing::ValuesIn(Concat(AtanhCases<AFloat>(),  //
                                               AtanhCases<f32>(),
                                               AtanhCases<f16>()))));
@@ -418,7 +418,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Acos,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kAcos),
+    testing::Combine(testing::Values(core::BuiltinFn::kAcos),
                      testing::ValuesIn(Concat(AcosCases<AFloat>(),  //
                                               AcosCases<f32>(),
                                               AcosCases<f16>()))));
@@ -440,7 +440,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Acosh,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kAcosh),
+    testing::Combine(testing::Values(core::BuiltinFn::kAcosh),
                      testing::ValuesIn(Concat(AcoshCases<AFloat>(),  //
                                               AcoshCases<f32>(),
                                               AcoshCases<f16>()))));
@@ -467,7 +467,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Asin,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kAsin),
+    testing::Combine(testing::Values(core::BuiltinFn::kAsin),
                      testing::ValuesIn(Concat(AsinCases<AFloat>(),  //
                                               AsinCases<f32>(),
                                               AsinCases<f16>()))));
@@ -491,7 +491,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Asinh,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kAsinh),
+    testing::Combine(testing::Values(core::BuiltinFn::kAsinh),
                      testing::ValuesIn(Concat(AsinhCases<AFloat>(),  //
                                               AsinhCases<f32>(),
                                               AsinhCases<f16>()))));
@@ -513,7 +513,7 @@
     Ceil,
     ConstEvalBuiltinTest,
     testing::Combine(
-        testing::Values(core::Function::kCeil),
+        testing::Values(core::BuiltinFn::kCeil),
         testing::ValuesIn(Concat(CeilCases<AFloat>(), CeilCases<f32>(), CeilCases<f16>()))));
 
 template <typename T>
@@ -558,7 +558,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Clamp,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kClamp),
+    testing::Combine(testing::Values(core::BuiltinFn::kClamp),
                      testing::ValuesIn(Concat(ClampCases<AInt>(),  //
                                               ClampCases<i32>(),
                                               ClampCases<u32>(),
@@ -581,7 +581,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Cos,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kCos),
+    testing::Combine(testing::Values(core::BuiltinFn::kCos),
                      testing::ValuesIn(Concat(CosCases<AFloat>(),  //
                                               CosCases<f32>(),
                                               CosCases<f16>()))));
@@ -607,7 +607,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Cosh,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kCosh),
+    testing::Combine(testing::Values(core::BuiltinFn::kCosh),
                      testing::ValuesIn(Concat(CoshCases<AFloat>(),  //
                                               CoshCases<f32>(),
                                               CoshCases<f16>()))));
@@ -654,7 +654,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     CountLeadingZeros,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kCountLeadingZeros),
+    testing::Combine(testing::Values(core::BuiltinFn::kCountLeadingZeros),
                      testing::ValuesIn(Concat(CountLeadingZerosCases<i32>(),  //
                                               CountLeadingZerosCases<u32>()))));
 
@@ -700,7 +700,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     CountTrailingZeros,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kCountTrailingZeros),
+    testing::Combine(testing::Values(core::BuiltinFn::kCountTrailingZeros),
                      testing::ValuesIn(Concat(CountTrailingZerosCases<i32>(),  //
                                               CountTrailingZerosCases<u32>()))));
 
@@ -737,7 +737,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     CountOneBits,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kCountOneBits),
+    testing::Combine(testing::Values(core::BuiltinFn::kCountOneBits),
                      testing::ValuesIn(Concat(CountOneBitsCases<i32>(),  //
                                               CountOneBitsCases<u32>()))));
 
@@ -836,7 +836,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Cross,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kCross),
+    testing::Combine(testing::Values(core::BuiltinFn::kCross),
                      testing::ValuesIn(Concat(CrossCases<AFloat>(),  //
                                               CrossCases<f32>(),     //
                                               CrossCases<f16>()))));
@@ -863,7 +863,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Distance,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kDistance),
+    testing::Combine(testing::Values(core::BuiltinFn::kDistance),
                      testing::ValuesIn(Concat(DistanceCases<AFloat>(),  //
                                               DistanceCases<f32>(),     //
                                               DistanceCases<f16>()))));
@@ -911,7 +911,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Dot,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kDot),
+    testing::Combine(testing::Values(core::BuiltinFn::kDot),
                      testing::ValuesIn(Concat(DotCases<AInt>(),    //
                                               DotCases<i32>(),     //
                                               DotCases<u32>(),     //
@@ -991,7 +991,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Determinant,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kDeterminant),
+    testing::Combine(testing::Values(core::BuiltinFn::kDeterminant),
                      testing::ValuesIn(Concat(DeterminantCases<AFloat>(),  //
                                               DeterminantCases<f32>(),     //
                                               DeterminantCases<f16>()))));
@@ -1073,7 +1073,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     FaceForward,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kFaceForward),
+    testing::Combine(testing::Values(core::BuiltinFn::kFaceForward),
                      testing::ValuesIn(Concat(FaceForwardCases<AFloat>(),  //
                                               FaceForwardCases<f32>(),     //
                                               FaceForwardCases<f16>()))));
@@ -1136,7 +1136,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     FirstLeadingBit,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kFirstLeadingBit),
+    testing::Combine(testing::Values(core::BuiltinFn::kFirstLeadingBit),
                      testing::ValuesIn(Concat(FirstLeadingBitCases<i32>(),  //
                                               FirstLeadingBitCases<u32>()))));
 
@@ -1169,7 +1169,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     FirstTrailingBit,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kFirstTrailingBit),
+    testing::Combine(testing::Values(core::BuiltinFn::kFirstTrailingBit),
                      testing::ValuesIn(Concat(FirstTrailingBitCases<i32>(),  //
                                               FirstTrailingBitCases<u32>()))));
 
@@ -1189,7 +1189,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Floor,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kFloor),
+    testing::Combine(testing::Values(core::BuiltinFn::kFloor),
                      testing::ValuesIn(Concat(FloorCases<AFloat>(),  //
                                               FloorCases<f32>(),
                                               FloorCases<f16>()))));
@@ -1213,7 +1213,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Fma,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kFma),
+    testing::Combine(testing::Values(core::BuiltinFn::kFma),
                      testing::ValuesIn(Concat(FmaCases<AFloat>(),  //
                                               FmaCases<f32>(),
                                               FmaCases<f16>()))));
@@ -1245,7 +1245,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Fract,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kFract),
+    testing::Combine(testing::Values(core::BuiltinFn::kFract),
                      testing::ValuesIn(Concat(FractCases<AFloat>(),  //
                                               FractCases<f32>(),
                                               FractCases<f16>()))));
@@ -1302,7 +1302,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Frexp,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kFrexp),
+    testing::Combine(testing::Values(core::BuiltinFn::kFrexp),
                      testing::ValuesIn(Concat(FrexpCases<AFloat>(),  //
                                               FrexpCases<f32>(),     //
                                               FrexpCases<f16>()))));
@@ -1384,7 +1384,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     InsertBits,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kInsertBits),
+    testing::Combine(testing::Values(core::BuiltinFn::kInsertBits),
                      testing::ValuesIn(Concat(InsertBitsCases<i32>(),  //
                                               InsertBitsCases<u32>()))));
 
@@ -1404,7 +1404,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     InverseSqrt,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kInverseSqrt),
+    testing::Combine(testing::Values(core::BuiltinFn::kInverseSqrt),
                      testing::ValuesIn(Concat(InverseSqrtCases<AFloat>(),  //
                                               InverseSqrtCases<f32>(),
                                               InverseSqrtCases<f16>()))));
@@ -1423,7 +1423,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     DegreesAFloat,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kDegrees),
+    testing::Combine(testing::Values(core::BuiltinFn::kDegrees),
                      testing::ValuesIn(DegreesAFloatCases<AFloat>())));
 
 template <typename T>
@@ -1440,7 +1440,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     DegreesF32,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kDegrees),
+    testing::Combine(testing::Values(core::BuiltinFn::kDegrees),
                      testing::ValuesIn(DegreesF32Cases<f32>())));
 
 template <typename T>
@@ -1457,7 +1457,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     DegreesF16,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kDegrees),
+    testing::Combine(testing::Values(core::BuiltinFn::kDegrees),
                      testing::ValuesIn(DegreesF16Cases<f16>())));
 
 template <typename T>
@@ -1474,7 +1474,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Exp,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kExp),
+    testing::Combine(testing::Values(core::BuiltinFn::kExp),
                      testing::ValuesIn(Concat(ExpCases<AFloat>(),  //
                                               ExpCases<f32>(),
                                               ExpCases<f16>()))));
@@ -1495,7 +1495,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Exp2,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kExp2),
+    testing::Combine(testing::Values(core::BuiltinFn::kExp2),
                      testing::ValuesIn(Concat(Exp2Cases<AFloat>(),  //
                                               Exp2Cases<f32>(),
                                               Exp2Cases<f16>()))));
@@ -1592,7 +1592,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     ExtractBits,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kExtractBits),
+    testing::Combine(testing::Values(core::BuiltinFn::kExtractBits),
                      testing::ValuesIn(Concat(ExtractBitsCases<i32>(),  //
                                               ExtractBitsCases<u32>()))));
 
@@ -1656,7 +1656,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Ldexp,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kLdexp),
+    testing::Combine(testing::Values(core::BuiltinFn::kLdexp),
                      testing::ValuesIn(Concat(LdexpCases<AFloat>(),  //
                                               LdexpCases<f32>(),
                                               LdexpCases<f16>()))));
@@ -1715,7 +1715,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Length,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kLength),
+    testing::Combine(testing::Values(core::BuiltinFn::kLength),
                      testing::ValuesIn(Concat(LengthCases<AFloat>(),  //
                                               LengthCases<f32>(),
                                               LengthCases<f16>()))));
@@ -1731,7 +1731,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Log,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kLog),
+    testing::Combine(testing::Values(core::BuiltinFn::kLog),
                      testing::ValuesIn(Concat(LogCases<AFloat>(),  //
                                               LogCases<f32>(),
                                               LogCases<f16>()))));
@@ -1744,7 +1744,8 @@
 INSTANTIATE_TEST_SUITE_P(  //
     LogF16,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kLog), testing::ValuesIn(LogF16Cases<f16>())));
+    testing::Combine(testing::Values(core::BuiltinFn::kLog),
+                     testing::ValuesIn(LogF16Cases<f16>())));
 template <typename T>
 std::vector<Case> LogF32Cases() {
     return {
@@ -1754,7 +1755,8 @@
 INSTANTIATE_TEST_SUITE_P(  //
     LogF32,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kLog), testing::ValuesIn(LogF32Cases<f32>())));
+    testing::Combine(testing::Values(core::BuiltinFn::kLog),
+                     testing::ValuesIn(LogF32Cases<f32>())));
 
 template <typename T>
 std::vector<Case> LogAbstractCases() {
@@ -1765,7 +1767,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     LogAbstract,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kLog),
+    testing::Combine(testing::Values(core::BuiltinFn::kLog),
                      testing::ValuesIn(LogAbstractCases<AFloat>())));
 
 template <typename T>
@@ -1783,7 +1785,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Log2,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kLog2),
+    testing::Combine(testing::Values(core::BuiltinFn::kLog2),
                      testing::ValuesIn(Concat(Log2Cases<AFloat>(),  //
                                               Log2Cases<f32>(),
                                               Log2Cases<f16>()))));
@@ -1796,7 +1798,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Log2F16,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kLog2),
+    testing::Combine(testing::Values(core::BuiltinFn::kLog2),
                      testing::ValuesIn(Log2F16Cases<f16>())));
 template <typename T>
 std::vector<Case> Log2F32Cases() {
@@ -1807,7 +1809,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Log2F32,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kLog2),
+    testing::Combine(testing::Values(core::BuiltinFn::kLog2),
                      testing::ValuesIn(Log2F32Cases<f32>())));
 template <typename T>
 std::vector<Case> Log2AbstractCases() {
@@ -1818,7 +1820,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Log2Abstract,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kLog2),
+    testing::Combine(testing::Values(core::BuiltinFn::kLog2),
                      testing::ValuesIn(Log2AbstractCases<AFloat>())));
 
 template <typename T>
@@ -1841,7 +1843,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Max,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kMax),
+    testing::Combine(testing::Values(core::BuiltinFn::kMax),
                      testing::ValuesIn(Concat(MaxCases<AInt>(),  //
                                               MaxCases<i32>(),
                                               MaxCases<u32>(),
@@ -1867,7 +1869,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Min,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kMin),
+    testing::Combine(testing::Values(core::BuiltinFn::kMin),
                      testing::ValuesIn(Concat(MinCases<AInt>(),  //
                                               MinCases<i32>(),
                                               MinCases<u32>(),
@@ -1957,7 +1959,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Mix,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kMix),
+    testing::Combine(testing::Values(core::BuiltinFn::kMix),
                      testing::ValuesIn(Concat(MixCases<AFloat>(),  //
                                               MixCases<f32>(),     //
                                               MixCases<f16>()))));
@@ -1991,7 +1993,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Modf,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kModf),
+    testing::Combine(testing::Values(core::BuiltinFn::kModf),
                      testing::ValuesIn(Concat(ModfCases<AFloat>(),  //
                                               ModfCases<f32>(),     //
                                               ModfCases<f16>()))));
@@ -2021,7 +2023,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Normalize,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kNormalize),
+    testing::Combine(testing::Values(core::BuiltinFn::kNormalize),
                      testing::ValuesIn(Concat(NormalizeCases<AFloat>(),  //
                                               NormalizeCases<f32>(),     //
                                               NormalizeCases<f16>()))));
@@ -2041,7 +2043,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Pack4x8snorm,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kPack4X8Snorm),
+    testing::Combine(testing::Values(core::BuiltinFn::kPack4X8Snorm),
                      testing::ValuesIn(Pack4x8snormCases())));
 
 std::vector<Case> Pack4x8unormCases() {
@@ -2058,7 +2060,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Pack4x8unorm,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kPack4X8Unorm),
+    testing::Combine(testing::Values(core::BuiltinFn::kPack4X8Unorm),
                      testing::ValuesIn(Pack4x8unormCases())));
 
 std::vector<Case> Pack2x16floatCases() {
@@ -2079,7 +2081,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Pack2x16float,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kPack2X16Float),
+    testing::Combine(testing::Values(core::BuiltinFn::kPack2X16Float),
                      testing::ValuesIn(Pack2x16floatCases())));
 
 std::vector<Case> Pack2x16snormCases() {
@@ -2097,7 +2099,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Pack2x16snorm,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kPack2X16Snorm),
+    testing::Combine(testing::Values(core::BuiltinFn::kPack2X16Snorm),
                      testing::ValuesIn(Pack2x16snormCases())));
 
 std::vector<Case> Pack2x16unormCases() {
@@ -2111,7 +2113,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Pack2x16unorm,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kPack2X16Unorm),
+    testing::Combine(testing::Values(core::BuiltinFn::kPack2X16Unorm),
                      testing::ValuesIn(Pack2x16unormCases())));
 
 template <typename T>
@@ -2157,7 +2159,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Pow,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kPow),
+    testing::Combine(testing::Values(core::BuiltinFn::kPow),
                      testing::ValuesIn(Concat(PowCases<AFloat>(),  //
                                               PowCases<f32>(),     //
                                               PowCases<f16>()))));
@@ -2204,7 +2206,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     ReverseBits,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kReverseBits),
+    testing::Combine(testing::Values(core::BuiltinFn::kReverseBits),
                      testing::ValuesIn(Concat(ReverseBitsCases<i32>(),  //
                                               ReverseBitsCases<u32>()))));
 
@@ -2256,7 +2258,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Reflect,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kReflect),
+    testing::Combine(testing::Values(core::BuiltinFn::kReflect),
                      testing::ValuesIn(Concat(ReflectCases<AFloat>(),  //
                                               ReflectCases<f32>(),     //
                                               ReflectCases<f16>()))));
@@ -2346,7 +2348,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Refract,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kRefract),
+    testing::Combine(testing::Values(core::BuiltinFn::kRefract),
                      testing::ValuesIn(Concat(RefractCases<AFloat>(),  //
                                               RefractCases<f32>(),     //
                                               RefractCases<f16>()))));
@@ -2365,7 +2367,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Radians,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kRadians),
+    testing::Combine(testing::Values(core::BuiltinFn::kRadians),
                      testing::ValuesIn(Concat(RadiansCases<AFloat>(),  //
                                               RadiansCases<f32>()))));
 
@@ -2383,7 +2385,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     RadiansF16,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kRadians),
+    testing::Combine(testing::Values(core::BuiltinFn::kRadians),
                      testing::ValuesIn(RadiansF16Cases<f16>())));
 
 template <typename T>
@@ -2409,7 +2411,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Round,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kRound),
+    testing::Combine(testing::Values(core::BuiltinFn::kRound),
                      testing::ValuesIn(Concat(RoundCases<AFloat>(),  //
                                               RoundCases<f32>(),
                                               RoundCases<f16>()))));
@@ -2434,7 +2436,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Saturate,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kSaturate),
+    testing::Combine(testing::Values(core::BuiltinFn::kSaturate),
                      testing::ValuesIn(Concat(SaturateCases<AFloat>(),  //
                                               SaturateCases<f32>(),
                                               SaturateCases<f16>()))));
@@ -2476,7 +2478,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Select,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kSelect),
+    testing::Combine(testing::Values(core::BuiltinFn::kSelect),
                      testing::ValuesIn(Concat(SelectCases<AInt>(),  //
                                               SelectCases<i32>(),
                                               SelectCases<u32>(),
@@ -2517,7 +2519,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Sign,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kSign),
+    testing::Combine(testing::Values(core::BuiltinFn::kSign),
                      testing::ValuesIn(Concat(SignCases<AInt>(),  //
                                               SignCases<i32>(),
                                               SignCases<AFloat>(),
@@ -2539,7 +2541,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Sin,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kSin),
+    testing::Combine(testing::Values(core::BuiltinFn::kSin),
                      testing::ValuesIn(Concat(SinCases<AFloat>(),  //
                                               SinCases<f32>(),
                                               SinCases<f16>()))));
@@ -2564,7 +2566,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Sinh,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kSinh),
+    testing::Combine(testing::Values(core::BuiltinFn::kSinh),
                      testing::ValuesIn(Concat(SinhCases<AFloat>(),  //
                                               SinhCases<f32>(),
                                               SinhCases<f16>()))));
@@ -2597,7 +2599,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Smoothstep,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kSmoothstep),
+    testing::Combine(testing::Values(core::BuiltinFn::kSmoothstep),
                      testing::ValuesIn(Concat(SmoothstepCases<AFloat>(),  //
                                               SmoothstepCases<f32>(),
                                               SmoothstepCases<f16>()))));
@@ -2629,7 +2631,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Step,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kStep),
+    testing::Combine(testing::Values(core::BuiltinFn::kStep),
                      testing::ValuesIn(Concat(StepCases<AFloat>(),  //
                                               StepCases<f32>(),
                                               StepCases<f16>()))));
@@ -2650,7 +2652,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Sqrt,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kSqrt),
+    testing::Combine(testing::Values(core::BuiltinFn::kSqrt),
                      testing::ValuesIn(Concat(SqrtCases<AFloat>(),  //
                                               SqrtCases<f32>(),
                                               SqrtCases<f16>()))));
@@ -2669,7 +2671,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Tan,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kTan),
+    testing::Combine(testing::Values(core::BuiltinFn::kTan),
                      testing::ValuesIn(Concat(TanCases<AFloat>(),  //
                                               TanCases<f32>(),
                                               TanCases<f16>()))));
@@ -2689,7 +2691,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Tanh,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kTanh),
+    testing::Combine(testing::Values(core::BuiltinFn::kTanh),
                      testing::ValuesIn(Concat(TanhCases<AFloat>(),  //
                                               TanhCases<f32>(),
                                               TanhCases<f16>()))));
@@ -2755,7 +2757,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Transpose,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kTranspose),
+    testing::Combine(testing::Values(core::BuiltinFn::kTranspose),
                      testing::ValuesIn(Concat(TransposeCases<AFloat>(),  //
                                               TransposeCases<f32>(),
                                               TransposeCases<f16>()))));
@@ -2773,7 +2775,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Trunc,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kTrunc),
+    testing::Combine(testing::Values(core::BuiltinFn::kTrunc),
                      testing::ValuesIn(Concat(TruncCases<AFloat>(),  //
                                               TruncCases<f32>(),
                                               TruncCases<f16>()))));
@@ -2794,7 +2796,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Unpack4x8snorm,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kUnpack4X8Snorm),
+    testing::Combine(testing::Values(core::BuiltinFn::kUnpack4X8Snorm),
                      testing::ValuesIn(Unpack4x8snormCases())));
 
 std::vector<Case> Unpack4x8unormCases() {
@@ -2811,7 +2813,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Unpack4x8unorm,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kUnpack4X8Unorm),
+    testing::Combine(testing::Values(core::BuiltinFn::kUnpack4X8Unorm),
                      testing::ValuesIn(Unpack4x8unormCases())));
 
 std::vector<Case> Unpack2x16floatCases() {
@@ -2825,7 +2827,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Unpack2x16float,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kUnpack2X16Float),
+    testing::Combine(testing::Values(core::BuiltinFn::kUnpack2X16Float),
                      testing::ValuesIn(Unpack2x16floatCases())));
 
 std::vector<Case> Unpack2x16snormCases() {
@@ -2843,7 +2845,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Unpack2x16snorm,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kUnpack2X16Snorm),
+    testing::Combine(testing::Values(core::BuiltinFn::kUnpack2X16Snorm),
                      testing::ValuesIn(Unpack2x16snormCases())));
 
 std::vector<Case> Unpack2x16unormCases() {
@@ -2857,7 +2859,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     Unpack2x16unorm,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kUnpack2X16Unorm),
+    testing::Combine(testing::Values(core::BuiltinFn::kUnpack2X16Unorm),
                      testing::ValuesIn(Unpack2x16unormCases())));
 
 std::vector<Case> QuantizeToF16Cases() {
@@ -2916,7 +2918,7 @@
 INSTANTIATE_TEST_SUITE_P(  //
     QuantizeToF16,
     ConstEvalBuiltinTest,
-    testing::Combine(testing::Values(core::Function::kQuantizeToF16),
+    testing::Combine(testing::Values(core::BuiltinFn::kQuantizeToF16),
                      testing::ValuesIn(QuantizeToF16Cases())));
 
 }  // namespace
diff --git a/src/tint/lang/core/constant/eval_conversion_test.cc b/src/tint/lang/core/constant/eval_conversion_test.cc
index 2ff6ce6..200666e 100644
--- a/src/tint/lang/core/constant/eval_conversion_test.cc
+++ b/src/tint/lang/core/constant/eval_conversion_test.cc
@@ -453,7 +453,7 @@
     //   const c = modf(4.0);
     //   var v = c;
     // }
-    auto* expr_c = Call(core::Function::kModf, 0_a);
+    auto* expr_c = Call(core::BuiltinFn::kModf, 0_a);
     auto* materialized = Expr("c");
     WrapInFunction(Decl(Const("c", expr_c)), Decl(Var("v", materialized)));
 
diff --git a/src/tint/lang/core/function.cc b/src/tint/lang/core/function.cc
deleted file mode 100644
index afa1150..0000000
--- a/src/tint/lang/core/function.cc
+++ /dev/null
@@ -1,711 +0,0 @@
-// Copyright 2023 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-////////////////////////////////////////////////////////////////////////////////
-// File generated by 'tools/src/cmd/gen' using the template:
-//   src/tint/lang/core/function.cc.tmpl
-//
-// To regenerate run: './tools/run gen'
-//
-//                       Do not modify this file directly
-////////////////////////////////////////////////////////////////////////////////
-
-#include "src/tint/lang/core/function.h"
-
-namespace tint::core {
-
-Function ParseFunction(std::string_view 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 == "textureBarrier") {
-        return Function::kTextureBarrier;
-    }
-    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 == "subgroupBallot") {
-        return Function::kSubgroupBallot;
-    }
-    if (name == "subgroupBroadcast") {
-        return Function::kSubgroupBroadcast;
-    }
-    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::kTextureBarrier:
-            return "textureBarrier";
-        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::kSubgroupBallot:
-            return "subgroupBallot";
-        case Function::kSubgroupBroadcast:
-            return "subgroupBroadcast";
-        case Function::kTintMaterialize:
-            return "_tint_materialize";
-    }
-    return "<unknown>";
-}
-
-bool IsCoarseDerivativeBuiltin(Function f) {
-    return f == Function::kDpdxCoarse || f == Function::kDpdyCoarse || f == Function::kFwidthCoarse;
-}
-
-bool IsFineDerivativeBuiltin(Function f) {
-    return f == Function::kDpdxFine || f == Function::kDpdyFine || f == Function::kFwidthFine;
-}
-
-bool IsDerivativeBuiltin(Function f) {
-    return f == Function::kDpdx || f == Function::kDpdy || f == Function::kFwidth ||
-           IsCoarseDerivativeBuiltin(f) || IsFineDerivativeBuiltin(f);
-}
-
-bool IsTextureBuiltin(Function f) {
-    return IsImageQueryBuiltin(f) ||                        //
-           f == Function::kTextureGather ||                 //
-           f == Function::kTextureGatherCompare ||          //
-           f == Function::kTextureLoad ||                   //
-           f == Function::kTextureSample ||                 //
-           f == Function::kTextureSampleBaseClampToEdge ||  //
-           f == Function::kTextureSampleBias ||             //
-           f == Function::kTextureSampleCompare ||          //
-           f == Function::kTextureSampleCompareLevel ||     //
-           f == Function::kTextureSampleGrad ||             //
-           f == Function::kTextureSampleLevel ||            //
-           f == Function::kTextureStore;
-}
-
-bool IsImageQueryBuiltin(Function f) {
-    return f == Function::kTextureDimensions || f == Function::kTextureNumLayers ||
-           f == Function::kTextureNumLevels || f == Function::kTextureNumSamples;
-}
-
-bool IsDataPackingBuiltin(Function f) {
-    return f == Function::kPack4X8Snorm || f == Function::kPack4X8Unorm ||
-           f == Function::kPack2X16Snorm || f == Function::kPack2X16Unorm ||
-           f == Function::kPack2X16Float;
-}
-
-bool IsDataUnpackingBuiltin(Function f) {
-    return f == Function::kUnpack4X8Snorm || f == Function::kUnpack4X8Unorm ||
-           f == Function::kUnpack2X16Snorm || f == Function::kUnpack2X16Unorm ||
-           f == Function::kUnpack2X16Float;
-}
-
-bool IsBarrierBuiltin(Function f) {
-    return f == Function::kWorkgroupBarrier || f == Function::kStorageBarrier ||
-           f == Function::kTextureBarrier;
-}
-
-bool IsAtomicBuiltin(Function f) {
-    return f == Function::kAtomicLoad || f == Function::kAtomicStore || f == Function::kAtomicAdd ||
-           f == Function::kAtomicSub || f == Function::kAtomicMax || f == Function::kAtomicMin ||
-           f == Function::kAtomicAnd || f == Function::kAtomicOr || f == Function::kAtomicXor ||
-           f == Function::kAtomicExchange || f == Function::kAtomicCompareExchangeWeak;
-}
-
-bool IsDP4aBuiltin(Function f) {
-    return f == Function::kDot4I8Packed || f == Function::kDot4U8Packed;
-}
-
-bool IsSubgroupBuiltin(Function f) {
-    return f == Function::kSubgroupBallot || f == Function::kSubgroupBroadcast;
-}
-
-bool HasSideEffects(Function f) {
-    switch (f) {
-        case Function::kAtomicAdd:
-        case Function::kAtomicAnd:
-        case Function::kAtomicCompareExchangeWeak:
-        case Function::kAtomicExchange:
-        case Function::kAtomicMax:
-        case Function::kAtomicMin:
-        case Function::kAtomicOr:
-        case Function::kAtomicStore:
-        case Function::kAtomicSub:
-        case Function::kAtomicXor:
-        case Function::kTextureStore:
-        case Function::kWorkgroupUniformLoad:
-            return true;
-        default:
-            break;
-    }
-    return false;
-}
-
-}  // namespace tint::core
diff --git a/src/tint/lang/core/function.cc.tmpl b/src/tint/lang/core/function.cc.tmpl
deleted file mode 100644
index e594eb6..0000000
--- a/src/tint/lang/core/function.cc.tmpl
+++ /dev/null
@@ -1,132 +0,0 @@
-{{- /*
---------------------------------------------------------------------------------
-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
---------------------------------------------------------------------------------
-*/ -}}
-
-{{- $I := LoadIntrinsics "src/tint/lang/core/core.def" -}}
-#include "src/tint/lang/core/function.h"
-
-namespace tint::core {
-
-Function ParseFunction(std::string_view name) {
-{{- range $I.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 $I.Sem.Builtins  }}
-        case Function::k{{PascalCase .Name}}:
-            return "{{.Name}}";
-{{- end  }}
-    }
-    return "<unknown>";
-}
-
-bool IsCoarseDerivativeBuiltin(Function f) {
-    return f == Function::kDpdxCoarse || f == Function::kDpdyCoarse ||
-           f == Function::kFwidthCoarse;
-}
-
-bool IsFineDerivativeBuiltin(Function f) {
-    return f == Function::kDpdxFine || f == Function::kDpdyFine ||
-           f == Function::kFwidthFine;
-}
-
-bool IsDerivativeBuiltin(Function f) {
-    return f == Function::kDpdx || f == Function::kDpdy ||
-           f == Function::kFwidth || IsCoarseDerivativeBuiltin(f) ||
-           IsFineDerivativeBuiltin(f);
-}
-
-bool IsTextureBuiltin(Function f) {
-    return IsImageQueryBuiltin(f) ||                                 //
-           f == Function::kTextureGather ||                 //
-           f == Function::kTextureGatherCompare ||          //
-           f == Function::kTextureLoad ||                   //
-           f == Function::kTextureSample ||                 //
-           f == Function::kTextureSampleBaseClampToEdge ||  //
-           f == Function::kTextureSampleBias ||             //
-           f == Function::kTextureSampleCompare ||          //
-           f == Function::kTextureSampleCompareLevel ||     //
-           f == Function::kTextureSampleGrad ||             //
-           f == Function::kTextureSampleLevel ||            //
-           f == Function::kTextureStore;
-}
-
-bool IsImageQueryBuiltin(Function f) {
-    return f == Function::kTextureDimensions ||
-           f == Function::kTextureNumLayers || f == Function::kTextureNumLevels ||
-           f == Function::kTextureNumSamples;
-}
-
-bool IsDataPackingBuiltin(Function f) {
-    return f == Function::kPack4X8Snorm || f == Function::kPack4X8Unorm ||
-           f == Function::kPack2X16Snorm || f == Function::kPack2X16Unorm ||
-           f == Function::kPack2X16Float;
-}
-
-bool IsDataUnpackingBuiltin(Function f) {
-    return f == Function::kUnpack4X8Snorm || f == Function::kUnpack4X8Unorm ||
-           f == Function::kUnpack2X16Snorm || f == Function::kUnpack2X16Unorm ||
-           f == Function::kUnpack2X16Float;
-}
-
-bool IsBarrierBuiltin(Function f) {
-    return f == Function::kWorkgroupBarrier || f == Function::kStorageBarrier ||
-           f == Function::kTextureBarrier;
-}
-
-bool IsAtomicBuiltin(Function f) {
-    return f == Function::kAtomicLoad || f == Function::kAtomicStore ||
-           f == Function::kAtomicAdd || f == Function::kAtomicSub ||
-           f == Function::kAtomicMax || f == Function::kAtomicMin ||
-           f == Function::kAtomicAnd || f == Function::kAtomicOr ||
-           f == Function::kAtomicXor || f == Function::kAtomicExchange ||
-           f == Function::kAtomicCompareExchangeWeak;
-}
-
-bool IsDP4aBuiltin(Function f) {
-    return f == Function::kDot4I8Packed || f == Function::kDot4U8Packed;
-}
-
-bool IsSubgroupBuiltin(Function f) {
-    return f == Function::kSubgroupBallot || f == Function::kSubgroupBroadcast;
-}
-
-bool HasSideEffects(Function f) {
-    switch (f) {
-        case Function::kAtomicAdd:
-        case Function::kAtomicAnd:
-        case Function::kAtomicCompareExchangeWeak:
-        case Function::kAtomicExchange:
-        case Function::kAtomicMax:
-        case Function::kAtomicMin:
-        case Function::kAtomicOr:
-        case Function::kAtomicStore:
-        case Function::kAtomicSub:
-        case Function::kAtomicXor:
-        case Function::kTextureStore:
-        case Function::kWorkgroupUniformLoad:
-            return true;
-        default:
-            break;
-    }
-    return false;
-}
-
-}  // namespace tint::core
diff --git a/src/tint/lang/core/intrinsic/table.cc b/src/tint/lang/core/intrinsic/table.cc
index 221f43b..ce4c23e 100644
--- a/src/tint/lang/core/intrinsic/table.cc
+++ b/src/tint/lang/core/intrinsic/table.cc
@@ -584,7 +584,7 @@
 }  // namespace
 
 Result<Overload> Lookup(Context& context,
-                        core::Function builtin_type,
+                        core::BuiltinFn builtin_type,
                         VectorRef<const core::type::Type*> args,
                         EvaluationStage earliest_eval_stage,
                         const Source& source) {
diff --git a/src/tint/lang/core/intrinsic/table.h b/src/tint/lang/core/intrinsic/table.h
index edae840..1f38b3d 100644
--- a/src/tint/lang/core/intrinsic/table.h
+++ b/src/tint/lang/core/intrinsic/table.h
@@ -19,7 +19,7 @@
 #include <string>
 
 #include "src/tint/lang/core/binary_op.h"
-#include "src/tint/lang/core/function.h"
+#include "src/tint/lang/core/builtin_fn.h"
 #include "src/tint/lang/core/intrinsic/ctor_conv.h"
 #include "src/tint/lang/core/intrinsic/table_data.h"
 #include "src/tint/lang/core/parameter_usage.h"
@@ -110,7 +110,7 @@
 /// @param source the source of the builtin call
 /// @return the resolved builtin function overload
 Result<Overload> Lookup(Context& context,
-                        core::Function builtin_type,
+                        core::BuiltinFn builtin_type,
                         VectorRef<const core::type::Type*> args,
                         EvaluationStage earliest_eval_stage,
                         const Source& source);
diff --git a/src/tint/lang/core/intrinsic/table_test.cc b/src/tint/lang/core/intrinsic/table_test.cc
index c0a3387..7b90ec7 100644
--- a/src/tint/lang/core/intrinsic/table_test.cc
+++ b/src/tint/lang/core/intrinsic/table_test.cc
@@ -56,7 +56,7 @@
 TEST_F(IntrinsicTableTest, MatchF32) {
     auto* f32 = create<core::type::F32>();
     auto result =
-        Lookup(context, core::Function::kCos, Vector{f32}, EvaluationStage::kConstant, Source{});
+        Lookup(context, core::BuiltinFn::kCos, Vector{f32}, EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
     EXPECT_EQ(result->return_type, f32);
@@ -67,7 +67,7 @@
 TEST_F(IntrinsicTableTest, MismatchF32) {
     auto* i32 = create<core::type::I32>();
     auto result =
-        Lookup(context, core::Function::kCos, Vector{i32}, EvaluationStage::kConstant, Source{});
+        Lookup(context, core::BuiltinFn::kCos, Vector{i32}, EvaluationStage::kConstant, Source{});
     ASSERT_FALSE(result);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
 }
@@ -76,7 +76,7 @@
     auto* f32 = create<core::type::F32>();
     auto* u32 = create<core::type::U32>();
     auto* vec2_f32 = create<core::type::Vector>(f32, 2u);
-    auto result = Lookup(context, core::Function::kUnpack2X16Float, Vector{u32},
+    auto result = Lookup(context, core::BuiltinFn::kUnpack2X16Float, Vector{u32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -87,7 +87,7 @@
 
 TEST_F(IntrinsicTableTest, MismatchU32) {
     auto* f32 = create<core::type::F32>();
-    auto result = Lookup(context, core::Function::kUnpack2X16Float, Vector{f32},
+    auto result = Lookup(context, core::BuiltinFn::kUnpack2X16Float, Vector{f32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_FALSE(result);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -98,7 +98,7 @@
     auto* i32 = create<core::type::I32>();
     auto* vec4_f32 = create<core::type::Vector>(f32, 4u);
     auto* tex = create<core::type::SampledTexture>(core::type::TextureDimension::k1d, f32);
-    auto result = Lookup(context, core::Function::kTextureLoad, Vector{tex, i32, i32},
+    auto result = Lookup(context, core::BuiltinFn::kTextureLoad, Vector{tex, i32, i32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -115,7 +115,7 @@
 TEST_F(IntrinsicTableTest, MismatchI32) {
     auto* f32 = create<core::type::F32>();
     auto* tex = create<core::type::SampledTexture>(core::type::TextureDimension::k1d, f32);
-    auto result = Lookup(context, core::Function::kTextureLoad, Vector{tex, f32},
+    auto result = Lookup(context, core::BuiltinFn::kTextureLoad, Vector{tex, f32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_FALSE(result);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -123,7 +123,7 @@
 
 TEST_F(IntrinsicTableTest, MatchIU32AsI32) {
     auto* i32 = create<core::type::I32>();
-    auto result = Lookup(context, core::Function::kCountOneBits, Vector{i32},
+    auto result = Lookup(context, core::BuiltinFn::kCountOneBits, Vector{i32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -134,7 +134,7 @@
 
 TEST_F(IntrinsicTableTest, MatchIU32AsU32) {
     auto* u32 = create<core::type::U32>();
-    auto result = Lookup(context, core::Function::kCountOneBits, Vector{u32},
+    auto result = Lookup(context, core::BuiltinFn::kCountOneBits, Vector{u32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -145,7 +145,7 @@
 
 TEST_F(IntrinsicTableTest, MismatchIU32) {
     auto* f32 = create<core::type::F32>();
-    auto result = Lookup(context, core::Function::kCountOneBits, Vector{f32},
+    auto result = Lookup(context, core::BuiltinFn::kCountOneBits, Vector{f32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_FALSE(result);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -153,7 +153,7 @@
 
 TEST_F(IntrinsicTableTest, MatchFIU32AsI32) {
     auto* i32 = create<core::type::I32>();
-    auto result = Lookup(context, core::Function::kClamp, Vector{i32, i32, i32},
+    auto result = Lookup(context, core::BuiltinFn::kClamp, Vector{i32, i32, i32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -166,7 +166,7 @@
 
 TEST_F(IntrinsicTableTest, MatchFIU32AsU32) {
     auto* u32 = create<core::type::U32>();
-    auto result = Lookup(context, core::Function::kClamp, Vector{u32, u32, u32},
+    auto result = Lookup(context, core::BuiltinFn::kClamp, Vector{u32, u32, u32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -179,7 +179,7 @@
 
 TEST_F(IntrinsicTableTest, MatchFIU32AsF32) {
     auto* f32 = create<core::type::F32>();
-    auto result = Lookup(context, core::Function::kClamp, Vector{f32, f32, f32},
+    auto result = Lookup(context, core::BuiltinFn::kClamp, Vector{f32, f32, f32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -192,7 +192,7 @@
 
 TEST_F(IntrinsicTableTest, MismatchFIU32) {
     auto* bool_ = create<core::type::Bool>();
-    auto result = Lookup(context, core::Function::kClamp, Vector{bool_, bool_, bool_},
+    auto result = Lookup(context, core::BuiltinFn::kClamp, Vector{bool_, bool_, bool_},
                          EvaluationStage::kConstant, Source{});
     ASSERT_FALSE(result);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -201,7 +201,7 @@
 TEST_F(IntrinsicTableTest, MatchBool) {
     auto* f32 = create<core::type::F32>();
     auto* bool_ = create<core::type::Bool>();
-    auto result = Lookup(context, core::Function::kSelect, Vector{f32, f32, bool_},
+    auto result = Lookup(context, core::BuiltinFn::kSelect, Vector{f32, f32, bool_},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -214,7 +214,7 @@
 
 TEST_F(IntrinsicTableTest, MismatchBool) {
     auto* f32 = create<core::type::F32>();
-    auto result = Lookup(context, core::Function::kSelect, Vector{f32, f32, f32},
+    auto result = Lookup(context, core::BuiltinFn::kSelect, Vector{f32, f32, f32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_FALSE(result);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -225,7 +225,7 @@
     auto* atomicI32 = create<core::type::Atomic>(i32);
     auto* ptr = create<core::type::Pointer>(core::AddressSpace::kWorkgroup, atomicI32,
                                             core::Access::kReadWrite);
-    auto result = Lookup(context, core::Function::kAtomicLoad, Vector{ptr},
+    auto result = Lookup(context, core::BuiltinFn::kAtomicLoad, Vector{ptr},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -237,7 +237,7 @@
 TEST_F(IntrinsicTableTest, MismatchPointer) {
     auto* i32 = create<core::type::I32>();
     auto* atomicI32 = create<core::type::Atomic>(i32);
-    auto result = Lookup(context, core::Function::kAtomicLoad, Vector{atomicI32},
+    auto result = Lookup(context, core::BuiltinFn::kAtomicLoad, Vector{atomicI32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_FALSE(result);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -248,7 +248,7 @@
                                           create<core::type::RuntimeArrayCount>(), 4u, 4u, 4u, 4u);
     auto* arr_ptr =
         create<core::type::Pointer>(core::AddressSpace::kStorage, arr, core::Access::kReadWrite);
-    auto result = Lookup(context, core::Function::kArrayLength, Vector{arr_ptr},
+    auto result = Lookup(context, core::BuiltinFn::kArrayLength, Vector{arr_ptr},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -261,7 +261,7 @@
 
 TEST_F(IntrinsicTableTest, MismatchArray) {
     auto* f32 = create<core::type::F32>();
-    auto result = Lookup(context, core::Function::kArrayLength, Vector{f32},
+    auto result = Lookup(context, core::BuiltinFn::kArrayLength, Vector{f32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_FALSE(result);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -273,7 +273,7 @@
     auto* vec4_f32 = create<core::type::Vector>(f32, 4u);
     auto* tex = create<core::type::SampledTexture>(core::type::TextureDimension::k2d, f32);
     auto* sampler = create<core::type::Sampler>(core::type::SamplerKind::kSampler);
-    auto result = Lookup(context, core::Function::kTextureSample, Vector{tex, sampler, vec2_f32},
+    auto result = Lookup(context, core::BuiltinFn::kTextureSample, Vector{tex, sampler, vec2_f32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -291,7 +291,7 @@
     auto* f32 = create<core::type::F32>();
     auto* vec2_f32 = create<core::type::Vector>(f32, 2u);
     auto* tex = create<core::type::SampledTexture>(core::type::TextureDimension::k2d, f32);
-    auto result = Lookup(context, core::Function::kTextureSample, Vector{tex, f32, vec2_f32},
+    auto result = Lookup(context, core::BuiltinFn::kTextureSample, Vector{tex, f32, vec2_f32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_FALSE(result);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -303,7 +303,7 @@
     auto* vec2_i32 = create<core::type::Vector>(i32, 2u);
     auto* vec4_f32 = create<core::type::Vector>(f32, 4u);
     auto* tex = create<core::type::SampledTexture>(core::type::TextureDimension::k2d, f32);
-    auto result = Lookup(context, core::Function::kTextureLoad, Vector{tex, vec2_i32, i32},
+    auto result = Lookup(context, core::BuiltinFn::kTextureLoad, Vector{tex, vec2_i32, i32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -323,7 +323,7 @@
     auto* vec2_i32 = create<core::type::Vector>(i32, 2u);
     auto* vec4_f32 = create<core::type::Vector>(f32, 4u);
     auto* tex = create<core::type::MultisampledTexture>(core::type::TextureDimension::k2d, f32);
-    auto result = Lookup(context, core::Function::kTextureLoad, Vector{tex, vec2_i32, i32},
+    auto result = Lookup(context, core::BuiltinFn::kTextureLoad, Vector{tex, vec2_i32, i32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -342,7 +342,7 @@
     auto* i32 = create<core::type::I32>();
     auto* vec2_i32 = create<core::type::Vector>(i32, 2u);
     auto* tex = create<core::type::DepthTexture>(core::type::TextureDimension::k2d);
-    auto result = Lookup(context, core::Function::kTextureLoad, Vector{tex, vec2_i32, i32},
+    auto result = Lookup(context, core::BuiltinFn::kTextureLoad, Vector{tex, vec2_i32, i32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -361,7 +361,7 @@
     auto* i32 = create<core::type::I32>();
     auto* vec2_i32 = create<core::type::Vector>(i32, 2u);
     auto* tex = create<core::type::DepthMultisampledTexture>(core::type::TextureDimension::k2d);
-    auto result = Lookup(context, core::Function::kTextureLoad, Vector{tex, vec2_i32, i32},
+    auto result = Lookup(context, core::BuiltinFn::kTextureLoad, Vector{tex, vec2_i32, i32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -381,7 +381,7 @@
     auto* vec2_i32 = create<core::type::Vector>(i32, 2u);
     auto* vec4_f32 = create<core::type::Vector>(f32, 4u);
     auto* tex = create<core::type::ExternalTexture>();
-    auto result = Lookup(context, core::Function::kTextureLoad, Vector{tex, vec2_i32},
+    auto result = Lookup(context, core::BuiltinFn::kTextureLoad, Vector{tex, vec2_i32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -403,7 +403,7 @@
                                                    core::TexelFormat::kR32Float,
                                                    core::Access::kWrite, subtype);
 
-    auto result = Lookup(context, core::Function::kTextureStore, Vector{tex, vec2_i32, vec4_f32},
+    auto result = Lookup(context, core::BuiltinFn::kTextureStore, Vector{tex, vec2_i32, vec4_f32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -421,7 +421,7 @@
     auto* f32 = create<core::type::F32>();
     auto* i32 = create<core::type::I32>();
     auto* vec2_i32 = create<core::type::Vector>(i32, 2u);
-    auto result = Lookup(context, core::Function::kTextureLoad, Vector{f32, vec2_i32},
+    auto result = Lookup(context, core::BuiltinFn::kTextureLoad, Vector{f32, vec2_i32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_FALSE(result);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -429,7 +429,7 @@
 
 TEST_F(IntrinsicTableTest, ImplicitLoadOnReference) {
     auto* f32 = create<core::type::F32>();
-    auto result = Lookup(context, core::Function::kCos,
+    auto result = Lookup(context, core::BuiltinFn::kCos,
                          Vector{
                              create<core::type::Reference>(core::AddressSpace::kFunction, f32,
                                                            core::Access::kReadWrite),
@@ -444,7 +444,7 @@
 
 TEST_F(IntrinsicTableTest, MatchTemplateType) {
     auto* f32 = create<core::type::F32>();
-    auto result = Lookup(context, core::Function::kClamp, Vector{f32, f32, f32},
+    auto result = Lookup(context, core::BuiltinFn::kClamp, Vector{f32, f32, f32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -457,7 +457,7 @@
 TEST_F(IntrinsicTableTest, MismatchTemplateType) {
     auto* f32 = create<core::type::F32>();
     auto* u32 = create<core::type::U32>();
-    auto result = Lookup(context, core::Function::kClamp, Vector{f32, u32, f32},
+    auto result = Lookup(context, core::BuiltinFn::kClamp, Vector{f32, u32, f32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_FALSE(result);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -466,7 +466,7 @@
 TEST_F(IntrinsicTableTest, MatchOpenSizeVector) {
     auto* f32 = create<core::type::F32>();
     auto* vec2_f32 = create<core::type::Vector>(f32, 2u);
-    auto result = Lookup(context, core::Function::kClamp, Vector{vec2_f32, vec2_f32, vec2_f32},
+    auto result = Lookup(context, core::BuiltinFn::kClamp, Vector{vec2_f32, vec2_f32, vec2_f32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -481,7 +481,7 @@
     auto* f32 = create<core::type::F32>();
     auto* u32 = create<core::type::U32>();
     auto* vec2_f32 = create<core::type::Vector>(f32, 2u);
-    auto result = Lookup(context, core::Function::kClamp, Vector{vec2_f32, u32, vec2_f32},
+    auto result = Lookup(context, core::BuiltinFn::kClamp, Vector{vec2_f32, u32, vec2_f32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_FALSE(result);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -491,7 +491,7 @@
     auto* f32 = create<core::type::F32>();
     auto* vec3_f32 = create<core::type::Vector>(f32, 3u);
     auto* mat3_f32 = create<core::type::Matrix>(vec3_f32, 3u);
-    auto result = Lookup(context, core::Function::kDeterminant, Vector{mat3_f32},
+    auto result = Lookup(context, core::BuiltinFn::kDeterminant, Vector{mat3_f32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -504,7 +504,7 @@
     auto* f32 = create<core::type::F32>();
     auto* vec2_f32 = create<core::type::Vector>(f32, 2u);
     auto* mat3x2_f32 = create<core::type::Matrix>(vec2_f32, 3u);
-    auto result = Lookup(context, core::Function::kDeterminant, Vector{mat3x2_f32},
+    auto result = Lookup(context, core::BuiltinFn::kDeterminant, Vector{mat3x2_f32},
                          EvaluationStage::kConstant, Source{});
     ASSERT_FALSE(result);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -513,7 +513,7 @@
 TEST_F(IntrinsicTableTest, MatchDifferentArgsElementType_Builtin_ConstantEval) {
     auto* af = create<core::type::AbstractFloat>();
     auto* bool_ = create<core::type::Bool>();
-    auto result = Lookup(context, core::Function::kSelect, Vector{af, af, bool_},
+    auto result = Lookup(context, core::BuiltinFn::kSelect, Vector{af, af, bool_},
                          EvaluationStage::kConstant, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -529,7 +529,7 @@
     auto* af = create<core::type::AbstractFloat>();
     auto* bool_ref = create<core::type::Reference>(
         core::AddressSpace::kFunction, create<core::type::Bool>(), core::Access::kReadWrite);
-    auto result = Lookup(context, core::Function::kSelect, Vector{af, af, bool_ref},
+    auto result = Lookup(context, core::BuiltinFn::kSelect, Vector{af, af, bool_ref},
                          EvaluationStage::kRuntime, Source{});
     ASSERT_TRUE(result) << Diagnostics().str();
     ASSERT_EQ(Diagnostics().str(), "");
@@ -571,7 +571,7 @@
     // None of the arguments match, so expect the overloads with 2 parameters to
     // come first
     auto* bool_ = create<core::type::Bool>();
-    auto result = Lookup(context, core::Function::kTextureDimensions, Vector{bool_, bool_},
+    auto result = Lookup(context, core::BuiltinFn::kTextureDimensions, Vector{bool_, bool_},
                          EvaluationStage::kConstant, Source{});
     EXPECT_FALSE(result);
     ASSERT_EQ(Diagnostics().str(),
@@ -611,7 +611,7 @@
 TEST_F(IntrinsicTableTest, OverloadOrderByMatchingParameter) {
     auto* tex = create<core::type::DepthTexture>(core::type::TextureDimension::k2d);
     auto* bool_ = create<core::type::Bool>();
-    auto result = Lookup(context, core::Function::kTextureDimensions, Vector{tex, bool_},
+    auto result = Lookup(context, core::BuiltinFn::kTextureDimensions, Vector{tex, bool_},
                          EvaluationStage::kConstant, Source{});
     EXPECT_FALSE(result);
     ASSERT_EQ(Diagnostics().str(),
@@ -980,7 +980,7 @@
     auto* f32 = create<core::type::F32>();
     Vector<const core::type::Type*, 0> arg_tys;
     arg_tys.Resize(257, f32);
-    auto result = Lookup(context, core::Function::kAbs, std::move(arg_tys),
+    auto result = Lookup(context, core::BuiltinFn::kAbs, std::move(arg_tys),
                          EvaluationStage::kConstant, Source{});
     ASSERT_FALSE(result);
     ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
@@ -1221,7 +1221,7 @@
     auto* arg_a = GetParam().arg_a(*this);
     auto* arg_b = GetParam().arg_b(*this);
     auto* arg_c = GetParam().arg_c(*this);
-    auto builtin = Lookup(context, core::Function::kClamp, Vector{arg_a, arg_b, arg_c},
+    auto builtin = Lookup(context, core::BuiltinFn::kClamp, Vector{arg_a, arg_b, arg_c},
                           EvaluationStage::kConstant, Source{{12, 34}});
 
     bool expected_match = GetParam().expected_match;
diff --git a/src/tint/lang/core/ir/builder.h b/src/tint/lang/core/ir/builder.h
index 7088ee0..76de594 100644
--- a/src/tint/lang/core/ir/builder.h
+++ b/src/tint/lang/core/ir/builder.h
@@ -672,7 +672,7 @@
     /// @param args the call arguments
     /// @returns the instruction
     template <typename... ARGS>
-    ir::CoreBuiltinCall* Call(const core::type::Type* type, core::Function func, ARGS&&... args) {
+    ir::CoreBuiltinCall* Call(const core::type::Type* type, core::BuiltinFn func, ARGS&&... args) {
         return Append(ir.instructions.Create<ir::CoreBuiltinCall>(
             InstructionResult(type), func, Values(std::forward<ARGS>(args)...)));
     }
diff --git a/src/tint/lang/core/ir/core_builtin_call.cc b/src/tint/lang/core/ir/core_builtin_call.cc
index ada7835..86325ac 100644
--- a/src/tint/lang/core/ir/core_builtin_call.cc
+++ b/src/tint/lang/core/ir/core_builtin_call.cc
@@ -25,11 +25,11 @@
 namespace tint::core::ir {
 
 CoreBuiltinCall::CoreBuiltinCall(InstructionResult* result,
-                                 core::Function func,
+                                 core::BuiltinFn func,
                                  VectorRef<Value*> arguments)
     : Base(result, arguments), func_(func) {
-    TINT_ASSERT(func != core::Function::kNone);
-    TINT_ASSERT(func != core::Function::kTintMaterialize);
+    TINT_ASSERT(func != core::BuiltinFn::kNone);
+    TINT_ASSERT(func != core::BuiltinFn::kTintMaterialize);
 }
 
 CoreBuiltinCall::~CoreBuiltinCall() = default;
diff --git a/src/tint/lang/core/ir/core_builtin_call.h b/src/tint/lang/core/ir/core_builtin_call.h
index c887b4b..24c998d 100644
--- a/src/tint/lang/core/ir/core_builtin_call.h
+++ b/src/tint/lang/core/ir/core_builtin_call.h
@@ -17,7 +17,7 @@
 
 #include <string>
 
-#include "src/tint/lang/core/function.h"
+#include "src/tint/lang/core/builtin_fn.h"
 #include "src/tint/lang/core/intrinsic/data/data.h"
 #include "src/tint/lang/core/intrinsic/table_data.h"
 #include "src/tint/lang/core/ir/builtin_call.h"
@@ -33,7 +33,7 @@
     /// @param func the builtin function
     /// @param args the conversion arguments
     CoreBuiltinCall(InstructionResult* result,
-                    core::Function func,
+                    core::BuiltinFn func,
                     VectorRef<Value*> args = tint::Empty);
     ~CoreBuiltinCall() override;
 
@@ -41,7 +41,7 @@
     CoreBuiltinCall* Clone(CloneContext& ctx) override;
 
     /// @returns the builtin function
-    core::Function Func() { return func_; }
+    core::BuiltinFn Func() { return func_; }
 
     /// @returns the identifier for the function
     size_t FuncId() override { return static_cast<size_t>(func_); }
@@ -56,7 +56,7 @@
     const core::intrinsic::TableData& TableData() override { return core::intrinsic::data::kData; }
 
   private:
-    core::Function func_;
+    core::BuiltinFn func_;
 };
 
 }  // namespace tint::core::ir
diff --git a/src/tint/lang/core/ir/core_builtin_call_test.cc b/src/tint/lang/core/ir/core_builtin_call_test.cc
index e05e564..290af5a 100644
--- a/src/tint/lang/core/ir/core_builtin_call_test.cc
+++ b/src/tint/lang/core/ir/core_builtin_call_test.cc
@@ -26,7 +26,7 @@
 TEST_F(IR_CoreBuiltinCallTest, Usage) {
     auto* arg1 = b.Constant(1_u);
     auto* arg2 = b.Constant(2_u);
-    auto* builtin = b.Call(mod.Types().f32(), core::Function::kAbs, arg1, arg2);
+    auto* builtin = b.Call(mod.Types().f32(), core::BuiltinFn::kAbs, arg1, arg2);
 
     EXPECT_THAT(arg1->Usages(), testing::UnorderedElementsAre(Usage{builtin, 0u}));
     EXPECT_THAT(arg2->Usages(), testing::UnorderedElementsAre(Usage{builtin, 1u}));
@@ -35,7 +35,7 @@
 TEST_F(IR_CoreBuiltinCallTest, Result) {
     auto* arg1 = b.Constant(1_u);
     auto* arg2 = b.Constant(2_u);
-    auto* builtin = b.Call(mod.Types().f32(), core::Function::kAbs, arg1, arg2);
+    auto* builtin = b.Call(mod.Types().f32(), core::BuiltinFn::kAbs, arg1, arg2);
 
     EXPECT_TRUE(builtin->HasResults());
     EXPECT_FALSE(builtin->HasMultiResults());
@@ -48,7 +48,7 @@
         {
             Module mod;
             Builder b{mod};
-            b.Call(nullptr, core::Function::kAbs);
+            b.Call(nullptr, core::BuiltinFn::kAbs);
         },
         "");
 }
@@ -58,7 +58,7 @@
         {
             Module mod;
             Builder b{mod};
-            b.Call(mod.Types().f32(), core::Function::kNone);
+            b.Call(mod.Types().f32(), core::BuiltinFn::kNone);
         },
         "");
 }
@@ -68,13 +68,13 @@
         {
             Module mod;
             Builder b{mod};
-            b.Call(mod.Types().f32(), core::Function::kTintMaterialize);
+            b.Call(mod.Types().f32(), core::BuiltinFn::kTintMaterialize);
         },
         "");
 }
 
 TEST_F(IR_CoreBuiltinCallTest, Clone) {
-    auto* builtin = b.Call(mod.Types().f32(), core::Function::kAbs, 1_u, 2_u);
+    auto* builtin = b.Call(mod.Types().f32(), core::BuiltinFn::kAbs, 1_u, 2_u);
 
     auto* new_b = clone_ctx.Clone(builtin);
 
@@ -82,7 +82,7 @@
     EXPECT_NE(builtin->Result(), new_b->Result());
     EXPECT_EQ(mod.Types().f32(), new_b->Result()->Type());
 
-    EXPECT_EQ(core::Function::kAbs, new_b->Func());
+    EXPECT_EQ(core::BuiltinFn::kAbs, new_b->Func());
 
     auto args = new_b->Args();
     EXPECT_EQ(2u, args.Length());
@@ -95,13 +95,13 @@
 }
 
 TEST_F(IR_CoreBuiltinCallTest, CloneNoArgs) {
-    auto* builtin = b.Call(mod.Types().f32(), core::Function::kAbs);
+    auto* builtin = b.Call(mod.Types().f32(), core::BuiltinFn::kAbs);
 
     auto* new_b = clone_ctx.Clone(builtin);
     EXPECT_NE(builtin->Result(), new_b->Result());
     EXPECT_EQ(mod.Types().f32(), new_b->Result()->Type());
 
-    EXPECT_EQ(core::Function::kAbs, new_b->Func());
+    EXPECT_EQ(core::BuiltinFn::kAbs, new_b->Func());
 
     auto args = new_b->Args();
     EXPECT_TRUE(args.IsEmpty());
diff --git a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc
index d4fcbf2..4acfbfb 100644
--- a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc
+++ b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill.cc
@@ -140,7 +140,7 @@
                 [&](CoreBuiltinCall* call) {
                     // Replace arguments to builtin functions and add swizzles if necessary.
                     call->SetOperand(use.operand_index, new_value);
-                    if (call->Func() == core::Function::kTextureStore) {
+                    if (call->Func() == core::BuiltinFn::kTextureStore) {
                         // Swizzle the value argument of a `textureStore()` builtin.
                         auto* tex = old_value->Type()->As<core::type::StorageTexture>();
                         auto index = core::type::IsTextureArray(tex->dim()) ? 3u : 2u;
@@ -148,7 +148,7 @@
                         auto* swizzle = b.Swizzle(value->Type(), value, Vector{2u, 1u, 0u, 3u});
                         swizzle->InsertBefore(call);
                         call->SetOperand(index, swizzle->Result());
-                    } else if (call->Func() == core::Function::kTextureLoad) {
+                    } else if (call->Func() == core::BuiltinFn::kTextureLoad) {
                         // Swizzle the result of a `textureLoad()` builtin.
                         auto* swizzle =
                             b.Swizzle(call->Result()->Type(), nullptr, Vector{2u, 1u, 0u, 3u});
diff --git a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc
index e8d19a3..aab9aa5 100644
--- a/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc
+++ b/src/tint/lang/core/ir/transform/bgra8unorm_polyfill_test.cc
@@ -60,7 +60,7 @@
     func->SetParams({value, coords});
     b.Append(func->Block(), [&] {
         auto* load = b.Load(var->Result());
-        b.Call(ty.void_(), core::Function::kTextureStore, load, coords, value);
+        b.Call(ty.void_(), core::BuiltinFn::kTextureStore, load, coords, value);
         b.Return(func);
     });
 
@@ -97,7 +97,7 @@
     auto* value = b.FunctionParam("value", ty.vec4<f32>());
     func->SetParams({texture, coords, value});
     b.Append(func->Block(), [&] {
-        b.Call(ty.void_(), core::Function::kTextureStore, texture, coords, value);
+        b.Call(ty.void_(), core::BuiltinFn::kTextureStore, texture, coords, value);
         b.Return(func);
     });
 
@@ -133,7 +133,7 @@
     func->SetParams({value, coords});
     b.Append(func->Block(), [&] {
         auto* load = b.Load(var->Result());
-        b.Call(ty.void_(), core::Function::kTextureStore, load, coords, value);
+        b.Call(ty.void_(), core::BuiltinFn::kTextureStore, load, coords, value);
         b.Return(func);
     });
 
@@ -183,7 +183,7 @@
     auto* value = b.FunctionParam("value", ty.vec4<f32>());
     func->SetParams({texture, coords, value});
     b.Append(func->Block(), [&] {
-        b.Call(ty.void_(), core::Function::kTextureStore, texture, coords, value);
+        b.Call(ty.void_(), core::BuiltinFn::kTextureStore, texture, coords, value);
         b.Return(func);
     });
 
@@ -228,7 +228,7 @@
         auto* value = b.FunctionParam("value", ty.vec4<f32>());
         bar->SetParams({texture, coords, value});
         b.Append(bar->Block(), [&] {
-            b.Call(ty.void_(), core::Function::kTextureStore, texture, coords, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, texture, coords, value);
             b.Return(bar);
         });
     }
@@ -316,9 +316,9 @@
         auto* value = b.FunctionParam("value", ty.vec4<f32>());
         bar->SetParams({texture_a, texture_b, texture_c, coords, value});
         b.Append(bar->Block(), [&] {
-            b.Call(ty.void_(), core::Function::kTextureStore, texture_a, coords, value);
-            b.Call(ty.void_(), core::Function::kTextureStore, texture_b, coords, value);
-            b.Call(ty.void_(), core::Function::kTextureStore, texture_c, coords, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, texture_a, coords, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, texture_b, coords, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, texture_c, coords, value);
             b.Return(bar);
         });
     }
@@ -414,9 +414,9 @@
         auto* value = b.FunctionParam("value", ty.vec4<f32>());
         bar->SetParams({texture, coords, value});
         b.Append(bar->Block(), [&] {
-            b.Call(ty.void_(), core::Function::kTextureStore, texture, coords, value);
-            b.Call(ty.void_(), core::Function::kTextureStore, texture, coords, value);
-            b.Call(ty.void_(), core::Function::kTextureStore, texture, coords, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, texture, coords, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, texture, coords, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, texture, coords, value);
             b.Return(bar);
         });
     }
@@ -428,7 +428,7 @@
         foo->SetParams({coords, value});
         b.Append(foo->Block(), [&] {
             auto* load_a = b.Load(var_a->Result());
-            b.Call(ty.void_(), core::Function::kTextureStore, load_a, coords, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, load_a, coords, value);
             auto* load_b = b.Load(var_a->Result());
             b.Call(ty.void_(), bar, load_b, coords, value);
             auto* load_c = b.Load(var_a->Result());
@@ -515,7 +515,7 @@
     func->SetParams({value, coords});
     b.Append(func->Block(), [&] {
         auto* load = b.Load(var->Result());
-        b.Call(ty.void_(), core::Function::kTextureStore, load, coords, index, value);
+        b.Call(ty.void_(), core::BuiltinFn::kTextureStore, load, coords, index, value);
         b.Return(func);
     });
 
@@ -566,7 +566,7 @@
     auto* func = b.Function("foo", ty.vec2<u32>());
     b.Append(func->Block(), [&] {
         auto* load = b.Load(var->Result());
-        auto* dims = b.Call(ty.vec2<u32>(), core::Function::kTextureDimensions, load);
+        auto* dims = b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, load);
         b.Return(func, dims);
         mod.SetName(dims, "dims");
     });
@@ -619,7 +619,7 @@
     func->SetParams({coords});
     b.Append(func->Block(), [&] {
         auto* load = b.Load(var->Result());
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, load, coords);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, load, coords);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -673,8 +673,8 @@
     func->SetParams({coords});
     b.Append(func->Block(), [&] {
         auto* load = b.Load(var->Result());
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, load, coords);
-        b.Call(ty.void_(), core::Function::kTextureStore, load, coords, result);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, load, coords);
+        b.Call(ty.void_(), core::BuiltinFn::kTextureStore, load, coords, result);
         b.Return(func);
         mod.SetName(result, "result");
     });
diff --git a/src/tint/lang/core/ir/transform/binary_polyfill.cc b/src/tint/lang/core/ir/transform/binary_polyfill.cc
index fcf6b7e..e4bed28 100644
--- a/src/tint/lang/core/ir/transform/binary_polyfill.cc
+++ b/src/tint/lang/core/ir/transform/binary_polyfill.cc
@@ -180,7 +180,7 @@
                     auto* rhs_is_minus_one = b.Equal(bool_ty, rhs, minus_one);
                     cond = b.Or(bool_ty, cond, b.And(bool_ty, lhs_is_lowest, rhs_is_minus_one));
                 }
-                auto* rhs_or_one = b.Call(result_ty, core::Function::kSelect, rhs, one, cond);
+                auto* rhs_or_one = b.Call(result_ty, core::BuiltinFn::kSelect, rhs, one, cond);
 
                 if (binary->Kind() == Binary::Kind::kDivide) {
                     // Perform the divide with the modified RHS.
diff --git a/src/tint/lang/core/ir/transform/builtin_polyfill.cc b/src/tint/lang/core/ir/transform/builtin_polyfill.cc
index d8dc094..e5d13d8 100644
--- a/src/tint/lang/core/ir/transform/builtin_polyfill.cc
+++ b/src/tint/lang/core/ir/transform/builtin_polyfill.cc
@@ -55,32 +55,32 @@
             }
             if (auto* builtin = inst->As<ir::CoreBuiltinCall>()) {
                 switch (builtin->Func()) {
-                    case core::Function::kCountLeadingZeros:
+                    case core::BuiltinFn::kCountLeadingZeros:
                         if (config.count_leading_zeros) {
                             worklist.Push(builtin);
                         }
                         break;
-                    case core::Function::kCountTrailingZeros:
+                    case core::BuiltinFn::kCountTrailingZeros:
                         if (config.count_trailing_zeros) {
                             worklist.Push(builtin);
                         }
                         break;
-                    case core::Function::kFirstLeadingBit:
+                    case core::BuiltinFn::kFirstLeadingBit:
                         if (config.first_leading_bit) {
                             worklist.Push(builtin);
                         }
                         break;
-                    case core::Function::kFirstTrailingBit:
+                    case core::BuiltinFn::kFirstTrailingBit:
                         if (config.first_trailing_bit) {
                             worklist.Push(builtin);
                         }
                         break;
-                    case core::Function::kSaturate:
+                    case core::BuiltinFn::kSaturate:
                         if (config.saturate) {
                             worklist.Push(builtin);
                         }
                         break;
-                    case core::Function::kTextureSampleBaseClampToEdge:
+                    case core::BuiltinFn::kTextureSampleBaseClampToEdge:
                         if (config.texture_sample_base_clamp_to_edge_2d_f32) {
                             auto* tex =
                                 builtin->Args()[0]->Type()->As<core::type::SampledTexture>();
@@ -100,22 +100,22 @@
         for (auto* builtin : worklist) {
             ir::Value* replacement = nullptr;
             switch (builtin->Func()) {
-                case core::Function::kCountLeadingZeros:
+                case core::BuiltinFn::kCountLeadingZeros:
                     replacement = CountLeadingZeros(builtin);
                     break;
-                case core::Function::kCountTrailingZeros:
+                case core::BuiltinFn::kCountTrailingZeros:
                     replacement = CountTrailingZeros(builtin);
                     break;
-                case core::Function::kFirstLeadingBit:
+                case core::BuiltinFn::kFirstLeadingBit:
                     replacement = FirstLeadingBit(builtin);
                     break;
-                case core::Function::kFirstTrailingBit:
+                case core::BuiltinFn::kFirstTrailingBit:
                     replacement = FirstTrailingBit(builtin);
                     break;
-                case core::Function::kSaturate:
+                case core::BuiltinFn::kSaturate:
                     replacement = Saturate(builtin);
                     break;
-                case core::Function::kTextureSampleBaseClampToEdge:
+                case core::BuiltinFn::kTextureSampleBaseClampToEdge:
                     replacement = TextureSampleBaseClampToEdge_2d_f32(builtin);
                     break;
                 default:
@@ -191,22 +191,22 @@
             if (result_ty->is_signed_integer_scalar_or_vector()) {
                 x = b.Bitcast(uint_ty, x)->Result();
             }
-            auto* b16 = b.Call(uint_ty, core::Function::kSelect, V(0), V(16),
+            auto* b16 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(16),
                                b.LessThanEqual(bool_ty, x, V(0x0000ffff)));
             x = b.ShiftLeft(uint_ty, x, b16)->Result();
-            auto* b8 = b.Call(uint_ty, core::Function::kSelect, V(0), V(8),
+            auto* b8 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(8),
                               b.LessThanEqual(bool_ty, x, V(0x00ffffff)));
             x = b.ShiftLeft(uint_ty, x, b8)->Result();
-            auto* b4 = b.Call(uint_ty, core::Function::kSelect, V(0), V(4),
+            auto* b4 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(4),
                               b.LessThanEqual(bool_ty, x, V(0x0fffffff)));
             x = b.ShiftLeft(uint_ty, x, b4)->Result();
-            auto* b2 = b.Call(uint_ty, core::Function::kSelect, V(0), V(2),
+            auto* b2 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(2),
                               b.LessThanEqual(bool_ty, x, V(0x3fffffff)));
             x = b.ShiftLeft(uint_ty, x, b2)->Result();
-            auto* b1 = b.Call(uint_ty, core::Function::kSelect, V(0), V(1),
+            auto* b1 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(1),
                               b.LessThanEqual(bool_ty, x, V(0x7fffffff)));
             auto* b0 =
-                b.Call(uint_ty, core::Function::kSelect, V(0), V(1), b.Equal(bool_ty, x, V(0)));
+                b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(1), b.Equal(bool_ty, x, V(0)));
             result = b.Add(uint_ty,
                            b.Or(uint_ty, b16,
                                 b.Or(uint_ty, b8,
@@ -254,22 +254,22 @@
             if (result_ty->is_signed_integer_scalar_or_vector()) {
                 x = b.Bitcast(uint_ty, x)->Result();
             }
-            auto* b16 = b.Call(uint_ty, core::Function::kSelect, V(0), V(16),
+            auto* b16 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(16),
                                b.Equal(bool_ty, b.And(uint_ty, x, V(0x0000ffff)), V(0)));
             x = b.ShiftRight(uint_ty, x, b16)->Result();
-            auto* b8 = b.Call(uint_ty, core::Function::kSelect, V(0), V(8),
+            auto* b8 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(8),
                               b.Equal(bool_ty, b.And(uint_ty, x, V(0x000000ff)), V(0)));
             x = b.ShiftRight(uint_ty, x, b8)->Result();
-            auto* b4 = b.Call(uint_ty, core::Function::kSelect, V(0), V(4),
+            auto* b4 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(4),
                               b.Equal(bool_ty, b.And(uint_ty, x, V(0x0000000f)), V(0)));
             x = b.ShiftRight(uint_ty, x, b4)->Result();
-            auto* b2 = b.Call(uint_ty, core::Function::kSelect, V(0), V(2),
+            auto* b2 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(2),
                               b.Equal(bool_ty, b.And(uint_ty, x, V(0x00000003)), V(0)));
             x = b.ShiftRight(uint_ty, x, b2)->Result();
-            auto* b1 = b.Call(uint_ty, core::Function::kSelect, V(0), V(1),
+            auto* b1 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(1),
                               b.Equal(bool_ty, b.And(uint_ty, x, V(0x00000001)), V(0)));
             auto* b0 =
-                b.Call(uint_ty, core::Function::kSelect, V(0), V(1), b.Equal(bool_ty, x, V(0)));
+                b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(1), b.Equal(bool_ty, x, V(0)));
             result = b.Add(uint_ty,
                            b.Or(uint_ty, b16,
                                 b.Or(uint_ty, b8, b.Or(uint_ty, b4, b.Or(uint_ty, b2, b1)))),
@@ -316,27 +316,27 @@
             if (result_ty->is_signed_integer_scalar_or_vector()) {
                 x = b.Bitcast(uint_ty, x)->Result();
                 auto* inverted = b.Complement(uint_ty, x);
-                x = b.Call(uint_ty, core::Function::kSelect, inverted, x,
+                x = b.Call(uint_ty, core::BuiltinFn::kSelect, inverted, x,
                            b.LessThan(bool_ty, x, V(0x80000000)))
                         ->Result();
             }
-            auto* b16 = b.Call(uint_ty, core::Function::kSelect, V(16), V(0),
+            auto* b16 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(16), V(0),
                                b.Equal(bool_ty, b.And(uint_ty, x, V(0xffff0000)), V(0)));
             x = b.ShiftRight(uint_ty, x, b16)->Result();
-            auto* b8 = b.Call(uint_ty, core::Function::kSelect, V(8), V(0),
+            auto* b8 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(8), V(0),
                               b.Equal(bool_ty, b.And(uint_ty, x, V(0x0000ff00)), V(0)));
             x = b.ShiftRight(uint_ty, x, b8)->Result();
-            auto* b4 = b.Call(uint_ty, core::Function::kSelect, V(4), V(0),
+            auto* b4 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(4), V(0),
                               b.Equal(bool_ty, b.And(uint_ty, x, V(0x000000f0)), V(0)));
             x = b.ShiftRight(uint_ty, x, b4)->Result();
-            auto* b2 = b.Call(uint_ty, core::Function::kSelect, V(2), V(0),
+            auto* b2 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(2), V(0),
                               b.Equal(bool_ty, b.And(uint_ty, x, V(0x0000000c)), V(0)));
             x = b.ShiftRight(uint_ty, x, b2)->Result();
-            auto* b1 = b.Call(uint_ty, core::Function::kSelect, V(1), V(0),
+            auto* b1 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(1), V(0),
                               b.Equal(bool_ty, b.And(uint_ty, x, V(0x00000002)), V(0)));
             result = b.Or(uint_ty, b16, b.Or(uint_ty, b8, b.Or(uint_ty, b4, b.Or(uint_ty, b2, b1))))
                          ->Result();
-            result = b.Call(uint_ty, core::Function::kSelect, result, V(0xffffffff),
+            result = b.Call(uint_ty, core::BuiltinFn::kSelect, result, V(0xffffffff),
                             b.Equal(bool_ty, x, V(0)))
                          ->Result();
             if (result_ty->is_signed_integer_scalar_or_vector()) {
@@ -380,23 +380,23 @@
             if (result_ty->is_signed_integer_scalar_or_vector()) {
                 x = b.Bitcast(uint_ty, x)->Result();
             }
-            auto* b16 = b.Call(uint_ty, core::Function::kSelect, V(0), V(16),
+            auto* b16 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(16),
                                b.Equal(bool_ty, b.And(uint_ty, x, V(0x0000ffff)), V(0)));
             x = b.ShiftRight(uint_ty, x, b16)->Result();
-            auto* b8 = b.Call(uint_ty, core::Function::kSelect, V(0), V(8),
+            auto* b8 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(8),
                               b.Equal(bool_ty, b.And(uint_ty, x, V(0x000000ff)), V(0)));
             x = b.ShiftRight(uint_ty, x, b8)->Result();
-            auto* b4 = b.Call(uint_ty, core::Function::kSelect, V(0), V(4),
+            auto* b4 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(4),
                               b.Equal(bool_ty, b.And(uint_ty, x, V(0x0000000f)), V(0)));
             x = b.ShiftRight(uint_ty, x, b4)->Result();
-            auto* b2 = b.Call(uint_ty, core::Function::kSelect, V(0), V(2),
+            auto* b2 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(2),
                               b.Equal(bool_ty, b.And(uint_ty, x, V(0x00000003)), V(0)));
             x = b.ShiftRight(uint_ty, x, b2)->Result();
-            auto* b1 = b.Call(uint_ty, core::Function::kSelect, V(0), V(1),
+            auto* b1 = b.Call(uint_ty, core::BuiltinFn::kSelect, V(0), V(1),
                               b.Equal(bool_ty, b.And(uint_ty, x, V(0x00000001)), V(0)));
             result = b.Or(uint_ty, b16, b.Or(uint_ty, b8, b.Or(uint_ty, b4, b.Or(uint_ty, b2, b1))))
                          ->Result();
-            result = b.Call(uint_ty, core::Function::kSelect, result, V(0xffffffff),
+            result = b.Call(uint_ty, core::BuiltinFn::kSelect, result, V(0xffffffff),
                             b.Equal(bool_ty, x, V(0)))
                          ->Result();
             if (result_ty->is_signed_integer_scalar_or_vector()) {
@@ -421,7 +421,7 @@
             zero = MatchWidth(b.Constant(0_h), type);
             one = MatchWidth(b.Constant(1_h), type);
         }
-        auto* clamp = b.Call(type, core::Function::kClamp, Vector{call->Args()[0], zero, one});
+        auto* clamp = b.Call(type, core::BuiltinFn::kClamp, Vector{call->Args()[0], zero, one});
         clamp->InsertBefore(call);
         return clamp->Result();
     }
@@ -441,13 +441,13 @@
         auto* coords = call->Args()[2];
         b.InsertBefore(call, [&] {
             auto* vec2f = ty.vec2<f32>();
-            auto* dims = b.Call(ty.vec2<u32>(), core::Function::kTextureDimensions, texture);
+            auto* dims = b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, texture);
             auto* fdims = b.Convert(vec2f, dims);
             auto* half_texel = b.Divide(vec2f, b.Splat(vec2f, 0.5_f, 2), fdims);
             auto* one_minus_half_texel = b.Subtract(vec2f, b.Splat(vec2f, 1_f, 2), half_texel);
             auto* clamped =
-                b.Call(vec2f, core::Function::kClamp, coords, half_texel, one_minus_half_texel);
-            result = b.Call(ty.vec4<f32>(), core::Function::kTextureSampleLevel, texture, sampler,
+                b.Call(vec2f, core::BuiltinFn::kClamp, coords, half_texel, one_minus_half_texel);
+            result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleLevel, texture, sampler,
                             clamped, 0_f)
                          ->Result();
         });
diff --git a/src/tint/lang/core/ir/transform/builtin_polyfill_test.cc b/src/tint/lang/core/ir/transform/builtin_polyfill_test.cc
index a89ed53..869c89c 100644
--- a/src/tint/lang/core/ir/transform/builtin_polyfill_test.cc
+++ b/src/tint/lang/core/ir/transform/builtin_polyfill_test.cc
@@ -31,7 +31,7 @@
     /// @param builtin the builtin to call
     /// @param result_ty the result type of the builtin call
     /// @param arg_types the arguments types for the builtin call
-    void Build(core::Function builtin,
+    void Build(core::BuiltinFn builtin,
                const core::type::Type* result_ty,
                VectorRef<const core::type::Type*> arg_types) {
         Vector<FunctionParam*, 4> args;
@@ -49,7 +49,7 @@
 };
 
 TEST_F(IR_BuiltinPolyfillTest, Saturate_NoPolyfill) {
-    Build(core::Function::kSaturate, ty.f32(), Vector{ty.f32()});
+    Build(core::BuiltinFn::kSaturate, ty.f32(), Vector{ty.f32()});
     auto* src = R"(
 %foo = func(%arg:f32):f32 -> %b1 {
   %b1 = block {
@@ -69,7 +69,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, Saturate_F32) {
-    Build(core::Function::kSaturate, ty.f32(), Vector{ty.f32()});
+    Build(core::BuiltinFn::kSaturate, ty.f32(), Vector{ty.f32()});
     auto* src = R"(
 %foo = func(%arg:f32):f32 -> %b1 {
   %b1 = block {
@@ -96,7 +96,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, Saturate_F16) {
-    Build(core::Function::kSaturate, ty.f16(), Vector{ty.f16()});
+    Build(core::BuiltinFn::kSaturate, ty.f16(), Vector{ty.f16()});
     auto* src = R"(
 %foo = func(%arg:f16):f16 -> %b1 {
   %b1 = block {
@@ -122,7 +122,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, Saturate_Vec2F32) {
-    Build(core::Function::kSaturate, ty.vec2<f32>(), Vector{ty.vec2<f32>()});
+    Build(core::BuiltinFn::kSaturate, ty.vec2<f32>(), Vector{ty.vec2<f32>()});
     auto* src = R"(
 %foo = func(%arg:vec2<f32>):vec2<f32> -> %b1 {
   %b1 = block {
@@ -149,7 +149,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, Saturate_Vec4F16) {
-    Build(core::Function::kSaturate, ty.vec4<f16>(), Vector{ty.vec4<f16>()});
+    Build(core::BuiltinFn::kSaturate, ty.vec4<f16>(), Vector{ty.vec4<f16>()});
     auto* src = R"(
 %foo = func(%arg:vec4<f16>):vec4<f16> -> %b1 {
   %b1 = block {
@@ -176,7 +176,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, CountLeadingZeros_NoPolyfill) {
-    Build(core::Function::kCountLeadingZeros, ty.u32(), Vector{ty.u32()});
+    Build(core::BuiltinFn::kCountLeadingZeros, ty.u32(), Vector{ty.u32()});
     auto* src = R"(
 %foo = func(%arg:u32):u32 -> %b1 {
   %b1 = block {
@@ -196,7 +196,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, CountLeadingZeros_U32) {
-    Build(core::Function::kCountLeadingZeros, ty.u32(), Vector{ty.u32()});
+    Build(core::BuiltinFn::kCountLeadingZeros, ty.u32(), Vector{ty.u32()});
     auto* src = R"(
 %foo = func(%arg:u32):u32 -> %b1 {
   %b1 = block {
@@ -244,7 +244,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, CountLeadingZeros_I32) {
-    Build(core::Function::kCountLeadingZeros, ty.i32(), Vector{ty.i32()});
+    Build(core::BuiltinFn::kCountLeadingZeros, ty.i32(), Vector{ty.i32()});
     auto* src = R"(
 %foo = func(%arg:i32):i32 -> %b1 {
   %b1 = block {
@@ -294,7 +294,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, CountLeadingZeros_Vec2U32) {
-    Build(core::Function::kCountLeadingZeros, ty.vec2<u32>(), Vector{ty.vec2<u32>()});
+    Build(core::BuiltinFn::kCountLeadingZeros, ty.vec2<u32>(), Vector{ty.vec2<u32>()});
     auto* src = R"(
 %foo = func(%arg:vec2<u32>):vec2<u32> -> %b1 {
   %b1 = block {
@@ -342,7 +342,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, CountLeadingZeros_Vec4I32) {
-    Build(core::Function::kCountLeadingZeros, ty.vec4<i32>(), Vector{ty.vec4<i32>()});
+    Build(core::BuiltinFn::kCountLeadingZeros, ty.vec4<i32>(), Vector{ty.vec4<i32>()});
     auto* src = R"(
 %foo = func(%arg:vec4<i32>):vec4<i32> -> %b1 {
   %b1 = block {
@@ -392,7 +392,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, CountTrailingZeros_NoPolyfill) {
-    Build(core::Function::kCountTrailingZeros, ty.u32(), Vector{ty.u32()});
+    Build(core::BuiltinFn::kCountTrailingZeros, ty.u32(), Vector{ty.u32()});
     auto* src = R"(
 %foo = func(%arg:u32):u32 -> %b1 {
   %b1 = block {
@@ -412,7 +412,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, CountTrailingZeros_U32) {
-    Build(core::Function::kCountTrailingZeros, ty.u32(), Vector{ty.u32()});
+    Build(core::BuiltinFn::kCountTrailingZeros, ty.u32(), Vector{ty.u32()});
     auto* src = R"(
 %foo = func(%arg:u32):u32 -> %b1 {
   %b1 = block {
@@ -464,7 +464,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, CountTrailingZeros_I32) {
-    Build(core::Function::kCountTrailingZeros, ty.i32(), Vector{ty.i32()});
+    Build(core::BuiltinFn::kCountTrailingZeros, ty.i32(), Vector{ty.i32()});
     auto* src = R"(
 %foo = func(%arg:i32):i32 -> %b1 {
   %b1 = block {
@@ -518,7 +518,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, CountTrailingZeros_Vec2U32) {
-    Build(core::Function::kCountTrailingZeros, ty.vec2<u32>(), Vector{ty.vec2<u32>()});
+    Build(core::BuiltinFn::kCountTrailingZeros, ty.vec2<u32>(), Vector{ty.vec2<u32>()});
     auto* src = R"(
 %foo = func(%arg:vec2<u32>):vec2<u32> -> %b1 {
   %b1 = block {
@@ -570,7 +570,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, CountTrailingZeros_Vec4I32) {
-    Build(core::Function::kCountTrailingZeros, ty.vec4<i32>(), Vector{ty.vec4<i32>()});
+    Build(core::BuiltinFn::kCountTrailingZeros, ty.vec4<i32>(), Vector{ty.vec4<i32>()});
     auto* src = R"(
 %foo = func(%arg:vec4<i32>):vec4<i32> -> %b1 {
   %b1 = block {
@@ -597,7 +597,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, FirstLeadingBit_NoPolyfill) {
-    Build(core::Function::kFirstLeadingBit, ty.u32(), Vector{ty.u32()});
+    Build(core::BuiltinFn::kFirstLeadingBit, ty.u32(), Vector{ty.u32()});
     auto* src = R"(
 %foo = func(%arg:u32):u32 -> %b1 {
   %b1 = block {
@@ -617,7 +617,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, FirstLeadingBit_U32) {
-    Build(core::Function::kFirstLeadingBit, ty.u32(), Vector{ty.u32()});
+    Build(core::BuiltinFn::kFirstLeadingBit, ty.u32(), Vector{ty.u32()});
     auto* src = R"(
 %foo = func(%arg:u32):u32 -> %b1 {
   %b1 = block {
@@ -668,7 +668,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, FirstLeadingBit_I32) {
-    Build(core::Function::kFirstLeadingBit, ty.i32(), Vector{ty.i32()});
+    Build(core::BuiltinFn::kFirstLeadingBit, ty.i32(), Vector{ty.i32()});
     auto* src = R"(
 %foo = func(%arg:i32):i32 -> %b1 {
   %b1 = block {
@@ -724,7 +724,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, FirstLeadingBit_Vec2U32) {
-    Build(core::Function::kFirstLeadingBit, ty.vec2<u32>(), Vector{ty.vec2<u32>()});
+    Build(core::BuiltinFn::kFirstLeadingBit, ty.vec2<u32>(), Vector{ty.vec2<u32>()});
     auto* src = R"(
 %foo = func(%arg:vec2<u32>):vec2<u32> -> %b1 {
   %b1 = block {
@@ -775,7 +775,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, FirstLeadingBit_Vec4I32) {
-    Build(core::Function::kFirstLeadingBit, ty.vec4<i32>(), Vector{ty.vec4<i32>()});
+    Build(core::BuiltinFn::kFirstLeadingBit, ty.vec4<i32>(), Vector{ty.vec4<i32>()});
     auto* src = R"(
 %foo = func(%arg:vec4<i32>):vec4<i32> -> %b1 {
   %b1 = block {
@@ -831,7 +831,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, FirstTrailingBit_NoPolyfill) {
-    Build(core::Function::kFirstTrailingBit, ty.u32(), Vector{ty.u32()});
+    Build(core::BuiltinFn::kFirstTrailingBit, ty.u32(), Vector{ty.u32()});
     auto* src = R"(
 %foo = func(%arg:u32):u32 -> %b1 {
   %b1 = block {
@@ -851,7 +851,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, FirstTrailingBit_U32) {
-    Build(core::Function::kFirstTrailingBit, ty.u32(), Vector{ty.u32()});
+    Build(core::BuiltinFn::kFirstTrailingBit, ty.u32(), Vector{ty.u32()});
     auto* src = R"(
 %foo = func(%arg:u32):u32 -> %b1 {
   %b1 = block {
@@ -902,7 +902,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, FirstTrailingBit_I32) {
-    Build(core::Function::kFirstTrailingBit, ty.i32(), Vector{ty.i32()});
+    Build(core::BuiltinFn::kFirstTrailingBit, ty.i32(), Vector{ty.i32()});
     auto* src = R"(
 %foo = func(%arg:i32):i32 -> %b1 {
   %b1 = block {
@@ -955,7 +955,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, FirstTrailingBit_Vec2U32) {
-    Build(core::Function::kFirstTrailingBit, ty.vec2<u32>(), Vector{ty.vec2<u32>()});
+    Build(core::BuiltinFn::kFirstTrailingBit, ty.vec2<u32>(), Vector{ty.vec2<u32>()});
     auto* src = R"(
 %foo = func(%arg:vec2<u32>):vec2<u32> -> %b1 {
   %b1 = block {
@@ -1006,7 +1006,7 @@
 }
 
 TEST_F(IR_BuiltinPolyfillTest, FirstTrailingBit_Vec4I32) {
-    Build(core::Function::kFirstTrailingBit, ty.vec4<i32>(), Vector{ty.vec4<i32>()});
+    Build(core::BuiltinFn::kFirstTrailingBit, ty.vec4<i32>(), Vector{ty.vec4<i32>()});
     auto* src = R"(
 %foo = func(%arg:vec4<i32>):vec4<i32> -> %b1 {
   %b1 = block {
@@ -1061,7 +1061,7 @@
 TEST_F(IR_BuiltinPolyfillTest, TextureSampleBaseClampToEdge_2d_f32_NoPolyfill) {
     auto* texture_ty =
         ty.Get<core::type::SampledTexture>(core::type::TextureDimension::k2d, ty.f32());
-    Build(core::Function::kTextureSampleBaseClampToEdge, ty.vec4<f32>(),
+    Build(core::BuiltinFn::kTextureSampleBaseClampToEdge, ty.vec4<f32>(),
           Vector{texture_ty, ty.sampler(), ty.vec2<f32>()});
     auto* src = R"(
 %foo = func(%arg:texture_2d<f32>, %arg_1:sampler, %arg_2:vec2<f32>):vec4<f32> -> %b1 {  # %arg_1: 'arg', %arg_2: 'arg'
@@ -1084,7 +1084,7 @@
 TEST_F(IR_BuiltinPolyfillTest, TextureSampleBaseClampToEdge_2d_f32) {
     auto* texture_ty =
         ty.Get<core::type::SampledTexture>(core::type::TextureDimension::k2d, ty.f32());
-    Build(core::Function::kTextureSampleBaseClampToEdge, ty.vec4<f32>(),
+    Build(core::BuiltinFn::kTextureSampleBaseClampToEdge, ty.vec4<f32>(),
           Vector{texture_ty, ty.sampler(), ty.vec2<f32>()});
     auto* src = R"(
 %foo = func(%arg:texture_2d<f32>, %arg_1:sampler, %arg_2:vec2<f32>):vec4<f32> -> %b1 {  # %arg_1: 'arg', %arg_2: 'arg'
diff --git a/src/tint/lang/core/ir/transform/demote_to_helper_test.cc b/src/tint/lang/core/ir/transform/demote_to_helper_test.cc
index 655c714..cc10af2 100644
--- a/src/tint/lang/core/ir/transform/demote_to_helper_test.cc
+++ b/src/tint/lang/core/ir/transform/demote_to_helper_test.cc
@@ -536,7 +536,7 @@
             b.Discard();
             b.ExitIf(ifelse);
         });
-        b.Call(ty.void_(), core::Function::kTextureStore, b.Load(texture), coord,
+        b.Call(ty.void_(), core::BuiltinFn::kTextureStore, b.Load(texture), coord,
                b.Splat(b.ir.Types().vec4<f32>(), 0.5_f, 4));
         b.Return(ep, 0.5_f);
     });
@@ -618,7 +618,7 @@
             b.Discard();
             b.ExitIf(ifelse);
         });
-        b.Call(ty.void_(), core::Function::kAtomicStore, buffer, 42_i);
+        b.Call(ty.void_(), core::BuiltinFn::kAtomicStore, buffer, 42_i);
         b.Return(ep, 0.5_f);
     });
 
@@ -697,7 +697,7 @@
             b.Discard();
             b.ExitIf(ifelse);
         });
-        auto* old = b.Call(ty.i32(), core::Function::kAtomicAdd, buffer, 42_i);
+        auto* old = b.Call(ty.i32(), core::BuiltinFn::kAtomicAdd, buffer, 42_i);
         b.Add(ty.i32(), old, 1_i);
         b.Return(ep, 0.5_f);
     });
@@ -782,7 +782,7 @@
         });
         auto* result =
             b.Call(core::type::CreateAtomicCompareExchangeResult(ty, mod.symbols, ty.i32()),
-                   core::Function::kAtomicCompareExchangeWeak, buffer, 0_i, 42_i);
+                   core::BuiltinFn::kAtomicCompareExchangeWeak, buffer, 0_i, 42_i);
         b.Add(ty.i32(), b.Access(ty.i32(), result, 0_i), 1_i);
         b.Return(ep, 0.5_f);
     });
diff --git a/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc b/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc
index 06eb634..2a94be1 100644
--- a/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc
+++ b/src/tint/lang/core/ir/transform/multiplanar_external_texture.cc
@@ -202,10 +202,10 @@
                     load->Destroy();
                 },
                 [&](CoreBuiltinCall* call) {
-                    if (call->Func() == core::Function::kTextureDimensions) {
+                    if (call->Func() == core::BuiltinFn::kTextureDimensions) {
                         // Use the first plane for the `textureDimensions()` call.
                         call->SetOperand(use.operand_index, plane_0);
-                    } else if (call->Func() == core::Function::kTextureLoad) {
+                    } else if (call->Func() == core::BuiltinFn::kTextureLoad) {
                         // Convert the coordinates to unsigned integers if necessary.
                         auto* coords = call->Args()[1];
                         if (coords->Type()->is_signed_integer_vector()) {
@@ -220,7 +220,7 @@
                         helper->InsertBefore(call);
                         call->Result()->ReplaceAllUsesWith(helper->Result());
                         call->Destroy();
-                    } else if (call->Func() == core::Function::kTextureSampleBaseClampToEdge) {
+                    } else if (call->Func() == core::BuiltinFn::kTextureSampleBaseClampToEdge) {
                         // Call the `TextureSampleExternal()` helper function.
                         auto* sampler = call->Args()[1];
                         auto* coords = call->Args()[2];
@@ -320,17 +320,17 @@
             auto* F = b.Access(ty.f32(), params, 6_u);
             auto* G_splat = b.Construct(vec3f, G);
             auto* D_splat = b.Construct(vec3f, D);
-            auto* abs_v = b.Call(vec3f, core::Function::kAbs, v);
-            auto* sign_v = b.Call(vec3f, core::Function::kSign, v);
+            auto* abs_v = b.Call(vec3f, core::BuiltinFn::kAbs, v);
+            auto* sign_v = b.Call(vec3f, core::BuiltinFn::kSign, v);
             auto* cond = b.LessThan(ty.vec3<bool>(), abs_v, D_splat);
             auto* t = b.Multiply(vec3f, sign_v, b.Add(vec3f, b.Multiply(vec3f, C, abs_v), F));
             auto* f =
                 b.Multiply(vec3f, sign_v,
                            b.Add(vec3f,
-                                 b.Call(vec3f, core::Function::kPow,
+                                 b.Call(vec3f, core::BuiltinFn::kPow,
                                         b.Add(vec3f, b.Multiply(vec3f, A, abs_v), B), G_splat),
                                  E));
-            b.Return(gamma_correction, b.Call(vec3f, core::Function::kSelect, f, t, cond));
+            b.Return(gamma_correction, b.Call(vec3f, core::BuiltinFn::kSelect, f, t, cond));
         });
 
         return gamma_correction;
@@ -390,7 +390,7 @@
             if_planes_eq_1->SetResults(rgb_result, alpha_result);
             b.Append(if_planes_eq_1->True(), [&] {
                 // Load the texel from the first plane and split into separate rgb and a values.
-                auto* texel = b.Call(vec4f, core::Function::kTextureLoad, plane_0, coords, 0_u);
+                auto* texel = b.Call(vec4f, core::BuiltinFn::kTextureLoad, plane_0, coords, 0_u);
                 auto* rgb = b.Swizzle(vec3f, texel, {0u, 1u, 2u});
                 auto* a = b.Access(ty.f32(), texel, 3_u);
                 b.ExitIf(if_planes_eq_1, rgb, a);
@@ -398,14 +398,14 @@
             b.Append(if_planes_eq_1->False(), [&] {
                 // Load the y value from the first plane.
                 auto* y = b.Access(
-                    ty.f32(), b.Call(vec4f, core::Function::kTextureLoad, plane_0, coords, 0_u),
+                    ty.f32(), b.Call(vec4f, core::BuiltinFn::kTextureLoad, plane_0, coords, 0_u),
                     0_u);
 
                 // Load the uv value from the second plane.
                 auto* coord_uv =
                     b.ShiftRight(ty.vec2<u32>(), coords, b.Splat(ty.vec2<u32>(), 1_u, 2u));
                 auto* uv = b.Swizzle(
-                    vec2f, b.Call(vec4f, core::Function::kTextureLoad, plane_1, coord_uv, 0_u),
+                    vec2f, b.Call(vec4f, core::BuiltinFn::kTextureLoad, plane_1, coord_uv, 0_u),
                     {0u, 1u});
 
                 // Convert the combined yuv value into rgb and set the alpha to 1.0.
@@ -498,16 +498,16 @@
             auto* modified_coords =
                 b.Multiply(vec2f, transformation_matrix, b.Construct(vec3f, coords, 1_f));
             auto* plane0_dims = b.Convert(
-                vec2f, b.Call(ty.vec2<u32>(), core::Function::kTextureDimensions, plane_0));
+                vec2f, b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, plane_0));
             auto* plane0_half_texel = b.Divide(vec2f, b.Splat(vec2f, 0.5_f, 2u), plane0_dims);
             auto* plane0_clamped =
-                b.Call(vec2f, core::Function::kClamp, modified_coords, plane0_half_texel,
+                b.Call(vec2f, core::BuiltinFn::kClamp, modified_coords, plane0_half_texel,
                        b.Subtract(vec2f, 1_f, plane0_half_texel));
             auto* plane1_dims = b.Convert(
-                vec2f, b.Call(ty.vec2<u32>(), core::Function::kTextureDimensions, plane_1));
+                vec2f, b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, plane_1));
             auto* plane1_half_texel = b.Divide(vec2f, b.Splat(vec2f, 0.5_f, 2u), plane1_dims);
             auto* plane1_clamped =
-                b.Call(vec2f, core::Function::kClamp, modified_coords, plane1_half_texel,
+                b.Call(vec2f, core::BuiltinFn::kClamp, modified_coords, plane1_half_texel,
                        b.Subtract(vec2f, 1_f, plane1_half_texel));
 
             auto* rgb_result = b.InstructionResult(vec3f);
@@ -517,7 +517,7 @@
             if_planes_eq_1->SetResults(rgb_result, alpha_result);
             b.Append(if_planes_eq_1->True(), [&] {
                 // Sample the texel from the first plane and split into separate rgb and a values.
-                auto* texel = b.Call(vec4f, core::Function::kTextureSampleLevel, plane_0, sampler,
+                auto* texel = b.Call(vec4f, core::BuiltinFn::kTextureSampleLevel, plane_0, sampler,
                                      plane0_clamped, 0_f);
                 auto* rgb = b.Swizzle(vec3f, texel, {0u, 1u, 2u});
                 auto* a = b.Access(ty.f32(), texel, 3_u);
@@ -526,13 +526,13 @@
             b.Append(if_planes_eq_1->False(), [&] {
                 // Sample the y value from the first plane.
                 auto* y = b.Access(ty.f32(),
-                                   b.Call(vec4f, core::Function::kTextureSampleLevel, plane_0,
+                                   b.Call(vec4f, core::BuiltinFn::kTextureSampleLevel, plane_0,
                                           sampler, plane0_clamped, 0_f),
                                    0_u);
 
                 // Sample the uv value from the second plane.
                 auto* uv = b.Swizzle(vec2f,
-                                     b.Call(vec4f, core::Function::kTextureSampleLevel, plane_1,
+                                     b.Call(vec4f, core::BuiltinFn::kTextureSampleLevel, plane_1,
                                             sampler, plane1_clamped, 0_f),
                                      {0u, 1u});
 
diff --git a/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc b/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc
index 25cba9b..d38c80a 100644
--- a/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc
+++ b/src/tint/lang/core/ir/transform/multiplanar_external_texture_test.cc
@@ -185,7 +185,7 @@
     auto* func = b.Function("foo", ty.vec2<u32>());
     b.Append(func->Block(), [&] {
         auto* load = b.Load(var->Result());
-        auto* result = b.Call(ty.vec2<u32>(), core::Function::kTextureDimensions, load);
+        auto* result = b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, load);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -260,7 +260,7 @@
     func->SetParams({coords});
     b.Append(func->Block(), [&] {
         auto* load = b.Load(var->Result());
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, load, coords);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, load, coords);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -404,7 +404,7 @@
     func->SetParams({coords});
     b.Append(func->Block(), [&] {
         auto* load = b.Load(var->Result());
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, load, coords);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, load, coords);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -550,7 +550,7 @@
     func->SetParams({sampler, coords});
     b.Append(func->Block(), [&] {
         auto* load = b.Load(var->Result());
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureSampleBaseClampToEdge, load,
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleBaseClampToEdge, load,
                               sampler, coords);
         b.Return(func, result);
         mod.SetName(result, "result");
@@ -709,7 +709,7 @@
         auto* coords = b.FunctionParam("coords", ty.vec2<f32>());
         foo->SetParams({texture, sampler, coords});
         b.Append(foo->Block(), [&] {
-            auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureSampleBaseClampToEdge,
+            auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleBaseClampToEdge,
                                   texture, sampler, coords);
             b.Return(foo, result);
             mod.SetName(result, "result");
@@ -894,7 +894,7 @@
         auto* coords = b.FunctionParam("coords", ty.vec2<f32>());
         foo->SetParams({texture, sampler, coords});
         b.Append(foo->Block(), [&] {
-            auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureSampleBaseClampToEdge,
+            auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleBaseClampToEdge,
                                   texture, sampler, coords);
             b.Return(foo, result);
             mod.SetName(result, "result");
@@ -908,12 +908,12 @@
         bar->SetParams({sampler, coords_f});
         b.Append(bar->Block(), [&] {
             auto* load_a = b.Load(var->Result());
-            b.Call(ty.vec2<u32>(), core::Function::kTextureDimensions, load_a);
+            b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, load_a);
             auto* load_b = b.Load(var->Result());
-            b.Call(ty.vec4<f32>(), core::Function::kTextureSampleBaseClampToEdge, load_b, sampler,
+            b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleBaseClampToEdge, load_b, sampler,
                    coords_f);
             auto* load_c = b.Load(var->Result());
-            b.Call(ty.vec4<f32>(), core::Function::kTextureSampleBaseClampToEdge, load_c, sampler,
+            b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleBaseClampToEdge, load_c, sampler,
                    coords_f);
             auto* load_d = b.Load(var->Result());
             auto* result_a = b.Call(ty.vec4<f32>(), foo, load_d, sampler, coords_f);
@@ -1117,11 +1117,11 @@
     foo->SetParams({coords});
     b.Append(foo->Block(), [&] {
         auto* load_a = b.Load(var_a->Result());
-        b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, load_a, coords);
+        b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, load_a, coords);
         auto* load_b = b.Load(var_b->Result());
-        b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, load_b, coords);
+        b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, load_b, coords);
         auto* load_c = b.Load(var_c->Result());
-        b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, load_c, coords);
+        b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, load_c, coords);
         b.Return(foo);
     });
 
diff --git a/src/tint/lang/core/ir/transform/robustness.cc b/src/tint/lang/core/ir/transform/robustness.cc
index 6eef036..77216e1 100644
--- a/src/tint/lang/core/ir/transform/robustness.cc
+++ b/src/tint/lang/core/ir/transform/robustness.cc
@@ -86,9 +86,9 @@
                     [&](ir::CoreBuiltinCall* call) {
                         // Check if this is a texture builtin that needs to be clamped.
                         if (config.clamp_texture) {
-                            if (call->Func() == core::Function::kTextureDimensions ||
-                                call->Func() == core::Function::kTextureLoad ||
-                                call->Func() == core::Function::kTextureStore) {
+                            if (call->Func() == core::BuiltinFn::kTextureDimensions ||
+                                call->Func() == core::BuiltinFn::kTextureLoad ||
+                                call->Func() == core::BuiltinFn::kTextureStore) {
                                 texture_calls.Push(call);
                             }
                         }
@@ -192,7 +192,7 @@
                                                   const_limit->Value()->ValueAs<uint32_t>())));
         } else {
             // Clamp it to the dynamic limit.
-            clamped_idx = b.Call(ty.u32(), core::Function::kMin, CastToU32(idx), limit)->Result();
+            clamped_idx = b.Call(ty.u32(), core::BuiltinFn::kMin, CastToU32(idx), limit)->Result();
         }
 
         // Replace the index operand with the clamped version.
@@ -242,7 +242,7 @@
                     }
 
                     // Use the `arrayLength` builtin to get the limit of a runtime-sized array.
-                    auto* length = b.Call(ty.u32(), core::Function::kArrayLength, object);
+                    auto* length = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, object);
                     return b.Subtract(ty.u32(), length, b.Constant(1_u))->Result();
                 });
 
@@ -268,10 +268,10 @@
         // Keep hold of the clamped value to use for clamping the coordinates.
         Value* clamped_level = nullptr;
         auto clamp_level = [&](uint32_t idx) {
-            auto* num_levels = b.Call(ty.u32(), core::Function::kTextureNumLevels, args[0]);
+            auto* num_levels = b.Call(ty.u32(), core::BuiltinFn::kTextureNumLevels, args[0]);
             auto* limit = b.Subtract(ty.u32(), num_levels, 1_u);
             clamped_level =
-                b.Call(ty.u32(), core::Function::kMin, CastToU32(args[idx]), limit)->Result();
+                b.Call(ty.u32(), core::BuiltinFn::kMin, CastToU32(args[idx]), limit)->Result();
             call->SetOperand(CoreBuiltinCall::kArgsOperandOffset + idx, clamped_level);
         };
 
@@ -283,33 +283,33 @@
                 type = ty.vec(type, vec->Width());
                 one = b.Splat(type, one, vec->Width());
             }
-            auto* dims = clamped_level ? b.Call(type, core::Function::kTextureDimensions, args[0],
+            auto* dims = clamped_level ? b.Call(type, core::BuiltinFn::kTextureDimensions, args[0],
                                                 clamped_level)
-                                       : b.Call(type, core::Function::kTextureDimensions, args[0]);
+                                       : b.Call(type, core::BuiltinFn::kTextureDimensions, args[0]);
             auto* limit = b.Subtract(type, dims, one);
             call->SetOperand(
                 CoreBuiltinCall::kArgsOperandOffset + idx,
-                b.Call(type, core::Function::kMin, CastToU32(args[idx]), limit)->Result());
+                b.Call(type, core::BuiltinFn::kMin, CastToU32(args[idx]), limit)->Result());
         };
 
         // Helper for clamping the array index.
         auto clamp_array_index = [&](uint32_t idx) {
-            auto* num_layers = b.Call(ty.u32(), core::Function::kTextureNumLayers, args[0]);
+            auto* num_layers = b.Call(ty.u32(), core::BuiltinFn::kTextureNumLayers, args[0]);
             auto* limit = b.Subtract(ty.u32(), num_layers, 1_u);
             call->SetOperand(
                 CoreBuiltinCall::kArgsOperandOffset + idx,
-                b.Call(ty.u32(), core::Function::kMin, CastToU32(args[idx]), limit)->Result());
+                b.Call(ty.u32(), core::BuiltinFn::kMin, CastToU32(args[idx]), limit)->Result());
         };
 
         // Select which arguments to clamp based on the function overload.
         switch (call->Func()) {
-            case core::Function::kTextureDimensions: {
+            case core::BuiltinFn::kTextureDimensions: {
                 if (args.Length() > 1) {
                     clamp_level(1u);
                 }
                 break;
             }
-            case core::Function::kTextureLoad: {
+            case core::BuiltinFn::kTextureLoad: {
                 clamp_coords(1u);
                 uint32_t next_arg = 2u;
                 if (type::IsTextureArray(texture->dim())) {
@@ -320,7 +320,7 @@
                 }
                 break;
             }
-            case core::Function::kTextureStore: {
+            case core::BuiltinFn::kTextureStore: {
                 clamp_coords(1u);
                 if (type::IsTextureArray(texture->dim())) {
                     clamp_array_index(2u);
diff --git a/src/tint/lang/core/ir/transform/robustness_test.cc b/src/tint/lang/core/ir/transform/robustness_test.cc
index e55a5de..b44f547 100644
--- a/src/tint/lang/core/ir/transform/robustness_test.cc
+++ b/src/tint/lang/core/ir/transform/robustness_test.cc
@@ -1944,7 +1944,7 @@
     auto* func = b.Function("foo", ty.vec2<u32>());
     b.Append(func->Block(), [&] {
         auto* handle = b.Load(texture);
-        auto* dims = b.Call(ty.vec2<u32>(), core::Function::kTextureDimensions, handle);
+        auto* dims = b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, handle);
         b.Return(func, dims);
     });
 
@@ -1984,7 +1984,7 @@
     func->SetParams({level});
     b.Append(func->Block(), [&] {
         auto* handle = b.Load(texture);
-        auto* dims = b.Call(ty.vec2<u32>(), core::Function::kTextureDimensions, handle, level);
+        auto* dims = b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, handle, level);
         b.Return(func, dims);
     });
 
@@ -2042,7 +2042,7 @@
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
             auto* texel =
-                b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords, level);
+                b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords, level);
             b.Return(func, texel);
         });
     }
@@ -2055,7 +2055,7 @@
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
             auto* texel =
-                b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords, level);
+                b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords, level);
             b.Return(func, texel);
         });
     }
@@ -2139,7 +2139,7 @@
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
             auto* texel =
-                b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords, level);
+                b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords, level);
             b.Return(func, texel);
         });
     }
@@ -2152,7 +2152,7 @@
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
             auto* texel =
-                b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords, level);
+                b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords, level);
             b.Return(func, texel);
         });
     }
@@ -2238,7 +2238,7 @@
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
             auto* texel =
-                b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords, layer, level);
+                b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords, layer, level);
             b.Return(func, texel);
         });
     }
@@ -2252,7 +2252,7 @@
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
             auto* texel =
-                b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords, layer, level);
+                b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords, layer, level);
             b.Return(func, texel);
         });
     }
@@ -2343,7 +2343,7 @@
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
             auto* texel =
-                b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords, level);
+                b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords, level);
             b.Return(func, texel);
         });
     }
@@ -2356,7 +2356,7 @@
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
             auto* texel =
-                b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords, level);
+                b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords, level);
             b.Return(func, texel);
         });
     }
@@ -2441,7 +2441,7 @@
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
             auto* texel =
-                b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords, level);
+                b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords, level);
             b.Return(func, texel);
         });
     }
@@ -2454,7 +2454,7 @@
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
             auto* texel =
-                b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords, level);
+                b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords, level);
             b.Return(func, texel);
         });
     }
@@ -2529,7 +2529,7 @@
         func->SetParams({coords, level});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            auto* texel = b.Call(ty.f32(), core::Function::kTextureLoad, handle, coords, level);
+            auto* texel = b.Call(ty.f32(), core::BuiltinFn::kTextureLoad, handle, coords, level);
             b.Return(func, texel);
         });
     }
@@ -2541,7 +2541,7 @@
         func->SetParams({coords, level});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            auto* texel = b.Call(ty.f32(), core::Function::kTextureLoad, handle, coords, level);
+            auto* texel = b.Call(ty.f32(), core::BuiltinFn::kTextureLoad, handle, coords, level);
             b.Return(func, texel);
         });
     }
@@ -2626,7 +2626,7 @@
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
             auto* texel =
-                b.Call(ty.f32(), core::Function::kTextureLoad, handle, coords, layer, level);
+                b.Call(ty.f32(), core::BuiltinFn::kTextureLoad, handle, coords, layer, level);
             b.Return(func, texel);
         });
     }
@@ -2640,7 +2640,7 @@
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
             auto* texel =
-                b.Call(ty.f32(), core::Function::kTextureLoad, handle, coords, layer, level);
+                b.Call(ty.f32(), core::BuiltinFn::kTextureLoad, handle, coords, layer, level);
             b.Return(func, texel);
         });
     }
@@ -2730,7 +2730,7 @@
         func->SetParams({coords, index});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            auto* texel = b.Call(ty.f32(), core::Function::kTextureLoad, handle, coords, index);
+            auto* texel = b.Call(ty.f32(), core::BuiltinFn::kTextureLoad, handle, coords, index);
             b.Return(func, texel);
         });
     }
@@ -2742,7 +2742,7 @@
         func->SetParams({coords, index});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            auto* texel = b.Call(ty.f32(), core::Function::kTextureLoad, handle, coords, index);
+            auto* texel = b.Call(ty.f32(), core::BuiltinFn::kTextureLoad, handle, coords, index);
             b.Return(func, texel);
         });
     }
@@ -2815,7 +2815,7 @@
         func->SetParams({coords});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            auto* texel = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords);
+            auto* texel = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords);
             b.Return(func, texel);
         });
     }
@@ -2826,7 +2826,7 @@
         func->SetParams({coords});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            auto* texel = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords);
+            auto* texel = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords);
             b.Return(func, texel);
         });
     }
@@ -2905,7 +2905,7 @@
         func->SetParams({coords});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            auto* texel = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords);
+            auto* texel = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords);
             b.Return(func, texel);
         });
     }
@@ -2916,7 +2916,7 @@
         func->SetParams({coords});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            auto* texel = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords);
+            auto* texel = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords);
             b.Return(func, texel);
         });
     }
@@ -2995,7 +2995,7 @@
         func->SetParams({coords});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            auto* texel = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords);
+            auto* texel = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords);
             b.Return(func, texel);
         });
     }
@@ -3006,7 +3006,7 @@
         func->SetParams({coords});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            auto* texel = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords);
+            auto* texel = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords);
             b.Return(func, texel);
         });
     }
@@ -3087,7 +3087,7 @@
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
             auto* texel =
-                b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords, layer);
+                b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords, layer);
             b.Return(func, texel);
         });
     }
@@ -3100,7 +3100,7 @@
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
             auto* texel =
-                b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords, layer);
+                b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords, layer);
             b.Return(func, texel);
         });
     }
@@ -3186,7 +3186,7 @@
         func->SetParams({coords});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            auto* texel = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords);
+            auto* texel = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords);
             b.Return(func, texel);
         });
     }
@@ -3197,7 +3197,7 @@
         func->SetParams({coords});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            auto* texel = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, handle, coords);
+            auto* texel = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, handle, coords);
             b.Return(func, texel);
         });
     }
@@ -3277,7 +3277,7 @@
         func->SetParams({coords, value});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            b.Call(ty.void_(), core::Function::kTextureStore, handle, coords, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, handle, coords, value);
             b.Return(func);
         });
     }
@@ -3289,7 +3289,7 @@
         func->SetParams({coords, value});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            b.Call(ty.void_(), core::Function::kTextureStore, handle, coords, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, handle, coords, value);
             b.Return(func);
         });
     }
@@ -3369,7 +3369,7 @@
         func->SetParams({coords, value});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            b.Call(ty.void_(), core::Function::kTextureStore, handle, coords, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, handle, coords, value);
             b.Return(func);
         });
     }
@@ -3381,7 +3381,7 @@
         func->SetParams({coords, value});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            b.Call(ty.void_(), core::Function::kTextureStore, handle, coords, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, handle, coords, value);
             b.Return(func);
         });
     }
@@ -3462,7 +3462,7 @@
         func->SetParams({coords, layer, value});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            b.Call(ty.void_(), core::Function::kTextureStore, handle, coords, layer, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, handle, coords, layer, value);
             b.Return(func);
         });
     }
@@ -3475,7 +3475,7 @@
         func->SetParams({coords, layer, value});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            b.Call(ty.void_(), core::Function::kTextureStore, handle, coords, layer, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, handle, coords, layer, value);
             b.Return(func);
         });
     }
@@ -3562,7 +3562,7 @@
         func->SetParams({coords, value});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            b.Call(ty.void_(), core::Function::kTextureStore, handle, coords, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, handle, coords, value);
             b.Return(func);
         });
     }
@@ -3574,7 +3574,7 @@
         func->SetParams({coords, value});
         b.Append(func->Block(), [&] {
             auto* handle = b.Load(texture);
-            b.Call(ty.void_(), core::Function::kTextureStore, handle, coords, value);
+            b.Call(ty.void_(), core::BuiltinFn::kTextureStore, handle, coords, value);
             b.Return(func);
         });
     }
diff --git a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
index 839cdb1..1eb6050 100644
--- a/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/ast_printer.cc
@@ -820,7 +820,7 @@
     Switch(
         call->Target(),  //
         [&](const sem::Function* fn) { EmitFunctionCall(out, call, fn); },
-        [&](const sem::Builtin* builtin) { EmitBuiltinCall(out, call, builtin); },
+        [&](const sem::BuiltinFn* builtin) { EmitBuiltinCall(out, call, builtin); },
         [&](const sem::ValueConversion* conv) { EmitValueConversion(out, call, conv); },
         [&](const sem::ValueConstructor* ctor) { EmitValueConstructor(out, call, ctor); },
         [&](Default) {
@@ -850,40 +850,39 @@
 
 void ASTPrinter::EmitBuiltinCall(StringStream& out,
                                  const sem::Call* call,
-                                 const sem::Builtin* builtin) {
+                                 const sem::BuiltinFn* builtin) {
     auto* expr = call->Declaration();
     if (builtin->IsTexture()) {
         EmitTextureCall(out, call, builtin);
-    } else if (builtin->Type() == core::Function::kCountOneBits) {
+    } else if (builtin->Fn() == core::BuiltinFn::kCountOneBits) {
         EmitCountOneBitsCall(out, expr);
-    } else if (builtin->Type() == core::Function::kSelect) {
+    } else if (builtin->Fn() == core::BuiltinFn::kSelect) {
         EmitSelectCall(out, expr, builtin);
-    } else if (builtin->Type() == core::Function::kDot) {
+    } else if (builtin->Fn() == core::BuiltinFn::kDot) {
         EmitDotCall(out, expr, builtin);
-    } else if (builtin->Type() == core::Function::kModf) {
+    } else if (builtin->Fn() == core::BuiltinFn::kModf) {
         EmitModfCall(out, expr, builtin);
-    } else if (builtin->Type() == core::Function::kFrexp) {
+    } else if (builtin->Fn() == core::BuiltinFn::kFrexp) {
         EmitFrexpCall(out, expr, builtin);
-    } else if (builtin->Type() == core::Function::kDegrees) {
+    } else if (builtin->Fn() == core::BuiltinFn::kDegrees) {
         EmitDegreesCall(out, expr, builtin);
-    } else if (builtin->Type() == core::Function::kRadians) {
+    } else if (builtin->Fn() == core::BuiltinFn::kRadians) {
         EmitRadiansCall(out, expr, builtin);
-    } else if (builtin->Type() == core::Function::kQuantizeToF16) {
+    } else if (builtin->Fn() == core::BuiltinFn::kQuantizeToF16) {
         EmitQuantizeToF16Call(out, expr, builtin);
-    } else if (builtin->Type() == core::Function::kArrayLength) {
+    } else if (builtin->Fn() == core::BuiltinFn::kArrayLength) {
         EmitArrayLength(out, expr);
-    } else if (builtin->Type() == core::Function::kExtractBits) {
+    } else if (builtin->Fn() == core::BuiltinFn::kExtractBits) {
         EmitExtractBits(out, expr);
-    } else if (builtin->Type() == core::Function::kInsertBits) {
+    } else if (builtin->Fn() == core::BuiltinFn::kInsertBits) {
         EmitInsertBits(out, expr);
-    } else if (builtin->Type() == core::Function::kFma && version_.IsES()) {
+    } else if (builtin->Fn() == core::BuiltinFn::kFma && version_.IsES()) {
         EmitEmulatedFMA(out, expr);
-    } else if (builtin->Type() == core::Function::kAbs &&
+    } else if (builtin->Fn() == core::BuiltinFn::kAbs &&
                TypeOf(expr->args[0])->UnwrapRef()->is_unsigned_integer_scalar_or_vector()) {
         // GLSL does not support abs() on unsigned arguments. However, it's a no-op.
         EmitExpression(out, expr->args[0]);
-    } else if ((builtin->Type() == core::Function::kAny ||
-                builtin->Type() == core::Function::kAll) &&
+    } else if ((builtin->Fn() == core::BuiltinFn::kAny || builtin->Fn() == core::BuiltinFn::kAll) &&
                TypeOf(expr->args[0])->UnwrapRef()->Is<core::type::Scalar>()) {
         // GLSL does not support any() or all() on scalar arguments. It's a no-op.
         EmitExpression(out, expr->args[0]);
@@ -948,7 +947,7 @@
 
 void ASTPrinter::EmitWorkgroupAtomicCall(StringStream& out,
                                          const ast::CallExpression* expr,
-                                         const sem::Builtin* builtin) {
+                                         const sem::BuiltinFn* builtin) {
     auto call = [&](const char* name) {
         out << name;
         {
@@ -964,8 +963,8 @@
         return;
     };
 
-    switch (builtin->Type()) {
-        case core::Function::kAtomicLoad: {
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kAtomicLoad: {
             // GLSL does not have an atomicLoad, so we emulate it with
             // atomicOr using 0 as the OR value
             out << "atomicOr";
@@ -979,7 +978,7 @@
             }
             return;
         }
-        case core::Function::kAtomicCompareExchangeWeak: {
+        case core::BuiltinFn::kAtomicCompareExchangeWeak: {
             EmitStructType(&helpers_, builtin->ReturnType()->As<core::type::Struct>());
 
             auto* dest = expr->args[0];
@@ -1018,33 +1017,33 @@
             return;
         }
 
-        case core::Function::kAtomicAdd:
-        case core::Function::kAtomicSub:
+        case core::BuiltinFn::kAtomicAdd:
+        case core::BuiltinFn::kAtomicSub:
             call("atomicAdd");
             return;
 
-        case core::Function::kAtomicMax:
+        case core::BuiltinFn::kAtomicMax:
             call("atomicMax");
             return;
 
-        case core::Function::kAtomicMin:
+        case core::BuiltinFn::kAtomicMin:
             call("atomicMin");
             return;
 
-        case core::Function::kAtomicAnd:
+        case core::BuiltinFn::kAtomicAnd:
             call("atomicAnd");
             return;
 
-        case core::Function::kAtomicOr:
+        case core::BuiltinFn::kAtomicOr:
             call("atomicOr");
             return;
 
-        case core::Function::kAtomicXor:
+        case core::BuiltinFn::kAtomicXor:
             call("atomicXor");
             return;
 
-        case core::Function::kAtomicExchange:
-        case core::Function::kAtomicStore:
+        case core::BuiltinFn::kAtomicExchange:
+        case core::BuiltinFn::kAtomicStore:
             // GLSL does not have an atomicStore, so we emulate it with
             // atomicExchange.
             call("atomicExchange");
@@ -1054,7 +1053,7 @@
             break;
     }
 
-    TINT_UNREACHABLE() << "unsupported atomic builtin: " << builtin->Type();
+    TINT_UNREACHABLE() << "unsupported atomic builtin: " << builtin->Fn();
 }
 
 void ASTPrinter::EmitArrayLength(StringStream& out, const ast::CallExpression* expr) {
@@ -1107,7 +1106,7 @@
 
 void ASTPrinter::EmitSelectCall(StringStream& out,
                                 const ast::CallExpression* expr,
-                                const sem::Builtin* builtin) {
+                                const sem::BuiltinFn* builtin) {
     // GLSL does not support ternary expressions with a bool vector conditional,
     // so polyfill with a helper.
     if (auto* vec = builtin->Parameters()[2]->Type()->As<core::type::Vector>()) {
@@ -1147,7 +1146,7 @@
 
 void ASTPrinter::EmitDotCall(StringStream& out,
                              const ast::CallExpression* expr,
-                             const sem::Builtin* builtin) {
+                             const sem::BuiltinFn* builtin) {
     auto* vec_ty = builtin->Parameters()[0]->Type()->As<core::type::Vector>();
     std::string fn = "dot";
     if (vec_ty->type()->is_integer_scalar()) {
@@ -1202,7 +1201,7 @@
 
 void ASTPrinter::EmitModfCall(StringStream& out,
                               const ast::CallExpression* expr,
-                              const sem::Builtin* builtin) {
+                              const sem::BuiltinFn* builtin) {
     TINT_ASSERT(expr->args.Length() == 1);
     CallBuiltinHelper(
         out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
@@ -1223,7 +1222,7 @@
 
 void ASTPrinter::EmitFrexpCall(StringStream& out,
                                const ast::CallExpression* expr,
-                               const sem::Builtin* builtin) {
+                               const sem::BuiltinFn* builtin) {
     TINT_ASSERT(expr->args.Length() == 1);
     CallBuiltinHelper(
         out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
@@ -1244,7 +1243,7 @@
 
 void ASTPrinter::EmitDegreesCall(StringStream& out,
                                  const ast::CallExpression* expr,
-                                 const sem::Builtin* builtin) {
+                                 const sem::BuiltinFn* builtin) {
     auto* return_elem_type = builtin->ReturnType()->DeepestElement();
     const std::string suffix = Is<core::type::F16>(return_elem_type) ? "hf" : "f";
     CallBuiltinHelper(out, expr, builtin,
@@ -1256,7 +1255,7 @@
 
 void ASTPrinter::EmitRadiansCall(StringStream& out,
                                  const ast::CallExpression* expr,
-                                 const sem::Builtin* builtin) {
+                                 const sem::BuiltinFn* builtin) {
     auto* return_elem_type = builtin->ReturnType()->DeepestElement();
     const std::string suffix = Is<core::type::F16>(return_elem_type) ? "hf" : "f";
     CallBuiltinHelper(out, expr, builtin,
@@ -1268,7 +1267,7 @@
 
 void ASTPrinter::EmitQuantizeToF16Call(StringStream& out,
                                        const ast::CallExpression* expr,
-                                       const sem::Builtin* builtin) {
+                                       const sem::BuiltinFn* builtin) {
     // Emulate by casting to f16 and back again.
     CallBuiltinHelper(
         out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
@@ -1297,17 +1296,17 @@
         });
 }
 
-void ASTPrinter::EmitBarrierCall(StringStream& out, const sem::Builtin* builtin) {
+void ASTPrinter::EmitBarrierCall(StringStream& out, const sem::BuiltinFn* builtin) {
     // TODO(crbug.com/tint/661): Combine sequential barriers to a single
     // instruction.
-    if (builtin->Type() == core::Function::kWorkgroupBarrier) {
+    if (builtin->Fn() == core::BuiltinFn::kWorkgroupBarrier) {
         out << "barrier()";
-    } else if (builtin->Type() == core::Function::kStorageBarrier) {
+    } else if (builtin->Fn() == core::BuiltinFn::kStorageBarrier) {
         out << "{ barrier(); memoryBarrierBuffer(); }";
-    } else if (builtin->Type() == core::Function::kTextureBarrier) {
+    } else if (builtin->Fn() == core::BuiltinFn::kTextureBarrier) {
         out << "{ barrier(); memoryBarrierImage(); }";
     } else {
-        TINT_UNREACHABLE() << "unexpected barrier builtin type " << core::str(builtin->Type());
+        TINT_UNREACHABLE() << "unexpected barrier builtin type " << core::str(builtin->Fn());
     }
 }
 
@@ -1323,7 +1322,7 @@
 
 void ASTPrinter::EmitTextureCall(StringStream& out,
                                  const sem::Call* call,
-                                 const sem::Builtin* builtin) {
+                                 const sem::BuiltinFn* builtin) {
     using Usage = core::ParameterUsage;
 
     auto& signature = builtin->Signature();
@@ -1374,8 +1373,8 @@
         return;
     };
 
-    switch (builtin->Type()) {
-        case core::Function::kTextureDimensions: {
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kTextureDimensions: {
             // textureDimensions() returns an unsigned scalar / vector in WGSL.
             // textureSize() / imageSize() returns a signed scalar / vector in GLSL.
             // Cast.
@@ -1410,7 +1409,7 @@
             }
             return;
         }
-        case core::Function::kTextureNumLayers: {
+        case core::BuiltinFn::kTextureNumLayers: {
             // textureNumLayers() returns an unsigned scalar in WGSL.
             // textureSize() / imageSize() returns a signed scalar / vector in GLSL.
             // Cast.
@@ -1441,7 +1440,7 @@
             out << ").z";
             return;
         }
-        case core::Function::kTextureNumLevels: {
+        case core::BuiltinFn::kTextureNumLevels: {
             // textureNumLevels() returns an unsigned scalar in WGSL.
             // textureQueryLevels() returns a signed scalar in GLSL.
             // Cast.
@@ -1453,7 +1452,7 @@
             out << ")";
             return;
         }
-        case core::Function::kTextureNumSamples: {
+        case core::BuiltinFn::kTextureNumSamples: {
             // textureNumSamples() returns an unsigned scalar in WGSL.
             // textureSamples() returns a signed scalar in GLSL.
             // Cast.
@@ -1473,41 +1472,41 @@
     bool append_depth_ref_to_coords = true;
     bool is_depth = texture_type->Is<core::type::DepthTexture>();
 
-    switch (builtin->Type()) {
-        case core::Function::kTextureSample:
-        case core::Function::kTextureSampleBias:
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kTextureSample:
+        case core::BuiltinFn::kTextureSampleBias:
             out << "texture";
             if (is_depth) {
                 glsl_ret_width = 1u;
             }
             break;
-        case core::Function::kTextureSampleLevel:
+        case core::BuiltinFn::kTextureSampleLevel:
             out << "textureLod";
             if (is_depth) {
                 glsl_ret_width = 1u;
             }
             break;
-        case core::Function::kTextureGather:
-        case core::Function::kTextureGatherCompare:
+        case core::BuiltinFn::kTextureGather:
+        case core::BuiltinFn::kTextureGatherCompare:
             out << "textureGather";
             append_depth_ref_to_coords = false;
             break;
-        case core::Function::kTextureSampleGrad:
+        case core::BuiltinFn::kTextureSampleGrad:
             out << "textureGrad";
             break;
-        case core::Function::kTextureSampleCompare:
-        case core::Function::kTextureSampleCompareLevel:
+        case core::BuiltinFn::kTextureSampleCompare:
+        case core::BuiltinFn::kTextureSampleCompareLevel:
             out << "texture";
             glsl_ret_width = 1;
             break;
-        case core::Function::kTextureLoad:
+        case core::BuiltinFn::kTextureLoad:
             if (texture_type->Is<core::type::StorageTexture>()) {
                 out << "imageLoad";
             } else {
                 out << "texelFetch";
             }
             break;
-        case core::Function::kTextureStore:
+        case core::BuiltinFn::kTextureStore:
             out << "imageStore";
             break;
         default:
@@ -1578,7 +1577,7 @@
     }
 
     // GLSL's textureGather always requires a refZ parameter.
-    if (is_depth && builtin->Type() == core::Function::kTextureGather) {
+    if (is_depth && builtin->Fn() == core::BuiltinFn::kTextureGather) {
         out << ", 0.0";
     }
 
@@ -1587,7 +1586,7 @@
         if (auto* e = arg(Usage::kDepthRef)) {
             out << ", ";
             EmitExpression(out, e);
-        } else if (builtin->Type() == core::Function::kTextureSample) {
+        } else if (builtin->Fn() == core::BuiltinFn::kTextureSample) {
             out << ", 0.0f";
         }
     }
@@ -1620,121 +1619,121 @@
     if (TINT_UNLIKELY(wgsl_ret_width > glsl_ret_width)) {
         TINT_ICE() << "WGSL return width (" << wgsl_ret_width
                    << ") is wider than GLSL return width (" << glsl_ret_width << ") for "
-                   << builtin->Type();
+                   << builtin->Fn();
         return;
     }
 }
 
-std::string ASTPrinter::generate_builtin_name(const sem::Builtin* builtin) {
-    switch (builtin->Type()) {
-        case core::Function::kAbs:
-        case core::Function::kAcos:
-        case core::Function::kAcosh:
-        case core::Function::kAll:
-        case core::Function::kAny:
-        case core::Function::kAsin:
-        case core::Function::kAsinh:
-        case core::Function::kAtan:
-        case core::Function::kAtanh:
-        case core::Function::kCeil:
-        case core::Function::kClamp:
-        case core::Function::kCos:
-        case core::Function::kCosh:
-        case core::Function::kCross:
-        case core::Function::kDeterminant:
-        case core::Function::kDistance:
-        case core::Function::kDot:
-        case core::Function::kExp:
-        case core::Function::kExp2:
-        case core::Function::kFloor:
-        case core::Function::kFrexp:
-        case core::Function::kLdexp:
-        case core::Function::kLength:
-        case core::Function::kLog:
-        case core::Function::kLog2:
-        case core::Function::kMax:
-        case core::Function::kMin:
-        case core::Function::kModf:
-        case core::Function::kNormalize:
-        case core::Function::kPow:
-        case core::Function::kReflect:
-        case core::Function::kRefract:
-        case core::Function::kRound:
-        case core::Function::kSign:
-        case core::Function::kSin:
-        case core::Function::kSinh:
-        case core::Function::kSqrt:
-        case core::Function::kStep:
-        case core::Function::kTan:
-        case core::Function::kTanh:
-        case core::Function::kTranspose:
-        case core::Function::kTrunc:
+std::string ASTPrinter::generate_builtin_name(const sem::BuiltinFn* builtin) {
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kAbs:
+        case core::BuiltinFn::kAcos:
+        case core::BuiltinFn::kAcosh:
+        case core::BuiltinFn::kAll:
+        case core::BuiltinFn::kAny:
+        case core::BuiltinFn::kAsin:
+        case core::BuiltinFn::kAsinh:
+        case core::BuiltinFn::kAtan:
+        case core::BuiltinFn::kAtanh:
+        case core::BuiltinFn::kCeil:
+        case core::BuiltinFn::kClamp:
+        case core::BuiltinFn::kCos:
+        case core::BuiltinFn::kCosh:
+        case core::BuiltinFn::kCross:
+        case core::BuiltinFn::kDeterminant:
+        case core::BuiltinFn::kDistance:
+        case core::BuiltinFn::kDot:
+        case core::BuiltinFn::kExp:
+        case core::BuiltinFn::kExp2:
+        case core::BuiltinFn::kFloor:
+        case core::BuiltinFn::kFrexp:
+        case core::BuiltinFn::kLdexp:
+        case core::BuiltinFn::kLength:
+        case core::BuiltinFn::kLog:
+        case core::BuiltinFn::kLog2:
+        case core::BuiltinFn::kMax:
+        case core::BuiltinFn::kMin:
+        case core::BuiltinFn::kModf:
+        case core::BuiltinFn::kNormalize:
+        case core::BuiltinFn::kPow:
+        case core::BuiltinFn::kReflect:
+        case core::BuiltinFn::kRefract:
+        case core::BuiltinFn::kRound:
+        case core::BuiltinFn::kSign:
+        case core::BuiltinFn::kSin:
+        case core::BuiltinFn::kSinh:
+        case core::BuiltinFn::kSqrt:
+        case core::BuiltinFn::kStep:
+        case core::BuiltinFn::kTan:
+        case core::BuiltinFn::kTanh:
+        case core::BuiltinFn::kTranspose:
+        case core::BuiltinFn::kTrunc:
             return builtin->str();
-        case core::Function::kAtan2:
+        case core::BuiltinFn::kAtan2:
             return "atan";
-        case core::Function::kCountOneBits:
+        case core::BuiltinFn::kCountOneBits:
             return "bitCount";
-        case core::Function::kDpdx:
+        case core::BuiltinFn::kDpdx:
             return "dFdx";
-        case core::Function::kDpdxCoarse:
+        case core::BuiltinFn::kDpdxCoarse:
             if (version_.IsES()) {
                 return "dFdx";
             }
             return "dFdxCoarse";
-        case core::Function::kDpdxFine:
+        case core::BuiltinFn::kDpdxFine:
             if (version_.IsES()) {
                 return "dFdx";
             }
             return "dFdxFine";
-        case core::Function::kDpdy:
+        case core::BuiltinFn::kDpdy:
             return "dFdy";
-        case core::Function::kDpdyCoarse:
+        case core::BuiltinFn::kDpdyCoarse:
             if (version_.IsES()) {
                 return "dFdy";
             }
             return "dFdyCoarse";
-        case core::Function::kDpdyFine:
+        case core::BuiltinFn::kDpdyFine:
             if (version_.IsES()) {
                 return "dFdy";
             }
             return "dFdyFine";
-        case core::Function::kFaceForward:
+        case core::BuiltinFn::kFaceForward:
             return "faceforward";
-        case core::Function::kFract:
+        case core::BuiltinFn::kFract:
             return "fract";
-        case core::Function::kFma:
+        case core::BuiltinFn::kFma:
             return "fma";
-        case core::Function::kFwidth:
-        case core::Function::kFwidthCoarse:
-        case core::Function::kFwidthFine:
+        case core::BuiltinFn::kFwidth:
+        case core::BuiltinFn::kFwidthCoarse:
+        case core::BuiltinFn::kFwidthFine:
             return "fwidth";
-        case core::Function::kInverseSqrt:
+        case core::BuiltinFn::kInverseSqrt:
             return "inversesqrt";
-        case core::Function::kMix:
+        case core::BuiltinFn::kMix:
             return "mix";
-        case core::Function::kPack2X16Float:
+        case core::BuiltinFn::kPack2X16Float:
             return "packHalf2x16";
-        case core::Function::kPack2X16Snorm:
+        case core::BuiltinFn::kPack2X16Snorm:
             return "packSnorm2x16";
-        case core::Function::kPack2X16Unorm:
+        case core::BuiltinFn::kPack2X16Unorm:
             return "packUnorm2x16";
-        case core::Function::kPack4X8Snorm:
+        case core::BuiltinFn::kPack4X8Snorm:
             return "packSnorm4x8";
-        case core::Function::kPack4X8Unorm:
+        case core::BuiltinFn::kPack4X8Unorm:
             return "packUnorm4x8";
-        case core::Function::kReverseBits:
+        case core::BuiltinFn::kReverseBits:
             return "bitfieldReverse";
-        case core::Function::kSmoothstep:
+        case core::BuiltinFn::kSmoothstep:
             return "smoothstep";
-        case core::Function::kUnpack2X16Float:
+        case core::BuiltinFn::kUnpack2X16Float:
             return "unpackHalf2x16";
-        case core::Function::kUnpack2X16Snorm:
+        case core::BuiltinFn::kUnpack2X16Snorm:
             return "unpackSnorm2x16";
-        case core::Function::kUnpack2X16Unorm:
+        case core::BuiltinFn::kUnpack2X16Unorm:
             return "unpackUnorm2x16";
-        case core::Function::kUnpack4X8Snorm:
+        case core::BuiltinFn::kUnpack4X8Snorm:
             return "unpackSnorm4x8";
-        case core::Function::kUnpack4X8Unorm:
+        case core::BuiltinFn::kUnpack4X8Unorm:
             return "unpackUnorm4x8";
         default:
             diagnostics_.add_error(diag::System::Writer,
@@ -2956,14 +2955,14 @@
 template <typename F>
 void ASTPrinter::CallBuiltinHelper(StringStream& out,
                                    const ast::CallExpression* call,
-                                   const sem::Builtin* builtin,
+                                   const sem::BuiltinFn* builtin,
                                    F&& build) {
     // Generate the helper function if it hasn't been created already
     auto fn = tint::GetOrCreate(builtins_, builtin, [&]() -> std::string {
         TextBuffer b;
         TINT_DEFER(helpers_.Append(b));
 
-        auto fn_name = UniqueIdentifier(std::string("tint_") + core::str(builtin->Type()));
+        auto fn_name = UniqueIdentifier(std::string("tint_") + core::str(builtin->Fn()));
         std::vector<std::string> parameter_names;
         {
             auto decl = Line(&b);
diff --git a/src/tint/lang/glsl/writer/ast_printer/ast_printer.h b/src/tint/lang/glsl/writer/ast_printer/ast_printer.h
index ad44120..eafc002 100644
--- a/src/tint/lang/glsl/writer/ast_printer/ast_printer.h
+++ b/src/tint/lang/glsl/writer/ast_printer/ast_printer.h
@@ -32,7 +32,7 @@
 
 // Forward declarations
 namespace tint::sem {
-class Builtin;
+class BuiltinFn;
 class Call;
 class ValueConstructor;
 class ValueConversion;
@@ -143,7 +143,7 @@
     /// @param out the output of the expression stream
     /// @param call the call expression
     /// @param builtin the builtin being called
-    void EmitBuiltinCall(StringStream& out, const sem::Call* call, const sem::Builtin* builtin);
+    void EmitBuiltinCall(StringStream& out, const sem::Call* call, const sem::BuiltinFn* builtin);
     /// Handles generating a value conversion expression
     /// @param out the output of the expression stream
     /// @param call the call expression
@@ -161,14 +161,14 @@
     /// Handles generating a barrier builtin call
     /// @param out the output of the expression stream
     /// @param builtin the semantic information for the barrier builtin
-    void EmitBarrierCall(StringStream& out, const sem::Builtin* builtin);
+    void EmitBarrierCall(StringStream& out, const sem::BuiltinFn* builtin);
     /// Handles generating an atomic builtin call for a workgroup variable
     /// @param out the output of the expression stream
     /// @param expr the call expression
     /// @param builtin the semantic information for the atomic builtin
     void EmitWorkgroupAtomicCall(StringStream& out,
                                  const ast::CallExpression* expr,
-                                 const sem::Builtin* builtin);
+                                 const sem::BuiltinFn* builtin);
     /// Handles generating an array.length() call
     /// @param out the output of the expression stream
     /// @param expr the call expression
@@ -195,7 +195,7 @@
     /// @param out the output of the expression stream
     /// @param call the call expression
     /// @param builtin the semantic information for the texture builtin
-    void EmitTextureCall(StringStream& out, const sem::Call* call, const sem::Builtin* builtin);
+    void EmitTextureCall(StringStream& out, const sem::Call* call, const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `select()` builtin
     /// @param out the output of the expression stream
     /// @param expr the call expression
@@ -206,49 +206,49 @@
     /// @param builtin the semantic information for the builtin
     void EmitSelectCall(StringStream& out,
                         const ast::CallExpression* expr,
-                        const sem::Builtin* builtin);
+                        const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `dot()` builtin
     /// @param out the output of the expression stream
     /// @param expr the call expression
     /// @param builtin the semantic information for the builtin
     void EmitDotCall(StringStream& out,
                      const ast::CallExpression* expr,
-                     const sem::Builtin* builtin);
+                     const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `modf()` builtin
     /// @param out the output of the expression stream
     /// @param expr the call expression
     /// @param builtin the semantic information for the builtin
     void EmitModfCall(StringStream& out,
                       const ast::CallExpression* expr,
-                      const sem::Builtin* builtin);
+                      const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `frexp()` builtin
     /// @param out the output of the expression stream
     /// @param expr the call expression
     /// @param builtin the semantic information for the builtin
     void EmitFrexpCall(StringStream& out,
                        const ast::CallExpression* expr,
-                       const sem::Builtin* builtin);
+                       const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `degrees()` builtin
     /// @param out the output of the expression stream
     /// @param expr the call expression
     /// @param builtin the semantic information for the builtin
     void EmitDegreesCall(StringStream& out,
                          const ast::CallExpression* expr,
-                         const sem::Builtin* builtin);
+                         const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `radians()` builtin
     /// @param out the output of the expression stream
     /// @param expr the call expression
     /// @param builtin the semantic information for the builtin
     void EmitRadiansCall(StringStream& out,
                          const ast::CallExpression* expr,
-                         const sem::Builtin* builtin);
+                         const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `quantizeToF16()` intrinsic
     /// @param out the output of the expression stream
     /// @param expr the call expression
     /// @param builtin the semantic information for the builtin
     void EmitQuantizeToF16Call(StringStream& out,
                                const ast::CallExpression* expr,
-                               const sem::Builtin* builtin);
+                               const sem::BuiltinFn* builtin);
     /// Handles a case statement
     /// @param stmt the statement
     void EmitCase(const ast::CaseStatement* stmt);
@@ -402,7 +402,7 @@
     /// Handles generating a builtin method name
     /// @param builtin the semantic info for the builtin
     /// @returns the name or "" if not valid
-    std::string generate_builtin_name(const sem::Builtin* builtin);
+    std::string generate_builtin_name(const sem::BuiltinFn* builtin);
     /// Converts a builtin to a gl_ string
     /// @param builtin the builtin to convert
     /// @param stage pipeline stage in which this builtin is used
@@ -440,7 +440,7 @@
     template <typename F>
     void CallBuiltinHelper(StringStream& out,
                            const ast::CallExpression* call,
-                           const sem::Builtin* builtin,
+                           const sem::BuiltinFn* builtin,
                            F&& build);
 
     /// Create a uint type corresponding to the given bool or bool vector type.
@@ -473,7 +473,7 @@
     /// Map of builtin structure to unique generated name
     std::unordered_map<const core::type::Struct*, std::string> builtin_struct_names_;
     std::function<void()> emit_continuing_;
-    std::unordered_map<const sem::Builtin*, std::string> builtins_;
+    std::unordered_map<const sem::BuiltinFn*, std::string> builtins_;
     std::unordered_map<const core::type::Vector*, std::string> dynamic_vector_write_;
     std::unordered_map<const core::type::Vector*, std::string> int_dot_funcs_;
     std::unordered_map<BinaryOperandType, std::string> float_modulo_funcs_;
diff --git a/src/tint/lang/glsl/writer/ast_printer/builtin_test.cc b/src/tint/lang/glsl/writer/ast_printer/builtin_test.cc
index 2694b2c..c23b308 100644
--- a/src/tint/lang/glsl/writer/ast_printer/builtin_test.cc
+++ b/src/tint/lang/glsl/writer/ast_printer/builtin_test.cc
@@ -36,7 +36,7 @@
 };
 
 struct BuiltinData {
-    core::Function builtin;
+    core::BuiltinFn builtin;
     CallParamType type;
     const char* glsl_name;
 };
@@ -60,86 +60,86 @@
     return out;
 }
 
-const ast::CallExpression* GenerateCall(core::Function builtin,
+const ast::CallExpression* GenerateCall(core::BuiltinFn builtin,
                                         CallParamType type,
                                         ProgramBuilder* builder) {
     std::string name;
     StringStream str;
     str << name << builtin;
     switch (builtin) {
-        case core::Function::kAcos:
-        case core::Function::kAsin:
-        case core::Function::kAtan:
-        case core::Function::kCeil:
-        case core::Function::kCos:
-        case core::Function::kCosh:
-        case core::Function::kDpdx:
-        case core::Function::kDpdxCoarse:
-        case core::Function::kDpdxFine:
-        case core::Function::kDpdy:
-        case core::Function::kDpdyCoarse:
-        case core::Function::kDpdyFine:
-        case core::Function::kExp:
-        case core::Function::kExp2:
-        case core::Function::kFloor:
-        case core::Function::kFract:
-        case core::Function::kFwidth:
-        case core::Function::kFwidthCoarse:
-        case core::Function::kFwidthFine:
-        case core::Function::kInverseSqrt:
-        case core::Function::kLength:
-        case core::Function::kLog:
-        case core::Function::kLog2:
-        case core::Function::kNormalize:
-        case core::Function::kRound:
-        case core::Function::kSin:
-        case core::Function::kSinh:
-        case core::Function::kSqrt:
-        case core::Function::kTan:
-        case core::Function::kTanh:
-        case core::Function::kTrunc:
-        case core::Function::kSign:
+        case core::BuiltinFn::kAcos:
+        case core::BuiltinFn::kAsin:
+        case core::BuiltinFn::kAtan:
+        case core::BuiltinFn::kCeil:
+        case core::BuiltinFn::kCos:
+        case core::BuiltinFn::kCosh:
+        case core::BuiltinFn::kDpdx:
+        case core::BuiltinFn::kDpdxCoarse:
+        case core::BuiltinFn::kDpdxFine:
+        case core::BuiltinFn::kDpdy:
+        case core::BuiltinFn::kDpdyCoarse:
+        case core::BuiltinFn::kDpdyFine:
+        case core::BuiltinFn::kExp:
+        case core::BuiltinFn::kExp2:
+        case core::BuiltinFn::kFloor:
+        case core::BuiltinFn::kFract:
+        case core::BuiltinFn::kFwidth:
+        case core::BuiltinFn::kFwidthCoarse:
+        case core::BuiltinFn::kFwidthFine:
+        case core::BuiltinFn::kInverseSqrt:
+        case core::BuiltinFn::kLength:
+        case core::BuiltinFn::kLog:
+        case core::BuiltinFn::kLog2:
+        case core::BuiltinFn::kNormalize:
+        case core::BuiltinFn::kRound:
+        case core::BuiltinFn::kSin:
+        case core::BuiltinFn::kSinh:
+        case core::BuiltinFn::kSqrt:
+        case core::BuiltinFn::kTan:
+        case core::BuiltinFn::kTanh:
+        case core::BuiltinFn::kTrunc:
+        case core::BuiltinFn::kSign:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2");
             } else {
                 return builder->Call(str.str(), "f2");
             }
-        case core::Function::kLdexp:
+        case core::BuiltinFn::kLdexp:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "i2");
             } else {
                 return builder->Call(str.str(), "f2", "i2");
             }
-        case core::Function::kAtan2:
-        case core::Function::kDot:
-        case core::Function::kDistance:
-        case core::Function::kPow:
-        case core::Function::kReflect:
-        case core::Function::kStep:
+        case core::BuiltinFn::kAtan2:
+        case core::BuiltinFn::kDot:
+        case core::BuiltinFn::kDistance:
+        case core::BuiltinFn::kPow:
+        case core::BuiltinFn::kReflect:
+        case core::BuiltinFn::kStep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2");
             }
-        case core::Function::kCross:
+        case core::BuiltinFn::kCross:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h3", "h3");
             } else {
                 return builder->Call(str.str(), "f3", "f3");
             }
-        case core::Function::kFma:
-        case core::Function::kMix:
-        case core::Function::kFaceForward:
-        case core::Function::kSmoothstep:
+        case core::BuiltinFn::kFma:
+        case core::BuiltinFn::kMix:
+        case core::BuiltinFn::kFaceForward:
+        case core::BuiltinFn::kSmoothstep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             }
-        case core::Function::kAll:
-        case core::Function::kAny:
+        case core::BuiltinFn::kAll:
+        case core::BuiltinFn::kAny:
             return builder->Call(str.str(), "b2");
-        case core::Function::kAbs:
+        case core::BuiltinFn::kAbs:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2");
             } else if (type == CallParamType::kF16) {
@@ -147,11 +147,11 @@
             } else {
                 return builder->Call(str.str(), "u2");
             }
-        case core::Function::kCountOneBits:
-        case core::Function::kReverseBits:
+        case core::BuiltinFn::kCountOneBits:
+        case core::BuiltinFn::kReverseBits:
             return builder->Call(str.str(), "u2");
-        case core::Function::kMax:
-        case core::Function::kMin:
+        case core::BuiltinFn::kMax:
+        case core::BuiltinFn::kMin:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -159,7 +159,7 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2");
             }
-        case core::Function::kClamp:
+        case core::BuiltinFn::kClamp:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -167,19 +167,19 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2", "u2");
             }
-        case core::Function::kSelect:
+        case core::BuiltinFn::kSelect:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "b2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "b2");
             }
-        case core::Function::kDeterminant:
+        case core::BuiltinFn::kDeterminant:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm2x2");
             } else {
                 return builder->Call(str.str(), "m2x2");
             }
-        case core::Function::kTranspose:
+        case core::BuiltinFn::kTranspose:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm3x2");
             } else {
@@ -225,7 +225,7 @@
     ASSERT_NE(sem, nullptr);
     auto* target = sem->Target();
     ASSERT_NE(target, nullptr);
-    auto* builtin = target->As<sem::Builtin>();
+    auto* builtin = target->As<sem::BuiltinFn>();
     ASSERT_NE(builtin, nullptr);
 
     EXPECT_EQ(gen.generate_builtin_name(builtin), param.glsl_name);
@@ -234,110 +234,110 @@
     GlslASTPrinterTest_Builtin,
     GlslBuiltinTest,
     testing::Values(/* Logical built-in */
-                    BuiltinData{core::Function::kAll, CallParamType::kBool, "all"},
-                    BuiltinData{core::Function::kAny, CallParamType::kBool, "any"},
+                    BuiltinData{core::BuiltinFn::kAll, CallParamType::kBool, "all"},
+                    BuiltinData{core::BuiltinFn::kAny, CallParamType::kBool, "any"},
                     /* Float built-in */
-                    BuiltinData{core::Function::kAbs, CallParamType::kF32, "abs"},
-                    BuiltinData{core::Function::kAbs, CallParamType::kF16, "abs"},
-                    BuiltinData{core::Function::kAcos, CallParamType::kF32, "acos"},
-                    BuiltinData{core::Function::kAcos, CallParamType::kF16, "acos"},
-                    BuiltinData{core::Function::kAsin, CallParamType::kF32, "asin"},
-                    BuiltinData{core::Function::kAsin, CallParamType::kF16, "asin"},
-                    BuiltinData{core::Function::kAtan, CallParamType::kF32, "atan"},
-                    BuiltinData{core::Function::kAtan, CallParamType::kF16, "atan"},
-                    BuiltinData{core::Function::kAtan2, CallParamType::kF32, "atan"},
-                    BuiltinData{core::Function::kAtan2, CallParamType::kF16, "atan"},
-                    BuiltinData{core::Function::kCeil, CallParamType::kF32, "ceil"},
-                    BuiltinData{core::Function::kCeil, CallParamType::kF16, "ceil"},
-                    BuiltinData{core::Function::kClamp, CallParamType::kF32, "clamp"},
-                    BuiltinData{core::Function::kClamp, CallParamType::kF16, "clamp"},
-                    BuiltinData{core::Function::kCos, CallParamType::kF32, "cos"},
-                    BuiltinData{core::Function::kCos, CallParamType::kF16, "cos"},
-                    BuiltinData{core::Function::kCosh, CallParamType::kF32, "cosh"},
-                    BuiltinData{core::Function::kCosh, CallParamType::kF16, "cosh"},
-                    BuiltinData{core::Function::kCross, CallParamType::kF32, "cross"},
-                    BuiltinData{core::Function::kCross, CallParamType::kF16, "cross"},
-                    BuiltinData{core::Function::kDistance, CallParamType::kF32, "distance"},
-                    BuiltinData{core::Function::kDistance, CallParamType::kF16, "distance"},
-                    BuiltinData{core::Function::kExp, CallParamType::kF32, "exp"},
-                    BuiltinData{core::Function::kExp, CallParamType::kF16, "exp"},
-                    BuiltinData{core::Function::kExp2, CallParamType::kF32, "exp2"},
-                    BuiltinData{core::Function::kExp2, CallParamType::kF16, "exp2"},
-                    BuiltinData{core::Function::kFaceForward, CallParamType::kF32, "faceforward"},
-                    BuiltinData{core::Function::kFaceForward, CallParamType::kF16, "faceforward"},
-                    BuiltinData{core::Function::kFloor, CallParamType::kF32, "floor"},
-                    BuiltinData{core::Function::kFloor, CallParamType::kF16, "floor"},
-                    BuiltinData{core::Function::kFma, CallParamType::kF32, "fma"},
-                    BuiltinData{core::Function::kFma, CallParamType::kF16, "fma"},
-                    BuiltinData{core::Function::kFract, CallParamType::kF32, "fract"},
-                    BuiltinData{core::Function::kFract, CallParamType::kF16, "fract"},
-                    BuiltinData{core::Function::kInverseSqrt, CallParamType::kF32, "inversesqrt"},
-                    BuiltinData{core::Function::kInverseSqrt, CallParamType::kF16, "inversesqrt"},
-                    BuiltinData{core::Function::kLdexp, CallParamType::kF32, "ldexp"},
-                    BuiltinData{core::Function::kLdexp, CallParamType::kF16, "ldexp"},
-                    BuiltinData{core::Function::kLength, CallParamType::kF32, "length"},
-                    BuiltinData{core::Function::kLength, CallParamType::kF16, "length"},
-                    BuiltinData{core::Function::kLog, CallParamType::kF32, "log"},
-                    BuiltinData{core::Function::kLog, CallParamType::kF16, "log"},
-                    BuiltinData{core::Function::kLog2, CallParamType::kF32, "log2"},
-                    BuiltinData{core::Function::kLog2, CallParamType::kF16, "log2"},
-                    BuiltinData{core::Function::kMax, CallParamType::kF32, "max"},
-                    BuiltinData{core::Function::kMax, CallParamType::kF16, "max"},
-                    BuiltinData{core::Function::kMin, CallParamType::kF32, "min"},
-                    BuiltinData{core::Function::kMin, CallParamType::kF16, "min"},
-                    BuiltinData{core::Function::kMix, CallParamType::kF32, "mix"},
-                    BuiltinData{core::Function::kMix, CallParamType::kF16, "mix"},
-                    BuiltinData{core::Function::kNormalize, CallParamType::kF32, "normalize"},
-                    BuiltinData{core::Function::kNormalize, CallParamType::kF16, "normalize"},
-                    BuiltinData{core::Function::kPow, CallParamType::kF32, "pow"},
-                    BuiltinData{core::Function::kPow, CallParamType::kF16, "pow"},
-                    BuiltinData{core::Function::kReflect, CallParamType::kF32, "reflect"},
-                    BuiltinData{core::Function::kReflect, CallParamType::kF16, "reflect"},
-                    BuiltinData{core::Function::kSign, CallParamType::kF32, "sign"},
-                    BuiltinData{core::Function::kSign, CallParamType::kF16, "sign"},
-                    BuiltinData{core::Function::kSin, CallParamType::kF32, "sin"},
-                    BuiltinData{core::Function::kSin, CallParamType::kF16, "sin"},
-                    BuiltinData{core::Function::kSinh, CallParamType::kF32, "sinh"},
-                    BuiltinData{core::Function::kSinh, CallParamType::kF16, "sinh"},
-                    BuiltinData{core::Function::kSmoothstep, CallParamType::kF32, "smoothstep"},
-                    BuiltinData{core::Function::kSmoothstep, CallParamType::kF16, "smoothstep"},
-                    BuiltinData{core::Function::kSqrt, CallParamType::kF32, "sqrt"},
-                    BuiltinData{core::Function::kSqrt, CallParamType::kF16, "sqrt"},
-                    BuiltinData{core::Function::kStep, CallParamType::kF32, "step"},
-                    BuiltinData{core::Function::kStep, CallParamType::kF16, "step"},
-                    BuiltinData{core::Function::kTan, CallParamType::kF32, "tan"},
-                    BuiltinData{core::Function::kTan, CallParamType::kF16, "tan"},
-                    BuiltinData{core::Function::kTanh, CallParamType::kF32, "tanh"},
-                    BuiltinData{core::Function::kTanh, CallParamType::kF16, "tanh"},
-                    BuiltinData{core::Function::kTrunc, CallParamType::kF32, "trunc"},
-                    BuiltinData{core::Function::kTrunc, CallParamType::kF16, "trunc"},
+                    BuiltinData{core::BuiltinFn::kAbs, CallParamType::kF32, "abs"},
+                    BuiltinData{core::BuiltinFn::kAbs, CallParamType::kF16, "abs"},
+                    BuiltinData{core::BuiltinFn::kAcos, CallParamType::kF32, "acos"},
+                    BuiltinData{core::BuiltinFn::kAcos, CallParamType::kF16, "acos"},
+                    BuiltinData{core::BuiltinFn::kAsin, CallParamType::kF32, "asin"},
+                    BuiltinData{core::BuiltinFn::kAsin, CallParamType::kF16, "asin"},
+                    BuiltinData{core::BuiltinFn::kAtan, CallParamType::kF32, "atan"},
+                    BuiltinData{core::BuiltinFn::kAtan, CallParamType::kF16, "atan"},
+                    BuiltinData{core::BuiltinFn::kAtan2, CallParamType::kF32, "atan"},
+                    BuiltinData{core::BuiltinFn::kAtan2, CallParamType::kF16, "atan"},
+                    BuiltinData{core::BuiltinFn::kCeil, CallParamType::kF32, "ceil"},
+                    BuiltinData{core::BuiltinFn::kCeil, CallParamType::kF16, "ceil"},
+                    BuiltinData{core::BuiltinFn::kClamp, CallParamType::kF32, "clamp"},
+                    BuiltinData{core::BuiltinFn::kClamp, CallParamType::kF16, "clamp"},
+                    BuiltinData{core::BuiltinFn::kCos, CallParamType::kF32, "cos"},
+                    BuiltinData{core::BuiltinFn::kCos, CallParamType::kF16, "cos"},
+                    BuiltinData{core::BuiltinFn::kCosh, CallParamType::kF32, "cosh"},
+                    BuiltinData{core::BuiltinFn::kCosh, CallParamType::kF16, "cosh"},
+                    BuiltinData{core::BuiltinFn::kCross, CallParamType::kF32, "cross"},
+                    BuiltinData{core::BuiltinFn::kCross, CallParamType::kF16, "cross"},
+                    BuiltinData{core::BuiltinFn::kDistance, CallParamType::kF32, "distance"},
+                    BuiltinData{core::BuiltinFn::kDistance, CallParamType::kF16, "distance"},
+                    BuiltinData{core::BuiltinFn::kExp, CallParamType::kF32, "exp"},
+                    BuiltinData{core::BuiltinFn::kExp, CallParamType::kF16, "exp"},
+                    BuiltinData{core::BuiltinFn::kExp2, CallParamType::kF32, "exp2"},
+                    BuiltinData{core::BuiltinFn::kExp2, CallParamType::kF16, "exp2"},
+                    BuiltinData{core::BuiltinFn::kFaceForward, CallParamType::kF32, "faceforward"},
+                    BuiltinData{core::BuiltinFn::kFaceForward, CallParamType::kF16, "faceforward"},
+                    BuiltinData{core::BuiltinFn::kFloor, CallParamType::kF32, "floor"},
+                    BuiltinData{core::BuiltinFn::kFloor, CallParamType::kF16, "floor"},
+                    BuiltinData{core::BuiltinFn::kFma, CallParamType::kF32, "fma"},
+                    BuiltinData{core::BuiltinFn::kFma, CallParamType::kF16, "fma"},
+                    BuiltinData{core::BuiltinFn::kFract, CallParamType::kF32, "fract"},
+                    BuiltinData{core::BuiltinFn::kFract, CallParamType::kF16, "fract"},
+                    BuiltinData{core::BuiltinFn::kInverseSqrt, CallParamType::kF32, "inversesqrt"},
+                    BuiltinData{core::BuiltinFn::kInverseSqrt, CallParamType::kF16, "inversesqrt"},
+                    BuiltinData{core::BuiltinFn::kLdexp, CallParamType::kF32, "ldexp"},
+                    BuiltinData{core::BuiltinFn::kLdexp, CallParamType::kF16, "ldexp"},
+                    BuiltinData{core::BuiltinFn::kLength, CallParamType::kF32, "length"},
+                    BuiltinData{core::BuiltinFn::kLength, CallParamType::kF16, "length"},
+                    BuiltinData{core::BuiltinFn::kLog, CallParamType::kF32, "log"},
+                    BuiltinData{core::BuiltinFn::kLog, CallParamType::kF16, "log"},
+                    BuiltinData{core::BuiltinFn::kLog2, CallParamType::kF32, "log2"},
+                    BuiltinData{core::BuiltinFn::kLog2, CallParamType::kF16, "log2"},
+                    BuiltinData{core::BuiltinFn::kMax, CallParamType::kF32, "max"},
+                    BuiltinData{core::BuiltinFn::kMax, CallParamType::kF16, "max"},
+                    BuiltinData{core::BuiltinFn::kMin, CallParamType::kF32, "min"},
+                    BuiltinData{core::BuiltinFn::kMin, CallParamType::kF16, "min"},
+                    BuiltinData{core::BuiltinFn::kMix, CallParamType::kF32, "mix"},
+                    BuiltinData{core::BuiltinFn::kMix, CallParamType::kF16, "mix"},
+                    BuiltinData{core::BuiltinFn::kNormalize, CallParamType::kF32, "normalize"},
+                    BuiltinData{core::BuiltinFn::kNormalize, CallParamType::kF16, "normalize"},
+                    BuiltinData{core::BuiltinFn::kPow, CallParamType::kF32, "pow"},
+                    BuiltinData{core::BuiltinFn::kPow, CallParamType::kF16, "pow"},
+                    BuiltinData{core::BuiltinFn::kReflect, CallParamType::kF32, "reflect"},
+                    BuiltinData{core::BuiltinFn::kReflect, CallParamType::kF16, "reflect"},
+                    BuiltinData{core::BuiltinFn::kSign, CallParamType::kF32, "sign"},
+                    BuiltinData{core::BuiltinFn::kSign, CallParamType::kF16, "sign"},
+                    BuiltinData{core::BuiltinFn::kSin, CallParamType::kF32, "sin"},
+                    BuiltinData{core::BuiltinFn::kSin, CallParamType::kF16, "sin"},
+                    BuiltinData{core::BuiltinFn::kSinh, CallParamType::kF32, "sinh"},
+                    BuiltinData{core::BuiltinFn::kSinh, CallParamType::kF16, "sinh"},
+                    BuiltinData{core::BuiltinFn::kSmoothstep, CallParamType::kF32, "smoothstep"},
+                    BuiltinData{core::BuiltinFn::kSmoothstep, CallParamType::kF16, "smoothstep"},
+                    BuiltinData{core::BuiltinFn::kSqrt, CallParamType::kF32, "sqrt"},
+                    BuiltinData{core::BuiltinFn::kSqrt, CallParamType::kF16, "sqrt"},
+                    BuiltinData{core::BuiltinFn::kStep, CallParamType::kF32, "step"},
+                    BuiltinData{core::BuiltinFn::kStep, CallParamType::kF16, "step"},
+                    BuiltinData{core::BuiltinFn::kTan, CallParamType::kF32, "tan"},
+                    BuiltinData{core::BuiltinFn::kTan, CallParamType::kF16, "tan"},
+                    BuiltinData{core::BuiltinFn::kTanh, CallParamType::kF32, "tanh"},
+                    BuiltinData{core::BuiltinFn::kTanh, CallParamType::kF16, "tanh"},
+                    BuiltinData{core::BuiltinFn::kTrunc, CallParamType::kF32, "trunc"},
+                    BuiltinData{core::BuiltinFn::kTrunc, CallParamType::kF16, "trunc"},
                     /* Integer built-in */
-                    BuiltinData{core::Function::kAbs, CallParamType::kU32, "abs"},
-                    BuiltinData{core::Function::kClamp, CallParamType::kU32, "clamp"},
-                    BuiltinData{core::Function::kCountOneBits, CallParamType::kU32, "bitCount"},
-                    BuiltinData{core::Function::kMax, CallParamType::kU32, "max"},
-                    BuiltinData{core::Function::kMin, CallParamType::kU32, "min"},
-                    BuiltinData{core::Function::kReverseBits, CallParamType::kU32,
+                    BuiltinData{core::BuiltinFn::kAbs, CallParamType::kU32, "abs"},
+                    BuiltinData{core::BuiltinFn::kClamp, CallParamType::kU32, "clamp"},
+                    BuiltinData{core::BuiltinFn::kCountOneBits, CallParamType::kU32, "bitCount"},
+                    BuiltinData{core::BuiltinFn::kMax, CallParamType::kU32, "max"},
+                    BuiltinData{core::BuiltinFn::kMin, CallParamType::kU32, "min"},
+                    BuiltinData{core::BuiltinFn::kReverseBits, CallParamType::kU32,
                                 "bitfieldReverse"},
-                    BuiltinData{core::Function::kRound, CallParamType::kU32, "round"},
+                    BuiltinData{core::BuiltinFn::kRound, CallParamType::kU32, "round"},
                     /* Matrix built-in */
-                    BuiltinData{core::Function::kDeterminant, CallParamType::kF32, "determinant"},
-                    BuiltinData{core::Function::kDeterminant, CallParamType::kF16, "determinant"},
-                    BuiltinData{core::Function::kTranspose, CallParamType::kF32, "transpose"},
-                    BuiltinData{core::Function::kTranspose, CallParamType::kF16, "transpose"},
+                    BuiltinData{core::BuiltinFn::kDeterminant, CallParamType::kF32, "determinant"},
+                    BuiltinData{core::BuiltinFn::kDeterminant, CallParamType::kF16, "determinant"},
+                    BuiltinData{core::BuiltinFn::kTranspose, CallParamType::kF32, "transpose"},
+                    BuiltinData{core::BuiltinFn::kTranspose, CallParamType::kF16, "transpose"},
                     /* Vector built-in */
-                    BuiltinData{core::Function::kDot, CallParamType::kF32, "dot"},
-                    BuiltinData{core::Function::kDot, CallParamType::kF16, "dot"},
+                    BuiltinData{core::BuiltinFn::kDot, CallParamType::kF32, "dot"},
+                    BuiltinData{core::BuiltinFn::kDot, CallParamType::kF16, "dot"},
                     /* Derivate built-in */
-                    BuiltinData{core::Function::kDpdx, CallParamType::kF32, "dFdx"},
-                    BuiltinData{core::Function::kDpdxCoarse, CallParamType::kF32, "dFdx"},
-                    BuiltinData{core::Function::kDpdxFine, CallParamType::kF32, "dFdx"},
-                    BuiltinData{core::Function::kDpdy, CallParamType::kF32, "dFdy"},
-                    BuiltinData{core::Function::kDpdyCoarse, CallParamType::kF32, "dFdy"},
-                    BuiltinData{core::Function::kDpdyFine, CallParamType::kF32, "dFdy"},
-                    BuiltinData{core::Function::kFwidth, CallParamType::kF32, "fwidth"},
-                    BuiltinData{core::Function::kFwidthCoarse, CallParamType::kF32, "fwidth"},
-                    BuiltinData{core::Function::kFwidthFine, CallParamType::kF32, "fwidth"}));
+                    BuiltinData{core::BuiltinFn::kDpdx, CallParamType::kF32, "dFdx"},
+                    BuiltinData{core::BuiltinFn::kDpdxCoarse, CallParamType::kF32, "dFdx"},
+                    BuiltinData{core::BuiltinFn::kDpdxFine, CallParamType::kF32, "dFdx"},
+                    BuiltinData{core::BuiltinFn::kDpdy, CallParamType::kF32, "dFdy"},
+                    BuiltinData{core::BuiltinFn::kDpdyCoarse, CallParamType::kF32, "dFdy"},
+                    BuiltinData{core::BuiltinFn::kDpdyFine, CallParamType::kF32, "dFdy"},
+                    BuiltinData{core::BuiltinFn::kFwidth, CallParamType::kF32, "fwidth"},
+                    BuiltinData{core::BuiltinFn::kFwidthCoarse, CallParamType::kF32, "fwidth"},
+                    BuiltinData{core::BuiltinFn::kFwidthFine, CallParamType::kF32, "fwidth"}));
 
 TEST_F(GlslASTPrinterTest_Builtin, Builtin_Call) {
     auto* call = Call("dot", "param1", "param2");
diff --git a/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc b/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc
index 84647d0..a8f8267 100644
--- a/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc
+++ b/src/tint/lang/glsl/writer/ast_raise/combine_samplers.cc
@@ -226,7 +226,7 @@
             if (auto* call = sem.Get(expr)->UnwrapMaterialize()->As<sem::Call>()) {
                 Vector<const ast::Expression*, 8> args;
                 // Replace all texture builtin calls.
-                if (auto* builtin = call->Target()->As<sem::Builtin>()) {
+                if (auto* builtin = call->Target()->As<sem::BuiltinFn>()) {
                     const auto& signature = builtin->Signature();
                     auto sampler_index = signature.IndexOf(core::ParameterUsage::kSampler);
                     auto texture_index = signature.IndexOf(core::ParameterUsage::kTexture);
@@ -270,7 +270,7 @@
                         }
                     }
                     const ast::Expression* value = ctx.dst->Call(ctx.Clone(expr->target), args);
-                    if (builtin->Type() == core::Function::kTextureLoad &&
+                    if (builtin->Fn() == core::BuiltinFn::kTextureLoad &&
                         texture_var->Type()->UnwrapRef()->Is<core::type::DepthTexture>() &&
                         !call->Stmt()->Declaration()->Is<ast::CallStatement>()) {
                         value = ctx.dst->MemberAccessor(value, "x");
diff --git a/src/tint/lang/glsl/writer/ast_raise/texture_1d_to_2d.cc b/src/tint/lang/glsl/writer/ast_raise/texture_1d_to_2d.cc
index aa23d0b..9636e07 100644
--- a/src/tint/lang/glsl/writer/ast_raise/texture_1d_to_2d.cc
+++ b/src/tint/lang/glsl/writer/ast_raise/texture_1d_to_2d.cc
@@ -126,7 +126,7 @@
             if (!call) {
                 return nullptr;
             }
-            auto* builtin = call->Target()->As<sem::Builtin>();
+            auto* builtin = call->Target()->As<sem::BuiltinFn>();
             if (!builtin) {
                 return nullptr;
             }
@@ -140,7 +140,7 @@
                 return nullptr;
             }
 
-            if (builtin->Type() == core::Function::kTextureDimensions) {
+            if (builtin->Fn() == core::BuiltinFn::kTextureDimensions) {
                 // If this textureDimensions() call is in a CallStatement, we can leave it
                 // unmodified since the return value will be dropped on the floor anyway.
                 if (call->Stmt()->Declaration()->Is<ast::CallStatement>()) {
diff --git a/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc b/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc
index 02c056d..db883b0 100644
--- a/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc
+++ b/src/tint/lang/glsl/writer/ast_raise/texture_builtins_from_uniform.cc
@@ -51,10 +51,10 @@
             for (auto* builtin : sem_fn->DirectlyCalledBuiltins()) {
                 // GLSL ES  has no native support for the counterpart of
                 // textureNumLevels (textureQueryLevels) and textureNumSamples (textureSamples)
-                if (builtin->Type() == core::Function::kTextureNumLevels) {
+                if (builtin->Fn() == core::BuiltinFn::kTextureNumLevels) {
                     return true;
                 }
-                if (builtin->Type() == core::Function::kTextureNumSamples) {
+                if (builtin->Fn() == core::BuiltinFn::kTextureNumSamples) {
                     return true;
                 }
             }
@@ -110,9 +110,9 @@
 
                     tint::Switch(
                         call->Target(),
-                        [&](const sem::Builtin* builtin) {
-                            if (builtin->Type() != core::Function::kTextureNumLevels &&
-                                builtin->Type() != core::Function::kTextureNumSamples) {
+                        [&](const sem::BuiltinFn* builtin) {
+                            if (builtin->Fn() != core::BuiltinFn::kTextureNumLevels &&
+                                builtin->Fn() != core::BuiltinFn::kTextureNumSamples) {
                                 return;
                             }
                             if (auto* call_stmt =
@@ -131,7 +131,7 @@
                             TINT_ASSERT(texture_sem);
 
                             TextureBuiltinsFromUniformOptions::Field dataType =
-                                GetFieldFromBuiltinFunctionType(builtin->Type());
+                                GetFieldFromBuiltinFunctionType(builtin->Fn());
 
                             tint::Switch(
                                 texture_sem,
@@ -462,11 +462,11 @@
     /// @param type of the builtin function
     /// @returns corresponding TextureBuiltinsFromUniformOptions::Field for the builtin
     static TextureBuiltinsFromUniformOptions::Field GetFieldFromBuiltinFunctionType(
-        core::Function type) {
+        core::BuiltinFn type) {
         switch (type) {
-            case core::Function::kTextureNumLevels:
+            case core::BuiltinFn::kTextureNumLevels:
                 return TextureBuiltinsFromUniformOptions::Field::TextureNumLevels;
-            case core::Function::kTextureNumSamples:
+            case core::BuiltinFn::kTextureNumSamples:
                 return TextureBuiltinsFromUniformOptions::Field::TextureNumSamples;
             default:
                 TINT_UNREACHABLE() << "unsupported builtin function type " << type;
diff --git a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
index 20b7775..f51312a 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.cc
@@ -1087,7 +1087,7 @@
     return Switch(
         target,  //
         [&](const sem::Function* func) { return EmitFunctionCall(out, call, func); },
-        [&](const sem::Builtin* builtin) { return EmitBuiltinCall(out, call, builtin); },
+        [&](const sem::BuiltinFn* builtin) { return EmitBuiltinCall(out, call, builtin); },
         [&](const sem::ValueConversion* conv) { return EmitValueConversion(out, call, conv); },
         [&](const sem::ValueConstructor* ctor) { return EmitValueConstructor(out, call, ctor); },
         [&](Default) {
@@ -1166,35 +1166,35 @@
 
 bool ASTPrinter::EmitBuiltinCall(StringStream& out,
                                  const sem::Call* call,
-                                 const sem::Builtin* builtin) {
-    const auto type = builtin->Type();
+                                 const sem::BuiltinFn* builtin) {
+    const auto type = builtin->Fn();
 
     auto* expr = call->Declaration();
     if (builtin->IsTexture()) {
         return EmitTextureCall(out, call, builtin);
     }
-    if (type == core::Function::kSelect) {
+    if (type == core::BuiltinFn::kSelect) {
         return EmitSelectCall(out, expr);
     }
-    if (type == core::Function::kModf) {
+    if (type == core::BuiltinFn::kModf) {
         return EmitModfCall(out, expr, builtin);
     }
-    if (type == core::Function::kFrexp) {
+    if (type == core::BuiltinFn::kFrexp) {
         return EmitFrexpCall(out, expr, builtin);
     }
-    if (type == core::Function::kDegrees) {
+    if (type == core::BuiltinFn::kDegrees) {
         return EmitDegreesCall(out, expr, builtin);
     }
-    if (type == core::Function::kRadians) {
+    if (type == core::BuiltinFn::kRadians) {
         return EmitRadiansCall(out, expr, builtin);
     }
-    if (type == core::Function::kSign) {
+    if (type == core::BuiltinFn::kSign) {
         return EmitSignCall(out, call, builtin);
     }
-    if (type == core::Function::kQuantizeToF16) {
+    if (type == core::BuiltinFn::kQuantizeToF16) {
         return EmitQuantizeToF16Call(out, expr, builtin);
     }
-    if (type == core::Function::kTrunc) {
+    if (type == core::BuiltinFn::kTrunc) {
         return EmitTruncCall(out, expr, builtin);
     }
     if (builtin->IsDataPacking()) {
@@ -1213,7 +1213,7 @@
         return EmitDP4aCall(out, expr, builtin);
     }
     if (builtin->IsSubgroup()) {
-        if (builtin->Type() == core::Function::kSubgroupBroadcast) {
+        if (builtin->Fn() == core::BuiltinFn::kSubgroupBroadcast) {
             // Fall through the regular path.
         } else {
             return EmitSubgroupCall(out, expr, builtin);
@@ -1228,7 +1228,7 @@
     // Handle single argument builtins that only accept and return uint (not int overload). We need
     // to explicitly cast the return value (we also cast the arg for good measure). See
     // crbug.com/tint/1550
-    if (type == core::Function::kCountOneBits || type == core::Function::kReverseBits) {
+    if (type == core::BuiltinFn::kCountOneBits || type == core::BuiltinFn::kReverseBits) {
         auto* arg = call->Arguments()[0];
         if (arg->Type()->UnwrapRef()->is_signed_integer_scalar_or_vector()) {
             out << "asint(" << name << "(asuint(";
@@ -1991,7 +1991,7 @@
 
 bool ASTPrinter::EmitWorkgroupAtomicCall(StringStream& out,
                                          const ast::CallExpression* expr,
-                                         const sem::Builtin* builtin) {
+                                         const sem::BuiltinFn* builtin) {
     std::string result = UniqueIdentifier("atomic_result");
 
     if (!builtin->ReturnType()->Is<core::type::Void>()) {
@@ -2018,7 +2018,7 @@
                 if (i > 0) {
                     pre << ", ";
                 }
-                if (i == 1 && builtin->Type() == core::Function::kAtomicSub) {
+                if (i == 1 && builtin->Fn() == core::BuiltinFn::kAtomicSub) {
                     // Sub uses InterlockedAdd with the operand negated.
                     pre << "-";
                 }
@@ -2036,8 +2036,8 @@
         return true;
     };
 
-    switch (builtin->Type()) {
-        case core::Function::kAtomicLoad: {
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kAtomicLoad: {
             // HLSL does not have an InterlockedLoad, so we emulate it with
             // InterlockedOr using 0 as the OR value
             auto pre = Line();
@@ -2054,7 +2054,7 @@
             out << result;
             return true;
         }
-        case core::Function::kAtomicStore: {
+        case core::BuiltinFn::kAtomicStore: {
             // HLSL does not have an InterlockedStore, so we emulate it with
             // InterlockedExchange and discard the returned value
             {  // T result = 0;
@@ -2085,7 +2085,7 @@
             }
             return true;
         }
-        case core::Function::kAtomicCompareExchangeWeak: {
+        case core::BuiltinFn::kAtomicCompareExchangeWeak: {
             if (!EmitStructType(&helpers_, builtin->ReturnType()->As<core::type::Struct>())) {
                 return false;
             }
@@ -2134,33 +2134,33 @@
             return true;
         }
 
-        case core::Function::kAtomicAdd:
-        case core::Function::kAtomicSub:
+        case core::BuiltinFn::kAtomicAdd:
+        case core::BuiltinFn::kAtomicSub:
             return call("InterlockedAdd");
 
-        case core::Function::kAtomicMax:
+        case core::BuiltinFn::kAtomicMax:
             return call("InterlockedMax");
 
-        case core::Function::kAtomicMin:
+        case core::BuiltinFn::kAtomicMin:
             return call("InterlockedMin");
 
-        case core::Function::kAtomicAnd:
+        case core::BuiltinFn::kAtomicAnd:
             return call("InterlockedAnd");
 
-        case core::Function::kAtomicOr:
+        case core::BuiltinFn::kAtomicOr:
             return call("InterlockedOr");
 
-        case core::Function::kAtomicXor:
+        case core::BuiltinFn::kAtomicXor:
             return call("InterlockedXor");
 
-        case core::Function::kAtomicExchange:
+        case core::BuiltinFn::kAtomicExchange:
             return call("InterlockedExchange");
 
         default:
             break;
     }
 
-    TINT_UNREACHABLE() << "unsupported atomic builtin: " << builtin->Type();
+    TINT_UNREACHABLE() << "unsupported atomic builtin: " << builtin->Fn();
     return false;
 }
 
@@ -2190,7 +2190,7 @@
 
 bool ASTPrinter::EmitModfCall(StringStream& out,
                               const ast::CallExpression* expr,
-                              const sem::Builtin* builtin) {
+                              const sem::BuiltinFn* builtin) {
     return CallBuiltinHelper(
         out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
             auto* ty = builtin->Parameters()[0]->Type();
@@ -2223,7 +2223,7 @@
 
 bool ASTPrinter::EmitFrexpCall(StringStream& out,
                                const ast::CallExpression* expr,
-                               const sem::Builtin* builtin) {
+                               const sem::BuiltinFn* builtin) {
     return CallBuiltinHelper(
         out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
             auto* ty = builtin->Parameters()[0]->Type();
@@ -2264,7 +2264,7 @@
 
 bool ASTPrinter::EmitDegreesCall(StringStream& out,
                                  const ast::CallExpression* expr,
-                                 const sem::Builtin* builtin) {
+                                 const sem::BuiltinFn* builtin) {
     return CallBuiltinHelper(out, expr, builtin,
                              [&](TextBuffer* b, const std::vector<std::string>& params) {
                                  Line(b) << "return " << params[0] << " * " << std::setprecision(20)
@@ -2275,7 +2275,7 @@
 
 bool ASTPrinter::EmitRadiansCall(StringStream& out,
                                  const ast::CallExpression* expr,
-                                 const sem::Builtin* builtin) {
+                                 const sem::BuiltinFn* builtin) {
     return CallBuiltinHelper(out, expr, builtin,
                              [&](TextBuffer* b, const std::vector<std::string>& params) {
                                  Line(b) << "return " << params[0] << " * " << std::setprecision(20)
@@ -2287,7 +2287,7 @@
 // The HLSL `sign` method always returns an `int` result (scalar or vector). In WGSL the result is
 // expected to be the same type as the argument. This injects a cast to the expected WGSL result
 // type after the call to `sign`.
-bool ASTPrinter::EmitSignCall(StringStream& out, const sem::Call* call, const sem::Builtin*) {
+bool ASTPrinter::EmitSignCall(StringStream& out, const sem::Call* call, const sem::BuiltinFn*) {
     auto* arg = call->Arguments()[0];
     if (!EmitType(out, arg->Type(), core::AddressSpace::kUndefined, core::Access::kReadWrite, "")) {
         return false;
@@ -2302,7 +2302,7 @@
 
 bool ASTPrinter::EmitQuantizeToF16Call(StringStream& out,
                                        const ast::CallExpression* expr,
-                                       const sem::Builtin* builtin) {
+                                       const sem::BuiltinFn* builtin) {
     // Cast to f16 and back
     std::string width;
     if (auto* vec = builtin->ReturnType()->As<core::type::Vector>()) {
@@ -2319,7 +2319,7 @@
 
 bool ASTPrinter::EmitTruncCall(StringStream& out,
                                const ast::CallExpression* expr,
-                               const sem::Builtin* builtin) {
+                               const sem::BuiltinFn* builtin) {
     // HLSL's trunc is broken for very large/small float values.
     // See crbug.com/tint/1883
     return CallBuiltinHelper(  //
@@ -2333,27 +2333,27 @@
 
 bool ASTPrinter::EmitDataPackingCall(StringStream& out,
                                      const ast::CallExpression* expr,
-                                     const sem::Builtin* builtin) {
+                                     const sem::BuiltinFn* builtin) {
     return CallBuiltinHelper(
         out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
             uint32_t dims = 2;
             bool is_signed = false;
             uint32_t scale = 65535;
-            if (builtin->Type() == core::Function::kPack4X8Snorm ||
-                builtin->Type() == core::Function::kPack4X8Unorm) {
+            if (builtin->Fn() == core::BuiltinFn::kPack4X8Snorm ||
+                builtin->Fn() == core::BuiltinFn::kPack4X8Unorm) {
                 dims = 4;
                 scale = 255;
             }
-            if (builtin->Type() == core::Function::kPack4X8Snorm ||
-                builtin->Type() == core::Function::kPack2X16Snorm) {
+            if (builtin->Fn() == core::BuiltinFn::kPack4X8Snorm ||
+                builtin->Fn() == core::BuiltinFn::kPack2X16Snorm) {
                 is_signed = true;
                 scale = (scale - 1) / 2;
             }
-            switch (builtin->Type()) {
-                case core::Function::kPack4X8Snorm:
-                case core::Function::kPack4X8Unorm:
-                case core::Function::kPack2X16Snorm:
-                case core::Function::kPack2X16Unorm: {
+            switch (builtin->Fn()) {
+                case core::BuiltinFn::kPack4X8Snorm:
+                case core::BuiltinFn::kPack4X8Unorm:
+                case core::BuiltinFn::kPack2X16Snorm:
+                case core::BuiltinFn::kPack2X16Unorm: {
                     {
                         auto l = Line(b);
                         l << (is_signed ? "" : "u") << "int" << dims
@@ -2379,7 +2379,7 @@
                     }
                     break;
                 }
-                case core::Function::kPack2X16Float: {
+                case core::BuiltinFn::kPack2X16Float: {
                     Line(b) << "uint2 i = f32tof16(" << params[0] << ");";
                     Line(b) << "return i.x | (i.y << 16);";
                     break;
@@ -2396,25 +2396,25 @@
 
 bool ASTPrinter::EmitDataUnpackingCall(StringStream& out,
                                        const ast::CallExpression* expr,
-                                       const sem::Builtin* builtin) {
+                                       const sem::BuiltinFn* builtin) {
     return CallBuiltinHelper(
         out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
             uint32_t dims = 2;
             bool is_signed = false;
             uint32_t scale = 65535;
-            if (builtin->Type() == core::Function::kUnpack4X8Snorm ||
-                builtin->Type() == core::Function::kUnpack4X8Unorm) {
+            if (builtin->Fn() == core::BuiltinFn::kUnpack4X8Snorm ||
+                builtin->Fn() == core::BuiltinFn::kUnpack4X8Unorm) {
                 dims = 4;
                 scale = 255;
             }
-            if (builtin->Type() == core::Function::kUnpack4X8Snorm ||
-                builtin->Type() == core::Function::kUnpack2X16Snorm) {
+            if (builtin->Fn() == core::BuiltinFn::kUnpack4X8Snorm ||
+                builtin->Fn() == core::BuiltinFn::kUnpack2X16Snorm) {
                 is_signed = true;
                 scale = (scale - 1) / 2;
             }
-            switch (builtin->Type()) {
-                case core::Function::kUnpack4X8Snorm:
-                case core::Function::kUnpack2X16Snorm: {
+            switch (builtin->Fn()) {
+                case core::BuiltinFn::kUnpack4X8Snorm:
+                case core::BuiltinFn::kUnpack2X16Snorm: {
                     Line(b) << "int j = int(" << params[0] << ");";
                     {  // Perform sign extension on the converted values.
                         auto l = Line(b);
@@ -2430,8 +2430,8 @@
                             << (is_signed ? "-1.0" : "0.0") << ", 1.0);";
                     break;
                 }
-                case core::Function::kUnpack4X8Unorm:
-                case core::Function::kUnpack2X16Unorm: {
+                case core::BuiltinFn::kUnpack4X8Unorm:
+                case core::BuiltinFn::kUnpack2X16Unorm: {
                     Line(b) << "uint j = " << params[0] << ";";
                     {
                         auto l = Line(b);
@@ -2447,7 +2447,7 @@
                     Line(b) << "return float" << dims << "(i) / " << scale << ".0;";
                     break;
                 }
-                case core::Function::kUnpack2X16Float:
+                case core::BuiltinFn::kUnpack2X16Float:
                     Line(b) << "uint i = " << params[0] << ";";
                     Line(b) << "return f16tof32(uint2(i & 0xffff, i >> 16));";
                     break;
@@ -2463,17 +2463,17 @@
 
 bool ASTPrinter::EmitDP4aCall(StringStream& out,
                               const ast::CallExpression* expr,
-                              const sem::Builtin* builtin) {
+                              const sem::BuiltinFn* builtin) {
     // TODO(crbug.com/tint/1497): support the polyfill version of DP4a functions.
     return CallBuiltinHelper(
         out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
             std::string functionName;
-            switch (builtin->Type()) {
-                case core::Function::kDot4I8Packed:
+            switch (builtin->Fn()) {
+                case core::BuiltinFn::kDot4I8Packed:
                     Line(b) << "int accumulator = 0;";
                     functionName = "dot4add_i8packed";
                     break;
-                case core::Function::kDot4U8Packed:
+                case core::BuiltinFn::kDot4U8Packed:
                     Line(b) << "uint accumulator = 0u;";
                     functionName = "dot4add_u8packed";
                     break;
@@ -2489,17 +2489,17 @@
         });
 }
 
-bool ASTPrinter::EmitBarrierCall(StringStream& out, const sem::Builtin* builtin) {
+bool ASTPrinter::EmitBarrierCall(StringStream& out, const sem::BuiltinFn* builtin) {
     // TODO(crbug.com/tint/661): Combine sequential barriers to a single
     // instruction.
-    if (builtin->Type() == core::Function::kWorkgroupBarrier) {
+    if (builtin->Fn() == core::BuiltinFn::kWorkgroupBarrier) {
         out << "GroupMemoryBarrierWithGroupSync()";
-    } else if (builtin->Type() == core::Function::kStorageBarrier) {
+    } else if (builtin->Fn() == core::BuiltinFn::kStorageBarrier) {
         out << "DeviceMemoryBarrierWithGroupSync()";
-    } else if (builtin->Type() == core::Function::kTextureBarrier) {
+    } else if (builtin->Fn() == core::BuiltinFn::kTextureBarrier) {
         out << "DeviceMemoryBarrierWithGroupSync()";
     } else {
-        TINT_UNREACHABLE() << "unexpected barrier builtin type " << core::str(builtin->Type());
+        TINT_UNREACHABLE() << "unexpected barrier builtin type " << core::str(builtin->Fn());
         return false;
     }
     return true;
@@ -2507,12 +2507,12 @@
 
 bool ASTPrinter::EmitSubgroupCall(StringStream& out,
                                   [[maybe_unused]] const ast::CallExpression* expr,
-                                  const sem::Builtin* builtin) {
-    if (builtin->Type() == core::Function::kSubgroupBallot) {
+                                  const sem::BuiltinFn* builtin) {
+    if (builtin->Fn() == core::BuiltinFn::kSubgroupBallot) {
         out << "WaveActiveBallot(true)";
     } else {
         // subgroupBroadcast is already handled in the regular builtin flow.
-        TINT_UNREACHABLE() << "unexpected subgroup builtin type " << core::str(builtin->Type());
+        TINT_UNREACHABLE() << "unexpected subgroup builtin type " << core::str(builtin->Fn());
         return false;
     }
     return true;
@@ -2551,7 +2551,7 @@
 
 bool ASTPrinter::EmitTextureCall(StringStream& out,
                                  const sem::Call* call,
-                                 const sem::Builtin* builtin) {
+                                 const sem::BuiltinFn* builtin) {
     using Usage = core::ParameterUsage;
 
     auto& signature = builtin->Signature();
@@ -2572,19 +2572,19 @@
 
     auto* texture_type = TypeOf(texture)->UnwrapRef()->As<core::type::Texture>();
 
-    switch (builtin->Type()) {
-        case core::Function::kTextureDimensions:
-        case core::Function::kTextureNumLayers:
-        case core::Function::kTextureNumLevels:
-        case core::Function::kTextureNumSamples: {
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kTextureDimensions:
+        case core::BuiltinFn::kTextureNumLayers:
+        case core::BuiltinFn::kTextureNumLevels:
+        case core::BuiltinFn::kTextureNumSamples: {
             // All of these builtins use the GetDimensions() method on the texture
             bool is_ms = texture_type->IsAnyOf<core::type::MultisampledTexture,
                                                core::type::DepthMultisampledTexture>();
             int num_dimensions = 0;
             std::string swizzle;
 
-            switch (builtin->Type()) {
-                case core::Function::kTextureDimensions:
+            switch (builtin->Fn()) {
+                case core::BuiltinFn::kTextureDimensions:
                     switch (texture_type->dim()) {
                         case core::type::TextureDimension::kNone:
                             TINT_ICE() << "texture dimension is kNone";
@@ -2612,7 +2612,7 @@
                             break;
                     }
                     break;
-                case core::Function::kTextureNumLayers:
+                case core::BuiltinFn::kTextureNumLayers:
                     switch (texture_type->dim()) {
                         default:
                             TINT_ICE() << "texture dimension is not arrayed";
@@ -2627,7 +2627,7 @@
                             break;
                     }
                     break;
-                case core::Function::kTextureNumLevels:
+                case core::BuiltinFn::kTextureNumLevels:
                     switch (texture_type->dim()) {
                         default:
                             TINT_ICE() << "texture dimension does not support mips";
@@ -2649,7 +2649,7 @@
                             break;
                     }
                     break;
-                case core::Function::kTextureNumSamples:
+                case core::BuiltinFn::kTextureNumSamples:
                     switch (texture_type->dim()) {
                         default:
                             TINT_ICE() << "texture dimension does not support multisampling";
@@ -2712,7 +2712,7 @@
                         return false;
                     }
                     pre << ", ";
-                } else if (builtin->Type() == core::Function::kTextureNumLevels) {
+                } else if (builtin->Fn() == core::BuiltinFn::kTextureNumLevels) {
                     pre << "0, ";
                 }
 
@@ -2757,35 +2757,35 @@
 
     uint32_t hlsl_ret_width = 4u;
 
-    switch (builtin->Type()) {
-        case core::Function::kTextureSample:
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kTextureSample:
             out << ".Sample(";
             break;
-        case core::Function::kTextureSampleBias:
+        case core::BuiltinFn::kTextureSampleBias:
             out << ".SampleBias(";
             break;
-        case core::Function::kTextureSampleLevel:
+        case core::BuiltinFn::kTextureSampleLevel:
             out << ".SampleLevel(";
             break;
-        case core::Function::kTextureSampleGrad:
+        case core::BuiltinFn::kTextureSampleGrad:
             out << ".SampleGrad(";
             break;
-        case core::Function::kTextureSampleCompare:
+        case core::BuiltinFn::kTextureSampleCompare:
             out << ".SampleCmp(";
             hlsl_ret_width = 1;
             break;
-        case core::Function::kTextureSampleCompareLevel:
+        case core::BuiltinFn::kTextureSampleCompareLevel:
             out << ".SampleCmpLevelZero(";
             hlsl_ret_width = 1;
             break;
-        case core::Function::kTextureLoad:
+        case core::BuiltinFn::kTextureLoad:
             out << ".Load(";
             // Multisampled textures do not support mip-levels.
             if (!texture_type->Is<core::type::MultisampledTexture>()) {
                 pack_level_in_coords = true;
             }
             break;
-        case core::Function::kTextureGather:
+        case core::BuiltinFn::kTextureGather:
             out << ".Gather";
             if (builtin->Parameters()[0]->Usage() == core::ParameterUsage::kComponent) {
                 switch (call->Arguments()[0]->ConstantValue()->ValueAs<AInt>()) {
@@ -2805,10 +2805,10 @@
             }
             out << "(";
             break;
-        case core::Function::kTextureGatherCompare:
+        case core::BuiltinFn::kTextureGatherCompare:
             out << ".GatherCmp(";
             break;
-        case core::Function::kTextureStore:
+        case core::BuiltinFn::kTextureStore:
             out << "[";
             break;
         default:
@@ -2869,7 +2869,7 @@
         if (!emit_vector_appended_with_level(param_coords)) {
             return false;
         }
-    } else if (builtin->Type() == core::Function::kTextureStore) {
+    } else if (builtin->Fn() == core::BuiltinFn::kTextureStore) {
         // param_coords is an index expression, not a function arg
         if (!EmitExpression(out, param_coords)) {
             return false;
@@ -2891,7 +2891,7 @@
         }
     }
 
-    if (builtin->Type() == core::Function::kTextureStore) {
+    if (builtin->Fn() == core::BuiltinFn::kTextureStore) {
         out << "] = ";
         if (!EmitExpression(out, arg(Usage::kValue))) {
             return false;
@@ -2915,7 +2915,7 @@
         if (TINT_UNLIKELY(wgsl_ret_width > hlsl_ret_width)) {
             TINT_ICE() << "WGSL return width (" << wgsl_ret_width
                        << ") is wider than HLSL return width (" << hlsl_ret_width << ") for "
-                       << builtin->Type();
+                       << builtin->Fn();
             return false;
         }
     }
@@ -2923,81 +2923,81 @@
     return true;
 }
 
-std::string ASTPrinter::generate_builtin_name(const sem::Builtin* builtin) {
-    switch (builtin->Type()) {
-        case core::Function::kAbs:
-        case core::Function::kAcos:
-        case core::Function::kAll:
-        case core::Function::kAny:
-        case core::Function::kAsin:
-        case core::Function::kAtan:
-        case core::Function::kAtan2:
-        case core::Function::kCeil:
-        case core::Function::kClamp:
-        case core::Function::kCos:
-        case core::Function::kCosh:
-        case core::Function::kCross:
-        case core::Function::kDeterminant:
-        case core::Function::kDistance:
-        case core::Function::kDot:
-        case core::Function::kExp:
-        case core::Function::kExp2:
-        case core::Function::kFloor:
-        case core::Function::kFrexp:
-        case core::Function::kLdexp:
-        case core::Function::kLength:
-        case core::Function::kLog:
-        case core::Function::kLog2:
-        case core::Function::kMax:
-        case core::Function::kMin:
-        case core::Function::kModf:
-        case core::Function::kNormalize:
-        case core::Function::kPow:
-        case core::Function::kReflect:
-        case core::Function::kRefract:
-        case core::Function::kRound:
-        case core::Function::kSaturate:
-        case core::Function::kSin:
-        case core::Function::kSinh:
-        case core::Function::kSqrt:
-        case core::Function::kStep:
-        case core::Function::kTan:
-        case core::Function::kTanh:
-        case core::Function::kTranspose:
+std::string ASTPrinter::generate_builtin_name(const sem::BuiltinFn* builtin) {
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kAbs:
+        case core::BuiltinFn::kAcos:
+        case core::BuiltinFn::kAll:
+        case core::BuiltinFn::kAny:
+        case core::BuiltinFn::kAsin:
+        case core::BuiltinFn::kAtan:
+        case core::BuiltinFn::kAtan2:
+        case core::BuiltinFn::kCeil:
+        case core::BuiltinFn::kClamp:
+        case core::BuiltinFn::kCos:
+        case core::BuiltinFn::kCosh:
+        case core::BuiltinFn::kCross:
+        case core::BuiltinFn::kDeterminant:
+        case core::BuiltinFn::kDistance:
+        case core::BuiltinFn::kDot:
+        case core::BuiltinFn::kExp:
+        case core::BuiltinFn::kExp2:
+        case core::BuiltinFn::kFloor:
+        case core::BuiltinFn::kFrexp:
+        case core::BuiltinFn::kLdexp:
+        case core::BuiltinFn::kLength:
+        case core::BuiltinFn::kLog:
+        case core::BuiltinFn::kLog2:
+        case core::BuiltinFn::kMax:
+        case core::BuiltinFn::kMin:
+        case core::BuiltinFn::kModf:
+        case core::BuiltinFn::kNormalize:
+        case core::BuiltinFn::kPow:
+        case core::BuiltinFn::kReflect:
+        case core::BuiltinFn::kRefract:
+        case core::BuiltinFn::kRound:
+        case core::BuiltinFn::kSaturate:
+        case core::BuiltinFn::kSin:
+        case core::BuiltinFn::kSinh:
+        case core::BuiltinFn::kSqrt:
+        case core::BuiltinFn::kStep:
+        case core::BuiltinFn::kTan:
+        case core::BuiltinFn::kTanh:
+        case core::BuiltinFn::kTranspose:
             return builtin->str();
-        case core::Function::kCountOneBits:  // uint
+        case core::BuiltinFn::kCountOneBits:  // uint
             return "countbits";
-        case core::Function::kDpdx:
+        case core::BuiltinFn::kDpdx:
             return "ddx";
-        case core::Function::kDpdxCoarse:
+        case core::BuiltinFn::kDpdxCoarse:
             return "ddx_coarse";
-        case core::Function::kDpdxFine:
+        case core::BuiltinFn::kDpdxFine:
             return "ddx_fine";
-        case core::Function::kDpdy:
+        case core::BuiltinFn::kDpdy:
             return "ddy";
-        case core::Function::kDpdyCoarse:
+        case core::BuiltinFn::kDpdyCoarse:
             return "ddy_coarse";
-        case core::Function::kDpdyFine:
+        case core::BuiltinFn::kDpdyFine:
             return "ddy_fine";
-        case core::Function::kFaceForward:
+        case core::BuiltinFn::kFaceForward:
             return "faceforward";
-        case core::Function::kFract:
+        case core::BuiltinFn::kFract:
             return "frac";
-        case core::Function::kFma:
+        case core::BuiltinFn::kFma:
             return "mad";
-        case core::Function::kFwidth:
-        case core::Function::kFwidthCoarse:
-        case core::Function::kFwidthFine:
+        case core::BuiltinFn::kFwidth:
+        case core::BuiltinFn::kFwidthCoarse:
+        case core::BuiltinFn::kFwidthFine:
             return "fwidth";
-        case core::Function::kInverseSqrt:
+        case core::BuiltinFn::kInverseSqrt:
             return "rsqrt";
-        case core::Function::kMix:
+        case core::BuiltinFn::kMix:
             return "lerp";
-        case core::Function::kReverseBits:  // uint
+        case core::BuiltinFn::kReverseBits:  // uint
             return "reversebits";
-        case core::Function::kSmoothstep:
+        case core::BuiltinFn::kSmoothstep:
             return "smoothstep";
-        case core::Function::kSubgroupBroadcast:
+        case core::BuiltinFn::kSubgroupBroadcast:
             return "WaveReadLaneAt";
         default:
             diagnostics_.add_error(diag::System::Writer,
@@ -4584,14 +4584,14 @@
 template <typename F>
 bool ASTPrinter::CallBuiltinHelper(StringStream& out,
                                    const ast::CallExpression* call,
-                                   const sem::Builtin* builtin,
+                                   const sem::BuiltinFn* builtin,
                                    F&& build) {
     // Generate the helper function if it hasn't been created already
     auto fn = tint::GetOrCreate(builtins_, builtin, [&]() -> std::string {
         TextBuffer b;
         TINT_DEFER(helpers_.Append(b));
 
-        auto fn_name = UniqueIdentifier(std::string("tint_") + core::str(builtin->Type()));
+        auto fn_name = UniqueIdentifier(std::string("tint_") + core::str(builtin->Fn()));
         std::vector<std::string> parameter_names;
         {
             auto decl = Line(&b);
diff --git a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.h b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.h
index 7b7966b..0c8072a 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/ast_printer.h
+++ b/src/tint/lang/hlsl/writer/ast_printer/ast_printer.h
@@ -33,7 +33,7 @@
 
 // Forward declarations
 namespace tint::sem {
-class Builtin;
+class BuiltinFn;
 class Call;
 class ValueConstructor;
 class ValueConversion;
@@ -129,7 +129,7 @@
     /// @param call the call expression
     /// @param builtin the builtin being called
     /// @returns true if the expression is emitted
-    bool EmitBuiltinCall(StringStream& out, const sem::Call* call, const sem::Builtin* builtin);
+    bool EmitBuiltinCall(StringStream& out, const sem::Call* call, const sem::BuiltinFn* builtin);
     /// Handles generating a value conversion expression
     /// @param out the output stream
     /// @param call the call expression
@@ -168,7 +168,7 @@
     /// @param out the output stream
     /// @param builtin the semantic information for the barrier builtin
     /// @returns true if the call expression is emitted
-    bool EmitBarrierCall(StringStream& out, const sem::Builtin* builtin);
+    bool EmitBarrierCall(StringStream& out, const sem::BuiltinFn* builtin);
     /// Handles generating an atomic intrinsic call for a storage buffer variable
     /// @param out the output stream
     /// @param expr the call expression
@@ -190,14 +190,14 @@
     /// @returns true if the call expression is emitted
     bool EmitWorkgroupAtomicCall(StringStream& out,
                                  const ast::CallExpression* expr,
-                                 const sem::Builtin* builtin);
+                                 const sem::BuiltinFn* builtin);
     /// Handles generating a call to a texture function (`textureSample`,
     /// `textureSampleGrad`, etc)
     /// @param out the output stream
     /// @param call the call expression
     /// @param builtin the semantic information for the texture builtin
     /// @returns true if the call expression is emitted
-    bool EmitTextureCall(StringStream& out, const sem::Call* call, const sem::Builtin* builtin);
+    bool EmitTextureCall(StringStream& out, const sem::Call* call, const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `select()` builtin
     /// @param out the output stream
     /// @param expr the call expression
@@ -210,7 +210,7 @@
     /// @returns true if the call expression is emitted
     bool EmitModfCall(StringStream& out,
                       const ast::CallExpression* expr,
-                      const sem::Builtin* builtin);
+                      const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `frexp()` builtin
     /// @param out the output stream
     /// @param expr the call expression
@@ -218,7 +218,7 @@
     /// @returns true if the call expression is emitted
     bool EmitFrexpCall(StringStream& out,
                        const ast::CallExpression* expr,
-                       const sem::Builtin* builtin);
+                       const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `degrees()` builtin
     /// @param out the output stream
     /// @param expr the call expression
@@ -226,7 +226,7 @@
     /// @returns true if the call expression is emitted
     bool EmitDegreesCall(StringStream& out,
                          const ast::CallExpression* expr,
-                         const sem::Builtin* builtin);
+                         const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `radians()` builtin
     /// @param out the output stream
     /// @param expr the call expression
@@ -234,13 +234,13 @@
     /// @returns true if the call expression is emitted
     bool EmitRadiansCall(StringStream& out,
                          const ast::CallExpression* expr,
-                         const sem::Builtin* builtin);
+                         const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `sign()` builtin
     /// @param out the output stream
     /// @param call the call semantic node
     /// @param builtin the semantic information for the builtin
     /// @returns true if the call expression is emitted
-    bool EmitSignCall(StringStream& out, const sem::Call* call, const sem::Builtin* builtin);
+    bool EmitSignCall(StringStream& out, const sem::Call* call, const sem::BuiltinFn* builtin);
     /// Handles generating a call to data packing builtin
     /// @param out the output stream
     /// @param expr the call expression
@@ -248,7 +248,7 @@
     /// @returns true if the call expression is emitted
     bool EmitDataPackingCall(StringStream& out,
                              const ast::CallExpression* expr,
-                             const sem::Builtin* builtin);
+                             const sem::BuiltinFn* builtin);
     /// Handles generating a call to data unpacking builtin
     /// @param out the output stream
     /// @param expr the call expression
@@ -256,7 +256,7 @@
     /// @returns true if the call expression is emitted
     bool EmitDataUnpackingCall(StringStream& out,
                                const ast::CallExpression* expr,
-                               const sem::Builtin* builtin);
+                               const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `quantizeToF16()` intrinsic
     /// @param out the output stream
     /// @param expr the call expression
@@ -264,7 +264,7 @@
     /// @returns true if the call expression is emitted
     bool EmitQuantizeToF16Call(StringStream& out,
                                const ast::CallExpression* expr,
-                               const sem::Builtin* builtin);
+                               const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `trunc()` intrinsic
     /// @param out the output stream
     /// @param expr the call expression
@@ -272,7 +272,7 @@
     /// @returns true if the call expression is emitted
     bool EmitTruncCall(StringStream& out,
                        const ast::CallExpression* expr,
-                       const sem::Builtin* builtin);
+                       const sem::BuiltinFn* builtin);
     /// Handles generating a call to DP4a builtins (dot4I8Packed and dot4U8Packed)
     /// @param out the output stream
     /// @param expr the call expression
@@ -280,7 +280,7 @@
     /// @returns true if the call expression is emitted
     bool EmitDP4aCall(StringStream& out,
                       const ast::CallExpression* expr,
-                      const sem::Builtin* builtin);
+                      const sem::BuiltinFn* builtin);
     /// Handles generating a call to subgroup builtins.
     /// @param out the output stream
     /// @param expr the call expression
@@ -288,7 +288,7 @@
     /// @returns true if the call expression is emitted
     bool EmitSubgroupCall(StringStream& out,
                           const ast::CallExpression* expr,
-                          const sem::Builtin* builtin);
+                          const sem::BuiltinFn* builtin);
     /// Handles a case statement
     /// @param s the switch statement
     /// @param case_idx the index of the switch case in the switch statement
@@ -507,7 +507,7 @@
     /// Handles generating a builtin method name
     /// @param builtin the semantic info for the builtin
     /// @returns the name or "" if not valid
-    std::string generate_builtin_name(const sem::Builtin* builtin);
+    std::string generate_builtin_name(const sem::BuiltinFn* builtin);
     /// Converts a builtin to an attribute name
     /// @param builtin the builtin to convert
     /// @returns the string name of the builtin or blank on error
@@ -562,7 +562,7 @@
     template <typename F>
     bool CallBuiltinHelper(StringStream& out,
                            const ast::CallExpression* call,
-                           const sem::Builtin* builtin,
+                           const sem::BuiltinFn* builtin,
                            F&& build);
 
     /// @param s the structure
@@ -591,7 +591,7 @@
     std::unordered_map<const core::type::Struct*, std::string> builtin_struct_names_;
     std::function<bool()> emit_continuing_;
     std::unordered_map<const core::type::Matrix*, std::string> matrix_scalar_inits_;
-    std::unordered_map<const sem::Builtin*, std::string> builtins_;
+    std::unordered_map<const sem::BuiltinFn*, std::string> builtins_;
     // Polyfill functions for bitcast expression, BinaryType indicates the source type and the
     // destination type.
     std::unordered_map<BinaryType, std::string> bitcast_funcs_;
diff --git a/src/tint/lang/hlsl/writer/ast_printer/builtin_test.cc b/src/tint/lang/hlsl/writer/ast_printer/builtin_test.cc
index a7bbede..9445273 100644
--- a/src/tint/lang/hlsl/writer/ast_printer/builtin_test.cc
+++ b/src/tint/lang/hlsl/writer/ast_printer/builtin_test.cc
@@ -36,7 +36,7 @@
 };
 
 struct BuiltinData {
-    core::Function builtin;
+    core::BuiltinFn builtin;
     CallParamType type;
     const char* hlsl_name;
 };
@@ -60,84 +60,84 @@
     return out;
 }
 
-const ast::CallExpression* GenerateCall(core::Function builtin,
+const ast::CallExpression* GenerateCall(core::BuiltinFn builtin,
                                         CallParamType type,
                                         ProgramBuilder* builder) {
     std::string name;
     StringStream str;
     str << name << builtin;
     switch (builtin) {
-        case core::Function::kAcos:
-        case core::Function::kAsin:
-        case core::Function::kAtan:
-        case core::Function::kCeil:
-        case core::Function::kCos:
-        case core::Function::kCosh:
-        case core::Function::kDpdx:
-        case core::Function::kDpdxCoarse:
-        case core::Function::kDpdxFine:
-        case core::Function::kDpdy:
-        case core::Function::kDpdyCoarse:
-        case core::Function::kDpdyFine:
-        case core::Function::kExp:
-        case core::Function::kExp2:
-        case core::Function::kFloor:
-        case core::Function::kFract:
-        case core::Function::kFwidth:
-        case core::Function::kFwidthCoarse:
-        case core::Function::kFwidthFine:
-        case core::Function::kInverseSqrt:
-        case core::Function::kLength:
-        case core::Function::kLog:
-        case core::Function::kLog2:
-        case core::Function::kNormalize:
-        case core::Function::kRound:
-        case core::Function::kSin:
-        case core::Function::kSinh:
-        case core::Function::kSqrt:
-        case core::Function::kTan:
-        case core::Function::kTanh:
+        case core::BuiltinFn::kAcos:
+        case core::BuiltinFn::kAsin:
+        case core::BuiltinFn::kAtan:
+        case core::BuiltinFn::kCeil:
+        case core::BuiltinFn::kCos:
+        case core::BuiltinFn::kCosh:
+        case core::BuiltinFn::kDpdx:
+        case core::BuiltinFn::kDpdxCoarse:
+        case core::BuiltinFn::kDpdxFine:
+        case core::BuiltinFn::kDpdy:
+        case core::BuiltinFn::kDpdyCoarse:
+        case core::BuiltinFn::kDpdyFine:
+        case core::BuiltinFn::kExp:
+        case core::BuiltinFn::kExp2:
+        case core::BuiltinFn::kFloor:
+        case core::BuiltinFn::kFract:
+        case core::BuiltinFn::kFwidth:
+        case core::BuiltinFn::kFwidthCoarse:
+        case core::BuiltinFn::kFwidthFine:
+        case core::BuiltinFn::kInverseSqrt:
+        case core::BuiltinFn::kLength:
+        case core::BuiltinFn::kLog:
+        case core::BuiltinFn::kLog2:
+        case core::BuiltinFn::kNormalize:
+        case core::BuiltinFn::kRound:
+        case core::BuiltinFn::kSin:
+        case core::BuiltinFn::kSinh:
+        case core::BuiltinFn::kSqrt:
+        case core::BuiltinFn::kTan:
+        case core::BuiltinFn::kTanh:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2");
             } else {
                 return builder->Call(str.str(), "f2");
             }
-        case core::Function::kLdexp:
+        case core::BuiltinFn::kLdexp:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "i2");
             } else {
                 return builder->Call(str.str(), "f2", "i2");
             }
-        case core::Function::kAtan2:
-        case core::Function::kDot:
-        case core::Function::kDistance:
-        case core::Function::kPow:
-        case core::Function::kReflect:
-        case core::Function::kStep:
+        case core::BuiltinFn::kAtan2:
+        case core::BuiltinFn::kDot:
+        case core::BuiltinFn::kDistance:
+        case core::BuiltinFn::kPow:
+        case core::BuiltinFn::kReflect:
+        case core::BuiltinFn::kStep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2");
             }
-        case core::Function::kCross:
+        case core::BuiltinFn::kCross:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h3", "h3");
             } else {
                 return builder->Call(str.str(), "f3", "f3");
             }
-        case core::Function::kFma:
-        case core::Function::kMix:
-        case core::Function::kFaceForward:
-        case core::Function::kSmoothstep:
+        case core::BuiltinFn::kFma:
+        case core::BuiltinFn::kMix:
+        case core::BuiltinFn::kFaceForward:
+        case core::BuiltinFn::kSmoothstep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             }
-        case core::Function::kAll:
-        case core::Function::kAny:
+        case core::BuiltinFn::kAll:
+        case core::BuiltinFn::kAny:
             return builder->Call(str.str(), "b2");
-        case core::Function::kAbs:
+        case core::BuiltinFn::kAbs:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2");
             } else if (type == CallParamType::kF16) {
@@ -145,11 +145,11 @@
             } else {
                 return builder->Call(str.str(), "u2");
             }
-        case core::Function::kCountOneBits:
-        case core::Function::kReverseBits:
+        case core::BuiltinFn::kCountOneBits:
+        case core::BuiltinFn::kReverseBits:
             return builder->Call(str.str(), "u2");
-        case core::Function::kMax:
-        case core::Function::kMin:
+        case core::BuiltinFn::kMax:
+        case core::BuiltinFn::kMin:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -157,7 +157,7 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2");
             }
-        case core::Function::kClamp:
+        case core::BuiltinFn::kClamp:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -165,19 +165,19 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2", "u2");
             }
-        case core::Function::kSelect:
+        case core::BuiltinFn::kSelect:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "b2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "b2");
             }
-        case core::Function::kDeterminant:
+        case core::BuiltinFn::kDeterminant:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm2x2");
             } else {
                 return builder->Call(str.str(), "m2x2");
             }
-        case core::Function::kTranspose:
+        case core::BuiltinFn::kTranspose:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm3x2");
             } else {
@@ -224,7 +224,7 @@
     ASSERT_NE(sem, nullptr);
     auto* target = sem->Target();
     ASSERT_NE(target, nullptr);
-    auto* builtin = target->As<sem::Builtin>();
+    auto* builtin = target->As<sem::BuiltinFn>();
     ASSERT_NE(builtin, nullptr);
 
     EXPECT_EQ(gen.generate_builtin_name(builtin), param.hlsl_name);
@@ -233,105 +233,105 @@
     HlslASTPrinterTest_Builtin,
     HlslBuiltinTest,
     testing::Values(/* Logical built-in */
-                    BuiltinData{core::Function::kAll, CallParamType::kBool, "all"},
-                    BuiltinData{core::Function::kAny, CallParamType::kBool, "any"},
+                    BuiltinData{core::BuiltinFn::kAll, CallParamType::kBool, "all"},
+                    BuiltinData{core::BuiltinFn::kAny, CallParamType::kBool, "any"},
                     /* Float built-in */
-                    BuiltinData{core::Function::kAbs, CallParamType::kF32, "abs"},
-                    BuiltinData{core::Function::kAbs, CallParamType::kF16, "abs"},
-                    BuiltinData{core::Function::kAcos, CallParamType::kF32, "acos"},
-                    BuiltinData{core::Function::kAcos, CallParamType::kF16, "acos"},
-                    BuiltinData{core::Function::kAsin, CallParamType::kF32, "asin"},
-                    BuiltinData{core::Function::kAsin, CallParamType::kF16, "asin"},
-                    BuiltinData{core::Function::kAtan, CallParamType::kF32, "atan"},
-                    BuiltinData{core::Function::kAtan, CallParamType::kF16, "atan"},
-                    BuiltinData{core::Function::kAtan2, CallParamType::kF32, "atan2"},
-                    BuiltinData{core::Function::kAtan2, CallParamType::kF16, "atan2"},
-                    BuiltinData{core::Function::kCeil, CallParamType::kF32, "ceil"},
-                    BuiltinData{core::Function::kCeil, CallParamType::kF16, "ceil"},
-                    BuiltinData{core::Function::kClamp, CallParamType::kF32, "clamp"},
-                    BuiltinData{core::Function::kClamp, CallParamType::kF16, "clamp"},
-                    BuiltinData{core::Function::kCos, CallParamType::kF32, "cos"},
-                    BuiltinData{core::Function::kCos, CallParamType::kF16, "cos"},
-                    BuiltinData{core::Function::kCosh, CallParamType::kF32, "cosh"},
-                    BuiltinData{core::Function::kCosh, CallParamType::kF16, "cosh"},
-                    BuiltinData{core::Function::kCross, CallParamType::kF32, "cross"},
-                    BuiltinData{core::Function::kCross, CallParamType::kF16, "cross"},
-                    BuiltinData{core::Function::kDistance, CallParamType::kF32, "distance"},
-                    BuiltinData{core::Function::kDistance, CallParamType::kF16, "distance"},
-                    BuiltinData{core::Function::kExp, CallParamType::kF32, "exp"},
-                    BuiltinData{core::Function::kExp, CallParamType::kF16, "exp"},
-                    BuiltinData{core::Function::kExp2, CallParamType::kF32, "exp2"},
-                    BuiltinData{core::Function::kExp2, CallParamType::kF16, "exp2"},
-                    BuiltinData{core::Function::kFaceForward, CallParamType::kF32, "faceforward"},
-                    BuiltinData{core::Function::kFaceForward, CallParamType::kF16, "faceforward"},
-                    BuiltinData{core::Function::kFloor, CallParamType::kF32, "floor"},
-                    BuiltinData{core::Function::kFloor, CallParamType::kF16, "floor"},
-                    BuiltinData{core::Function::kFma, CallParamType::kF32, "mad"},
-                    BuiltinData{core::Function::kFma, CallParamType::kF16, "mad"},
-                    BuiltinData{core::Function::kFract, CallParamType::kF32, "frac"},
-                    BuiltinData{core::Function::kFract, CallParamType::kF16, "frac"},
-                    BuiltinData{core::Function::kInverseSqrt, CallParamType::kF32, "rsqrt"},
-                    BuiltinData{core::Function::kInverseSqrt, CallParamType::kF16, "rsqrt"},
-                    BuiltinData{core::Function::kLdexp, CallParamType::kF32, "ldexp"},
-                    BuiltinData{core::Function::kLdexp, CallParamType::kF16, "ldexp"},
-                    BuiltinData{core::Function::kLength, CallParamType::kF32, "length"},
-                    BuiltinData{core::Function::kLength, CallParamType::kF16, "length"},
-                    BuiltinData{core::Function::kLog, CallParamType::kF32, "log"},
-                    BuiltinData{core::Function::kLog, CallParamType::kF16, "log"},
-                    BuiltinData{core::Function::kLog2, CallParamType::kF32, "log2"},
-                    BuiltinData{core::Function::kLog2, CallParamType::kF16, "log2"},
-                    BuiltinData{core::Function::kMax, CallParamType::kF32, "max"},
-                    BuiltinData{core::Function::kMax, CallParamType::kF16, "max"},
-                    BuiltinData{core::Function::kMin, CallParamType::kF32, "min"},
-                    BuiltinData{core::Function::kMin, CallParamType::kF16, "min"},
-                    BuiltinData{core::Function::kMix, CallParamType::kF32, "lerp"},
-                    BuiltinData{core::Function::kMix, CallParamType::kF16, "lerp"},
-                    BuiltinData{core::Function::kNormalize, CallParamType::kF32, "normalize"},
-                    BuiltinData{core::Function::kNormalize, CallParamType::kF16, "normalize"},
-                    BuiltinData{core::Function::kPow, CallParamType::kF32, "pow"},
-                    BuiltinData{core::Function::kPow, CallParamType::kF16, "pow"},
-                    BuiltinData{core::Function::kReflect, CallParamType::kF32, "reflect"},
-                    BuiltinData{core::Function::kReflect, CallParamType::kF16, "reflect"},
-                    BuiltinData{core::Function::kSin, CallParamType::kF32, "sin"},
-                    BuiltinData{core::Function::kSin, CallParamType::kF16, "sin"},
-                    BuiltinData{core::Function::kSinh, CallParamType::kF32, "sinh"},
-                    BuiltinData{core::Function::kSinh, CallParamType::kF16, "sinh"},
-                    BuiltinData{core::Function::kSmoothstep, CallParamType::kF32, "smoothstep"},
-                    BuiltinData{core::Function::kSmoothstep, CallParamType::kF16, "smoothstep"},
-                    BuiltinData{core::Function::kSqrt, CallParamType::kF32, "sqrt"},
-                    BuiltinData{core::Function::kSqrt, CallParamType::kF16, "sqrt"},
-                    BuiltinData{core::Function::kStep, CallParamType::kF32, "step"},
-                    BuiltinData{core::Function::kStep, CallParamType::kF16, "step"},
-                    BuiltinData{core::Function::kTan, CallParamType::kF32, "tan"},
-                    BuiltinData{core::Function::kTan, CallParamType::kF16, "tan"},
-                    BuiltinData{core::Function::kTanh, CallParamType::kF32, "tanh"},
-                    BuiltinData{core::Function::kTanh, CallParamType::kF16, "tanh"},
+                    BuiltinData{core::BuiltinFn::kAbs, CallParamType::kF32, "abs"},
+                    BuiltinData{core::BuiltinFn::kAbs, CallParamType::kF16, "abs"},
+                    BuiltinData{core::BuiltinFn::kAcos, CallParamType::kF32, "acos"},
+                    BuiltinData{core::BuiltinFn::kAcos, CallParamType::kF16, "acos"},
+                    BuiltinData{core::BuiltinFn::kAsin, CallParamType::kF32, "asin"},
+                    BuiltinData{core::BuiltinFn::kAsin, CallParamType::kF16, "asin"},
+                    BuiltinData{core::BuiltinFn::kAtan, CallParamType::kF32, "atan"},
+                    BuiltinData{core::BuiltinFn::kAtan, CallParamType::kF16, "atan"},
+                    BuiltinData{core::BuiltinFn::kAtan2, CallParamType::kF32, "atan2"},
+                    BuiltinData{core::BuiltinFn::kAtan2, CallParamType::kF16, "atan2"},
+                    BuiltinData{core::BuiltinFn::kCeil, CallParamType::kF32, "ceil"},
+                    BuiltinData{core::BuiltinFn::kCeil, CallParamType::kF16, "ceil"},
+                    BuiltinData{core::BuiltinFn::kClamp, CallParamType::kF32, "clamp"},
+                    BuiltinData{core::BuiltinFn::kClamp, CallParamType::kF16, "clamp"},
+                    BuiltinData{core::BuiltinFn::kCos, CallParamType::kF32, "cos"},
+                    BuiltinData{core::BuiltinFn::kCos, CallParamType::kF16, "cos"},
+                    BuiltinData{core::BuiltinFn::kCosh, CallParamType::kF32, "cosh"},
+                    BuiltinData{core::BuiltinFn::kCosh, CallParamType::kF16, "cosh"},
+                    BuiltinData{core::BuiltinFn::kCross, CallParamType::kF32, "cross"},
+                    BuiltinData{core::BuiltinFn::kCross, CallParamType::kF16, "cross"},
+                    BuiltinData{core::BuiltinFn::kDistance, CallParamType::kF32, "distance"},
+                    BuiltinData{core::BuiltinFn::kDistance, CallParamType::kF16, "distance"},
+                    BuiltinData{core::BuiltinFn::kExp, CallParamType::kF32, "exp"},
+                    BuiltinData{core::BuiltinFn::kExp, CallParamType::kF16, "exp"},
+                    BuiltinData{core::BuiltinFn::kExp2, CallParamType::kF32, "exp2"},
+                    BuiltinData{core::BuiltinFn::kExp2, CallParamType::kF16, "exp2"},
+                    BuiltinData{core::BuiltinFn::kFaceForward, CallParamType::kF32, "faceforward"},
+                    BuiltinData{core::BuiltinFn::kFaceForward, CallParamType::kF16, "faceforward"},
+                    BuiltinData{core::BuiltinFn::kFloor, CallParamType::kF32, "floor"},
+                    BuiltinData{core::BuiltinFn::kFloor, CallParamType::kF16, "floor"},
+                    BuiltinData{core::BuiltinFn::kFma, CallParamType::kF32, "mad"},
+                    BuiltinData{core::BuiltinFn::kFma, CallParamType::kF16, "mad"},
+                    BuiltinData{core::BuiltinFn::kFract, CallParamType::kF32, "frac"},
+                    BuiltinData{core::BuiltinFn::kFract, CallParamType::kF16, "frac"},
+                    BuiltinData{core::BuiltinFn::kInverseSqrt, CallParamType::kF32, "rsqrt"},
+                    BuiltinData{core::BuiltinFn::kInverseSqrt, CallParamType::kF16, "rsqrt"},
+                    BuiltinData{core::BuiltinFn::kLdexp, CallParamType::kF32, "ldexp"},
+                    BuiltinData{core::BuiltinFn::kLdexp, CallParamType::kF16, "ldexp"},
+                    BuiltinData{core::BuiltinFn::kLength, CallParamType::kF32, "length"},
+                    BuiltinData{core::BuiltinFn::kLength, CallParamType::kF16, "length"},
+                    BuiltinData{core::BuiltinFn::kLog, CallParamType::kF32, "log"},
+                    BuiltinData{core::BuiltinFn::kLog, CallParamType::kF16, "log"},
+                    BuiltinData{core::BuiltinFn::kLog2, CallParamType::kF32, "log2"},
+                    BuiltinData{core::BuiltinFn::kLog2, CallParamType::kF16, "log2"},
+                    BuiltinData{core::BuiltinFn::kMax, CallParamType::kF32, "max"},
+                    BuiltinData{core::BuiltinFn::kMax, CallParamType::kF16, "max"},
+                    BuiltinData{core::BuiltinFn::kMin, CallParamType::kF32, "min"},
+                    BuiltinData{core::BuiltinFn::kMin, CallParamType::kF16, "min"},
+                    BuiltinData{core::BuiltinFn::kMix, CallParamType::kF32, "lerp"},
+                    BuiltinData{core::BuiltinFn::kMix, CallParamType::kF16, "lerp"},
+                    BuiltinData{core::BuiltinFn::kNormalize, CallParamType::kF32, "normalize"},
+                    BuiltinData{core::BuiltinFn::kNormalize, CallParamType::kF16, "normalize"},
+                    BuiltinData{core::BuiltinFn::kPow, CallParamType::kF32, "pow"},
+                    BuiltinData{core::BuiltinFn::kPow, CallParamType::kF16, "pow"},
+                    BuiltinData{core::BuiltinFn::kReflect, CallParamType::kF32, "reflect"},
+                    BuiltinData{core::BuiltinFn::kReflect, CallParamType::kF16, "reflect"},
+                    BuiltinData{core::BuiltinFn::kSin, CallParamType::kF32, "sin"},
+                    BuiltinData{core::BuiltinFn::kSin, CallParamType::kF16, "sin"},
+                    BuiltinData{core::BuiltinFn::kSinh, CallParamType::kF32, "sinh"},
+                    BuiltinData{core::BuiltinFn::kSinh, CallParamType::kF16, "sinh"},
+                    BuiltinData{core::BuiltinFn::kSmoothstep, CallParamType::kF32, "smoothstep"},
+                    BuiltinData{core::BuiltinFn::kSmoothstep, CallParamType::kF16, "smoothstep"},
+                    BuiltinData{core::BuiltinFn::kSqrt, CallParamType::kF32, "sqrt"},
+                    BuiltinData{core::BuiltinFn::kSqrt, CallParamType::kF16, "sqrt"},
+                    BuiltinData{core::BuiltinFn::kStep, CallParamType::kF32, "step"},
+                    BuiltinData{core::BuiltinFn::kStep, CallParamType::kF16, "step"},
+                    BuiltinData{core::BuiltinFn::kTan, CallParamType::kF32, "tan"},
+                    BuiltinData{core::BuiltinFn::kTan, CallParamType::kF16, "tan"},
+                    BuiltinData{core::BuiltinFn::kTanh, CallParamType::kF32, "tanh"},
+                    BuiltinData{core::BuiltinFn::kTanh, CallParamType::kF16, "tanh"},
                     /* Integer built-in */
-                    BuiltinData{core::Function::kAbs, CallParamType::kU32, "abs"},
-                    BuiltinData{core::Function::kClamp, CallParamType::kU32, "clamp"},
-                    BuiltinData{core::Function::kCountOneBits, CallParamType::kU32, "countbits"},
-                    BuiltinData{core::Function::kMax, CallParamType::kU32, "max"},
-                    BuiltinData{core::Function::kMin, CallParamType::kU32, "min"},
-                    BuiltinData{core::Function::kReverseBits, CallParamType::kU32, "reversebits"},
-                    BuiltinData{core::Function::kRound, CallParamType::kU32, "round"},
+                    BuiltinData{core::BuiltinFn::kAbs, CallParamType::kU32, "abs"},
+                    BuiltinData{core::BuiltinFn::kClamp, CallParamType::kU32, "clamp"},
+                    BuiltinData{core::BuiltinFn::kCountOneBits, CallParamType::kU32, "countbits"},
+                    BuiltinData{core::BuiltinFn::kMax, CallParamType::kU32, "max"},
+                    BuiltinData{core::BuiltinFn::kMin, CallParamType::kU32, "min"},
+                    BuiltinData{core::BuiltinFn::kReverseBits, CallParamType::kU32, "reversebits"},
+                    BuiltinData{core::BuiltinFn::kRound, CallParamType::kU32, "round"},
                     /* Matrix built-in */
-                    BuiltinData{core::Function::kDeterminant, CallParamType::kF32, "determinant"},
-                    BuiltinData{core::Function::kDeterminant, CallParamType::kF16, "determinant"},
-                    BuiltinData{core::Function::kTranspose, CallParamType::kF32, "transpose"},
-                    BuiltinData{core::Function::kTranspose, CallParamType::kF16, "transpose"},
+                    BuiltinData{core::BuiltinFn::kDeterminant, CallParamType::kF32, "determinant"},
+                    BuiltinData{core::BuiltinFn::kDeterminant, CallParamType::kF16, "determinant"},
+                    BuiltinData{core::BuiltinFn::kTranspose, CallParamType::kF32, "transpose"},
+                    BuiltinData{core::BuiltinFn::kTranspose, CallParamType::kF16, "transpose"},
                     /* Vector built-in */
-                    BuiltinData{core::Function::kDot, CallParamType::kF32, "dot"},
-                    BuiltinData{core::Function::kDot, CallParamType::kF16, "dot"},
+                    BuiltinData{core::BuiltinFn::kDot, CallParamType::kF32, "dot"},
+                    BuiltinData{core::BuiltinFn::kDot, CallParamType::kF16, "dot"},
                     /* Derivate built-in */
-                    BuiltinData{core::Function::kDpdx, CallParamType::kF32, "ddx"},
-                    BuiltinData{core::Function::kDpdxCoarse, CallParamType::kF32, "ddx_coarse"},
-                    BuiltinData{core::Function::kDpdxFine, CallParamType::kF32, "ddx_fine"},
-                    BuiltinData{core::Function::kDpdy, CallParamType::kF32, "ddy"},
-                    BuiltinData{core::Function::kDpdyCoarse, CallParamType::kF32, "ddy_coarse"},
-                    BuiltinData{core::Function::kDpdyFine, CallParamType::kF32, "ddy_fine"},
-                    BuiltinData{core::Function::kFwidth, CallParamType::kF32, "fwidth"},
-                    BuiltinData{core::Function::kFwidthCoarse, CallParamType::kF32, "fwidth"},
-                    BuiltinData{core::Function::kFwidthFine, CallParamType::kF32, "fwidth"}));
+                    BuiltinData{core::BuiltinFn::kDpdx, CallParamType::kF32, "ddx"},
+                    BuiltinData{core::BuiltinFn::kDpdxCoarse, CallParamType::kF32, "ddx_coarse"},
+                    BuiltinData{core::BuiltinFn::kDpdxFine, CallParamType::kF32, "ddx_fine"},
+                    BuiltinData{core::BuiltinFn::kDpdy, CallParamType::kF32, "ddy"},
+                    BuiltinData{core::BuiltinFn::kDpdyCoarse, CallParamType::kF32, "ddy_coarse"},
+                    BuiltinData{core::BuiltinFn::kDpdyFine, CallParamType::kF32, "ddy_fine"},
+                    BuiltinData{core::BuiltinFn::kFwidth, CallParamType::kF32, "fwidth"},
+                    BuiltinData{core::BuiltinFn::kFwidthCoarse, CallParamType::kF32, "fwidth"},
+                    BuiltinData{core::BuiltinFn::kFwidthFine, CallParamType::kF32, "fwidth"}));
 
 TEST_F(HlslASTPrinterTest_Builtin, Builtin_Call) {
     auto* call = Call("dot", "param1", "param2");
diff --git a/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.cc b/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.cc
index 604700f..95c0661 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/calculate_array_length.cc
@@ -47,7 +47,7 @@
     for (auto* fn : program->AST().Functions()) {
         if (auto* sem_fn = program->Sem().Get(fn)) {
             for (auto* builtin : sem_fn->DirectlyCalledBuiltins()) {
-                if (builtin->Type() == core::Function::kArrayLength) {
+                if (builtin->Fn() == core::BuiltinFn::kArrayLength) {
                     return true;
                 }
             }
@@ -129,8 +129,8 @@
     for (auto* node : src->ASTNodes().Objects()) {
         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() == core::Function::kArrayLength) {
+            if (auto* builtin = call->Target()->As<sem::BuiltinFn>()) {
+                if (builtin->Fn() == core::BuiltinFn::kArrayLength) {
                     // We're dealing with an arrayLength() call
 
                     if (auto* call_stmt = call->Stmt()->Declaration()->As<ast::CallStatement>()) {
diff --git a/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.cc b/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.cc
index 9cff4ce..fe6977e 100644
--- a/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.cc
+++ b/src/tint/lang/hlsl/writer/ast_raise/decompose_memory_access.cc
@@ -129,7 +129,7 @@
 /// AtomicKey is the unordered map key to an atomic intrinsic.
 struct AtomicKey {
     core::type::Type const* el_ty = nullptr;  // element type
-    core::Function const op;                  // atomic op
+    core::BuiltinFn const op;                 // atomic op
     Symbol const buffer;                      // buffer name
     bool operator==(const AtomicKey& rhs) const {
         return el_ty == rhs.el_ty && op == rhs.op && buffer == rhs.buffer;
@@ -254,42 +254,42 @@
 /// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied to a stub function for
 /// the atomic op and the type @p ty.
 DecomposeMemoryAccess::Intrinsic* IntrinsicAtomicFor(ast::Builder* builder,
-                                                     core::Function ity,
+                                                     core::BuiltinFn ity,
                                                      const core::type::Type* ty,
                                                      const Symbol& buffer) {
     auto op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicLoad;
     switch (ity) {
-        case core::Function::kAtomicLoad:
+        case core::BuiltinFn::kAtomicLoad:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicLoad;
             break;
-        case core::Function::kAtomicStore:
+        case core::BuiltinFn::kAtomicStore:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicStore;
             break;
-        case core::Function::kAtomicAdd:
+        case core::BuiltinFn::kAtomicAdd:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicAdd;
             break;
-        case core::Function::kAtomicSub:
+        case core::BuiltinFn::kAtomicSub:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicSub;
             break;
-        case core::Function::kAtomicMax:
+        case core::BuiltinFn::kAtomicMax:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicMax;
             break;
-        case core::Function::kAtomicMin:
+        case core::BuiltinFn::kAtomicMin:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicMin;
             break;
-        case core::Function::kAtomicAnd:
+        case core::BuiltinFn::kAtomicAnd:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicAnd;
             break;
-        case core::Function::kAtomicOr:
+        case core::BuiltinFn::kAtomicOr:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicOr;
             break;
-        case core::Function::kAtomicXor:
+        case core::BuiltinFn::kAtomicXor:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicXor;
             break;
-        case core::Function::kAtomicExchange:
+        case core::BuiltinFn::kAtomicExchange:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicExchange;
             break;
-        case core::Function::kAtomicCompareExchangeWeak:
+        case core::BuiltinFn::kAtomicCompareExchangeWeak:
             op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicCompareExchangeWeak;
             break;
         default:
@@ -629,38 +629,38 @@
         });
     }
 
-    /// AtomicFunc() returns a symbol to an intrinsic function that performs an  atomic operation on
+    /// AtomicFunc() returns a symbol to an builtin function that performs an  atomic operation on
     /// the storage buffer @p buffer. The function has the signature:
     // `fn atomic_op(offset : u32, ...) -> T`
     /// @param el_ty the storage buffer element type
-    /// @param intrinsic the atomic intrinsic
+    /// @param builtin the atomic builtin
     /// @param buffer the symbol of the storage buffer variable, owned by the target ProgramBuilder.
     /// @return the name of the function that performs the load
     Symbol AtomicFunc(const core::type::Type* el_ty,
-                      const sem::Builtin* intrinsic,
+                      const sem::BuiltinFn* builtin,
                       const Symbol& buffer) {
-        auto op = intrinsic->Type();
-        return tint::GetOrCreate(atomic_funcs, AtomicKey{el_ty, op, buffer}, [&] {
+        auto fn = builtin->Fn();
+        return tint::GetOrCreate(atomic_funcs, AtomicKey{el_ty, fn, buffer}, [&] {
             // The first parameter to all WGSL atomics is the expression to the
             // atomic. This is replaced with two parameters: the buffer and offset.
             Vector params{b.Param("offset", b.ty.u32())};
 
             // Other parameters are copied as-is:
-            for (size_t i = 1; i < intrinsic->Parameters().Length(); i++) {
-                auto* param = intrinsic->Parameters()[i];
+            for (size_t i = 1; i < builtin->Parameters().Length(); i++) {
+                auto* param = builtin->Parameters()[i];
                 auto ty = CreateASTTypeFor(ctx, param->Type());
                 params.Push(b.Param("param_" + std::to_string(i), ty));
             }
 
-            auto* atomic = IntrinsicAtomicFor(ctx.dst, op, el_ty, buffer);
+            auto* atomic = IntrinsicAtomicFor(ctx.dst, fn, el_ty, buffer);
             if (TINT_UNLIKELY(!atomic)) {
-                TINT_ICE() << "IntrinsicAtomicFor() returned nullptr for op " << op << " and type "
+                TINT_ICE() << "IntrinsicAtomicFor() returned nullptr for fn " << fn << " and type "
                            << el_ty->TypeInfo().name;
             }
 
-            ast::Type ret_ty = CreateASTTypeFor(ctx, intrinsic->ReturnType());
+            ast::Type ret_ty = CreateASTTypeFor(ctx, builtin->ReturnType());
 
-            auto name = b.Symbols().New(buffer.Name() + intrinsic->str());
+            auto name = b.Symbols().New(buffer.Name() + builtin->str());
             b.Func(name, std::move(params), ret_ty, nullptr,
                    Vector{
                        atomic,
@@ -921,8 +921,8 @@
 
         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() == core::Function::kArrayLength) {
+            if (auto* builtin = call->Target()->As<sem::BuiltinFn>()) {
+                if (builtin->Fn() == core::BuiltinFn::kArrayLength) {
                     // arrayLength(X)
                     // Don't convert X into a load, this builtin actually requires the real pointer.
                     state.TakeAccess(call_expr->args[0]);
diff --git a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
index e2fd37e..dc72ff3 100644
--- a/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
+++ b/src/tint/lang/msl/writer/ast_printer/ast_printer.cc
@@ -630,7 +630,7 @@
     auto* target = call->Target();
     return Switch(
         target, [&](const sem::Function* func) { return EmitFunctionCall(out, call, func); },
-        [&](const sem::Builtin* builtin) { return EmitBuiltinCall(out, call, builtin); },
+        [&](const sem::BuiltinFn* builtin) { return EmitBuiltinCall(out, call, builtin); },
         [&](const sem::ValueConversion* conv) { return EmitTypeConversion(out, call, conv); },
         [&](const sem::ValueConstructor* ctor) { return EmitTypeInitializer(out, call, ctor); },
         [&](Default) {
@@ -668,7 +668,7 @@
 
 bool ASTPrinter::EmitBuiltinCall(StringStream& out,
                                  const sem::Call* call,
-                                 const sem::Builtin* builtin) {
+                                 const sem::BuiltinFn* builtin) {
     auto* expr = call->Declaration();
     if (builtin->IsAtomic()) {
         return EmitAtomicCall(out, expr, builtin);
@@ -679,25 +679,25 @@
 
     auto name = generate_builtin_name(builtin);
 
-    switch (builtin->Type()) {
-        case core::Function::kDot:
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kDot:
             return EmitDotCall(out, expr, builtin);
-        case core::Function::kModf:
+        case core::BuiltinFn::kModf:
             return EmitModfCall(out, expr, builtin);
-        case core::Function::kFrexp:
+        case core::BuiltinFn::kFrexp:
             return EmitFrexpCall(out, expr, builtin);
-        case core::Function::kDegrees:
+        case core::BuiltinFn::kDegrees:
             return EmitDegreesCall(out, expr, builtin);
-        case core::Function::kRadians:
+        case core::BuiltinFn::kRadians:
             return EmitRadiansCall(out, expr, builtin);
-        case core::Function::kDot4I8Packed:
+        case core::BuiltinFn::kDot4I8Packed:
             return EmitDot4I8PackedCall(out, expr, builtin);
-        case core::Function::kDot4U8Packed:
+        case core::BuiltinFn::kDot4U8Packed:
             return EmitDot4U8PackedCall(out, expr, builtin);
 
-        case core::Function::kPack2X16Float:
-        case core::Function::kUnpack2X16Float: {
-            if (builtin->Type() == core::Function::kPack2X16Float) {
+        case core::BuiltinFn::kPack2X16Float:
+        case core::BuiltinFn::kUnpack2X16Float: {
+            if (builtin->Fn() == core::BuiltinFn::kPack2X16Float) {
                 out << "as_type<uint>(half2(";
             } else {
                 out << "float2(as_type<half2>(";
@@ -708,7 +708,7 @@
             out << "))";
             return true;
         }
-        case core::Function::kQuantizeToF16: {
+        case core::BuiltinFn::kQuantizeToF16: {
             std::string width = "";
             if (auto* vec = builtin->ReturnType()->As<core::type::Vector>()) {
                 width = std::to_string(vec->Width());
@@ -722,20 +722,20 @@
         }
         // TODO(crbug.com/tint/661): Combine sequential barriers to a single
         // instruction.
-        case core::Function::kStorageBarrier: {
+        case core::BuiltinFn::kStorageBarrier: {
             out << "threadgroup_barrier(mem_flags::mem_device)";
             return true;
         }
-        case core::Function::kWorkgroupBarrier: {
+        case core::BuiltinFn::kWorkgroupBarrier: {
             out << "threadgroup_barrier(mem_flags::mem_threadgroup)";
             return true;
         }
-        case core::Function::kTextureBarrier: {
+        case core::BuiltinFn::kTextureBarrier: {
             out << "threadgroup_barrier(mem_flags::mem_texture)";
             return true;
         }
 
-        case core::Function::kLength: {
+        case core::BuiltinFn::kLength: {
             auto* sem = builder_.Sem().GetVal(expr->args[0]);
             if (sem->Type()->UnwrapRef()->Is<core::type::Scalar>()) {
                 // Emulate scalar overload using fabs(x).
@@ -744,7 +744,7 @@
             break;
         }
 
-        case core::Function::kDistance: {
+        case core::BuiltinFn::kDistance: {
             auto* sem = builder_.Sem().GetVal(expr->args[0]);
             if (sem->Type()->UnwrapRef()->Is<core::type::Scalar>()) {
                 // Emulate scalar overload using fabs(x - y);
@@ -762,7 +762,7 @@
             break;
         }
 
-        case core::Function::kSubgroupBroadcast: {
+        case core::BuiltinFn::kSubgroupBroadcast: {
             // The lane argument is ushort.
             out << "simd_broadcast(";
             if (!EmitExpression(out, expr->args[0])) {
@@ -876,7 +876,7 @@
 
 bool ASTPrinter::EmitAtomicCall(StringStream& out,
                                 const ast::CallExpression* expr,
-                                const sem::Builtin* builtin) {
+                                const sem::BuiltinFn* builtin) {
     auto call = [&](const std::string& name, bool append_memory_order_relaxed) {
         out << name;
         {
@@ -897,38 +897,38 @@
         return true;
     };
 
-    switch (builtin->Type()) {
-        case core::Function::kAtomicLoad:
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kAtomicLoad:
             return call("atomic_load_explicit", true);
 
-        case core::Function::kAtomicStore:
+        case core::BuiltinFn::kAtomicStore:
             return call("atomic_store_explicit", true);
 
-        case core::Function::kAtomicAdd:
+        case core::BuiltinFn::kAtomicAdd:
             return call("atomic_fetch_add_explicit", true);
 
-        case core::Function::kAtomicSub:
+        case core::BuiltinFn::kAtomicSub:
             return call("atomic_fetch_sub_explicit", true);
 
-        case core::Function::kAtomicMax:
+        case core::BuiltinFn::kAtomicMax:
             return call("atomic_fetch_max_explicit", true);
 
-        case core::Function::kAtomicMin:
+        case core::BuiltinFn::kAtomicMin:
             return call("atomic_fetch_min_explicit", true);
 
-        case core::Function::kAtomicAnd:
+        case core::BuiltinFn::kAtomicAnd:
             return call("atomic_fetch_and_explicit", true);
 
-        case core::Function::kAtomicOr:
+        case core::BuiltinFn::kAtomicOr:
             return call("atomic_fetch_or_explicit", true);
 
-        case core::Function::kAtomicXor:
+        case core::BuiltinFn::kAtomicXor:
             return call("atomic_fetch_xor_explicit", true);
 
-        case core::Function::kAtomicExchange:
+        case core::BuiltinFn::kAtomicExchange:
             return call("atomic_exchange_explicit", true);
 
-        case core::Function::kAtomicCompareExchangeWeak: {
+        case core::BuiltinFn::kAtomicCompareExchangeWeak: {
             auto* ptr_ty = TypeOf(expr->args[0])->UnwrapRef()->As<core::type::Pointer>();
             auto sc = ptr_ty->AddressSpace();
             auto* str = builtin->ReturnType()->As<core::type::Struct>();
@@ -995,13 +995,13 @@
             break;
     }
 
-    TINT_UNREACHABLE() << "unsupported atomic builtin: " << builtin->Type();
+    TINT_UNREACHABLE() << "unsupported atomic builtin: " << builtin->Fn();
     return false;
 }
 
 bool ASTPrinter::EmitTextureCall(StringStream& out,
                                  const sem::Call* call,
-                                 const sem::Builtin* builtin) {
+                                 const sem::BuiltinFn* builtin) {
     using Usage = core::ParameterUsage;
 
     auto& signature = builtin->Signature();
@@ -1043,8 +1043,8 @@
     // MSL requires that `lod` is a constant 0 for 1D textures.
     bool level_is_constant_zero = texture_type->dim() == core::type::TextureDimension::k1d;
 
-    switch (builtin->Type()) {
-        case core::Function::kTextureDimensions: {
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kTextureDimensions: {
             std::vector<const char*> dims;
             switch (texture_type->dim()) {
                 case core::type::TextureDimension::kNone:
@@ -1097,21 +1097,21 @@
             }
             return true;
         }
-        case core::Function::kTextureNumLayers: {
+        case core::BuiltinFn::kTextureNumLayers: {
             if (!texture_expr()) {
                 return false;
             }
             out << ".get_array_size()";
             return true;
         }
-        case core::Function::kTextureNumLevels: {
+        case core::BuiltinFn::kTextureNumLevels: {
             if (!texture_expr()) {
                 return false;
             }
             out << ".get_num_mip_levels()";
             return true;
         }
-        case core::Function::kTextureNumSamples: {
+        case core::BuiltinFn::kTextureNumSamples: {
             if (!texture_expr()) {
                 return false;
             }
@@ -1128,28 +1128,28 @@
 
     bool lod_param_is_named = true;
 
-    switch (builtin->Type()) {
-        case core::Function::kTextureSample:
-        case core::Function::kTextureSampleBias:
-        case core::Function::kTextureSampleLevel:
-        case core::Function::kTextureSampleGrad:
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kTextureSample:
+        case core::BuiltinFn::kTextureSampleBias:
+        case core::BuiltinFn::kTextureSampleLevel:
+        case core::BuiltinFn::kTextureSampleGrad:
             out << ".sample(";
             break;
-        case core::Function::kTextureSampleCompare:
-        case core::Function::kTextureSampleCompareLevel:
+        case core::BuiltinFn::kTextureSampleCompare:
+        case core::BuiltinFn::kTextureSampleCompareLevel:
             out << ".sample_compare(";
             break;
-        case core::Function::kTextureGather:
+        case core::BuiltinFn::kTextureGather:
             out << ".gather(";
             break;
-        case core::Function::kTextureGatherCompare:
+        case core::BuiltinFn::kTextureGatherCompare:
             out << ".gather_compare(";
             break;
-        case core::Function::kTextureLoad:
+        case core::BuiltinFn::kTextureLoad:
             out << ".read(";
             lod_param_is_named = false;
             break;
-        case core::Function::kTextureStore:
+        case core::BuiltinFn::kTextureStore:
             out << ".write(";
             break;
         default:
@@ -1225,7 +1225,7 @@
             out << ")";
         }
     }
-    if (builtin->Type() == core::Function::kTextureSampleCompareLevel) {
+    if (builtin->Fn() == core::BuiltinFn::kTextureSampleCompareLevel) {
         maybe_write_comma();
         out << "level(0)";
     }
@@ -1310,7 +1310,7 @@
     // If this is a `textureStore()` for a read-write texture, add a fence to ensure that the
     // written values are visible to subsequent reads from the same thread.
     if (auto* storage = texture_type->As<core::type::StorageTexture>();
-        builtin->Type() == core::Function::kTextureStore &&
+        builtin->Fn() == core::BuiltinFn::kTextureStore &&
         storage->access() == core::Access::kReadWrite) {
         out << "; ";
         texture_expr();
@@ -1322,7 +1322,7 @@
 
 bool ASTPrinter::EmitDotCall(StringStream& out,
                              const ast::CallExpression* expr,
-                             const sem::Builtin* builtin) {
+                             const sem::BuiltinFn* builtin) {
     auto* vec_ty = builtin->Parameters()[0]->Type()->As<core::type::Vector>();
     std::string fn = "dot";
     if (vec_ty->type()->is_integer_scalar()) {
@@ -1367,7 +1367,7 @@
 
 bool ASTPrinter::EmitDot4I8PackedCall(StringStream& out,
                                       const ast::CallExpression* expr,
-                                      const sem::Builtin* builtin) {
+                                      const sem::BuiltinFn* builtin) {
     return CallBuiltinHelper(
         out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
             Line(b) << "packed_char4 vec1 = as_type<packed_char4>(" << params[0] << ");";
@@ -1380,7 +1380,7 @@
 
 bool ASTPrinter::EmitDot4U8PackedCall(StringStream& out,
                                       const ast::CallExpression* expr,
-                                      const sem::Builtin* builtin) {
+                                      const sem::BuiltinFn* builtin) {
     return CallBuiltinHelper(
         out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
             Line(b) << "packed_uchar4 vec1 = as_type<packed_uchar4>(" << params[0] << ");";
@@ -1393,7 +1393,7 @@
 
 bool ASTPrinter::EmitModfCall(StringStream& out,
                               const ast::CallExpression* expr,
-                              const sem::Builtin* builtin) {
+                              const sem::BuiltinFn* builtin) {
     return CallBuiltinHelper(
         out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
             auto* ty = builtin->Parameters()[0]->Type();
@@ -1419,7 +1419,7 @@
 
 bool ASTPrinter::EmitFrexpCall(StringStream& out,
                                const ast::CallExpression* expr,
-                               const sem::Builtin* builtin) {
+                               const sem::BuiltinFn* builtin) {
     return CallBuiltinHelper(
         out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
             auto* ty = builtin->Parameters()[0]->Type();
@@ -1445,7 +1445,7 @@
 
 bool ASTPrinter::EmitDegreesCall(StringStream& out,
                                  const ast::CallExpression* expr,
-                                 const sem::Builtin* builtin) {
+                                 const sem::BuiltinFn* builtin) {
     return CallBuiltinHelper(out, expr, builtin,
                              [&](TextBuffer* b, const std::vector<std::string>& params) {
                                  Line(b) << "return " << params[0] << " * " << std::setprecision(20)
@@ -1456,7 +1456,7 @@
 
 bool ASTPrinter::EmitRadiansCall(StringStream& out,
                                  const ast::CallExpression* expr,
-                                 const sem::Builtin* builtin) {
+                                 const sem::BuiltinFn* builtin) {
     return CallBuiltinHelper(out, expr, builtin,
                              [&](TextBuffer* b, const std::vector<std::string>& params) {
                                  Line(b) << "return " << params[0] << " * " << std::setprecision(20)
@@ -1465,146 +1465,146 @@
                              });
 }
 
-std::string ASTPrinter::generate_builtin_name(const sem::Builtin* builtin) {
+std::string ASTPrinter::generate_builtin_name(const sem::BuiltinFn* builtin) {
     std::string out = "";
-    switch (builtin->Type()) {
-        case core::Function::kAcos:
-        case core::Function::kAcosh:
-        case core::Function::kAll:
-        case core::Function::kAny:
-        case core::Function::kAsin:
-        case core::Function::kAsinh:
-        case core::Function::kAtanh:
-        case core::Function::kAtan:
-        case core::Function::kAtan2:
-        case core::Function::kCeil:
-        case core::Function::kCos:
-        case core::Function::kCosh:
-        case core::Function::kCross:
-        case core::Function::kDeterminant:
-        case core::Function::kDistance:
-        case core::Function::kDot:
-        case core::Function::kExp:
-        case core::Function::kExp2:
-        case core::Function::kFloor:
-        case core::Function::kFma:
-        case core::Function::kFract:
-        case core::Function::kFrexp:
-        case core::Function::kLength:
-        case core::Function::kLdexp:
-        case core::Function::kLog:
-        case core::Function::kLog2:
-        case core::Function::kMix:
-        case core::Function::kModf:
-        case core::Function::kNormalize:
-        case core::Function::kPow:
-        case core::Function::kReflect:
-        case core::Function::kRefract:
-        case core::Function::kSaturate:
-        case core::Function::kSelect:
-        case core::Function::kSin:
-        case core::Function::kSinh:
-        case core::Function::kSqrt:
-        case core::Function::kStep:
-        case core::Function::kTan:
-        case core::Function::kTanh:
-        case core::Function::kTranspose:
-        case core::Function::kTrunc:
-        case core::Function::kSign:
-        case core::Function::kClamp:
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kAcos:
+        case core::BuiltinFn::kAcosh:
+        case core::BuiltinFn::kAll:
+        case core::BuiltinFn::kAny:
+        case core::BuiltinFn::kAsin:
+        case core::BuiltinFn::kAsinh:
+        case core::BuiltinFn::kAtanh:
+        case core::BuiltinFn::kAtan:
+        case core::BuiltinFn::kAtan2:
+        case core::BuiltinFn::kCeil:
+        case core::BuiltinFn::kCos:
+        case core::BuiltinFn::kCosh:
+        case core::BuiltinFn::kCross:
+        case core::BuiltinFn::kDeterminant:
+        case core::BuiltinFn::kDistance:
+        case core::BuiltinFn::kDot:
+        case core::BuiltinFn::kExp:
+        case core::BuiltinFn::kExp2:
+        case core::BuiltinFn::kFloor:
+        case core::BuiltinFn::kFma:
+        case core::BuiltinFn::kFract:
+        case core::BuiltinFn::kFrexp:
+        case core::BuiltinFn::kLength:
+        case core::BuiltinFn::kLdexp:
+        case core::BuiltinFn::kLog:
+        case core::BuiltinFn::kLog2:
+        case core::BuiltinFn::kMix:
+        case core::BuiltinFn::kModf:
+        case core::BuiltinFn::kNormalize:
+        case core::BuiltinFn::kPow:
+        case core::BuiltinFn::kReflect:
+        case core::BuiltinFn::kRefract:
+        case core::BuiltinFn::kSaturate:
+        case core::BuiltinFn::kSelect:
+        case core::BuiltinFn::kSin:
+        case core::BuiltinFn::kSinh:
+        case core::BuiltinFn::kSqrt:
+        case core::BuiltinFn::kStep:
+        case core::BuiltinFn::kTan:
+        case core::BuiltinFn::kTanh:
+        case core::BuiltinFn::kTranspose:
+        case core::BuiltinFn::kTrunc:
+        case core::BuiltinFn::kSign:
+        case core::BuiltinFn::kClamp:
             out += builtin->str();
             break;
-        case core::Function::kAbs:
+        case core::BuiltinFn::kAbs:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 out += "fabs";
             } else {
                 out += "abs";
             }
             break;
-        case core::Function::kCountLeadingZeros:
+        case core::BuiltinFn::kCountLeadingZeros:
             out += "clz";
             break;
-        case core::Function::kCountOneBits:
+        case core::BuiltinFn::kCountOneBits:
             out += "popcount";
             break;
-        case core::Function::kCountTrailingZeros:
+        case core::BuiltinFn::kCountTrailingZeros:
             out += "ctz";
             break;
-        case core::Function::kDpdx:
-        case core::Function::kDpdxCoarse:
-        case core::Function::kDpdxFine:
+        case core::BuiltinFn::kDpdx:
+        case core::BuiltinFn::kDpdxCoarse:
+        case core::BuiltinFn::kDpdxFine:
             out += "dfdx";
             break;
-        case core::Function::kDpdy:
-        case core::Function::kDpdyCoarse:
-        case core::Function::kDpdyFine:
+        case core::BuiltinFn::kDpdy:
+        case core::BuiltinFn::kDpdyCoarse:
+        case core::BuiltinFn::kDpdyFine:
             out += "dfdy";
             break;
-        case core::Function::kExtractBits:
+        case core::BuiltinFn::kExtractBits:
             out += "extract_bits";
             break;
-        case core::Function::kInsertBits:
+        case core::BuiltinFn::kInsertBits:
             out += "insert_bits";
             break;
-        case core::Function::kFwidth:
-        case core::Function::kFwidthCoarse:
-        case core::Function::kFwidthFine:
+        case core::BuiltinFn::kFwidth:
+        case core::BuiltinFn::kFwidthCoarse:
+        case core::BuiltinFn::kFwidthFine:
             out += "fwidth";
             break;
-        case core::Function::kMax:
+        case core::BuiltinFn::kMax:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 out += "fmax";
             } else {
                 out += "max";
             }
             break;
-        case core::Function::kMin:
+        case core::BuiltinFn::kMin:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 out += "fmin";
             } else {
                 out += "min";
             }
             break;
-        case core::Function::kFaceForward:
+        case core::BuiltinFn::kFaceForward:
             out += "faceforward";
             break;
-        case core::Function::kPack4X8Snorm:
+        case core::BuiltinFn::kPack4X8Snorm:
             out += "pack_float_to_snorm4x8";
             break;
-        case core::Function::kPack4X8Unorm:
+        case core::BuiltinFn::kPack4X8Unorm:
             out += "pack_float_to_unorm4x8";
             break;
-        case core::Function::kPack2X16Snorm:
+        case core::BuiltinFn::kPack2X16Snorm:
             out += "pack_float_to_snorm2x16";
             break;
-        case core::Function::kPack2X16Unorm:
+        case core::BuiltinFn::kPack2X16Unorm:
             out += "pack_float_to_unorm2x16";
             break;
-        case core::Function::kReverseBits:
+        case core::BuiltinFn::kReverseBits:
             out += "reverse_bits";
             break;
-        case core::Function::kRound:
+        case core::BuiltinFn::kRound:
             out += "rint";
             break;
-        case core::Function::kSmoothstep:
+        case core::BuiltinFn::kSmoothstep:
             out += "smoothstep";
             break;
-        case core::Function::kInverseSqrt:
+        case core::BuiltinFn::kInverseSqrt:
             out += "rsqrt";
             break;
-        case core::Function::kUnpack4X8Snorm:
+        case core::BuiltinFn::kUnpack4X8Snorm:
             out += "unpack_snorm4x8_to_float";
             break;
-        case core::Function::kUnpack4X8Unorm:
+        case core::BuiltinFn::kUnpack4X8Unorm:
             out += "unpack_unorm4x8_to_float";
             break;
-        case core::Function::kUnpack2X16Snorm:
+        case core::BuiltinFn::kUnpack2X16Snorm:
             out += "unpack_snorm2x16_to_float";
             break;
-        case core::Function::kUnpack2X16Unorm:
+        case core::BuiltinFn::kUnpack2X16Unorm:
             out += "unpack_unorm2x16_to_float";
             break;
-        case core::Function::kArrayLength:
+        case core::BuiltinFn::kArrayLength:
             diagnostics_.add_error(
                 diag::System::Writer,
                 "Unable to translate builtin: " + std::string(builtin->str()) +
@@ -3063,14 +3063,14 @@
 template <typename F>
 bool ASTPrinter::CallBuiltinHelper(StringStream& out,
                                    const ast::CallExpression* call,
-                                   const sem::Builtin* builtin,
+                                   const sem::BuiltinFn* builtin,
                                    F&& build) {
     // Generate the helper function if it hasn't been created already
     auto fn = tint::GetOrCreate(builtins_, builtin, [&]() -> std::string {
         TextBuffer b;
         TINT_DEFER(helpers_.Append(b));
 
-        auto fn_name = UniqueIdentifier(std::string("tint_") + core::str(builtin->Type()));
+        auto fn_name = UniqueIdentifier(std::string("tint_") + core::str(builtin->Fn()));
         std::vector<std::string> parameter_names;
         {
             auto decl = Line(&b);
diff --git a/src/tint/lang/msl/writer/ast_printer/ast_printer.h b/src/tint/lang/msl/writer/ast_printer/ast_printer.h
index 47f1ef7..b4796b0 100644
--- a/src/tint/lang/msl/writer/ast_printer/ast_printer.h
+++ b/src/tint/lang/msl/writer/ast_printer/ast_printer.h
@@ -47,7 +47,7 @@
 #include "src/tint/utils/text/string_stream.h"
 
 namespace tint::sem {
-class Builtin;
+class BuiltinFn;
 class Call;
 class ValueConstructor;
 class ValueConversion;
@@ -144,7 +144,7 @@
     /// @param call the call expression
     /// @param builtin the builtin being called
     /// @returns true if the call expression is emitted
-    bool EmitBuiltinCall(StringStream& out, const sem::Call* call, const sem::Builtin* builtin);
+    bool EmitBuiltinCall(StringStream& out, const sem::Call* call, const sem::BuiltinFn* builtin);
     /// Handles generating a value conversion expression
     /// @param out the output of the expression stream
     /// @param call the call expression
@@ -175,14 +175,14 @@
     /// @returns true if the call expression is emitted
     bool EmitAtomicCall(StringStream& out,
                         const ast::CallExpression* expr,
-                        const sem::Builtin* builtin);
+                        const sem::BuiltinFn* builtin);
     /// Handles generating a call to a texture function (`textureSample`,
     /// `textureSampleGrad`, etc)
     /// @param out the output of the expression stream
     /// @param call the call expression
     /// @param builtin the semantic information for the texture builtin
     /// @returns true if the call expression is emitted
-    bool EmitTextureCall(StringStream& out, const sem::Call* call, const sem::Builtin* builtin);
+    bool EmitTextureCall(StringStream& out, const sem::Call* call, const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `dot()` builtin
     /// @param out the output of the expression stream
     /// @param expr the call expression
@@ -190,7 +190,7 @@
     /// @returns true if the call expression is emitted
     bool EmitDotCall(StringStream& out,
                      const ast::CallExpression* expr,
-                     const sem::Builtin* builtin);
+                     const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `modf()` builtin
     /// @param out the output of the expression stream
     /// @param expr the call expression
@@ -198,7 +198,7 @@
     /// @returns true if the call expression is emitted
     bool EmitModfCall(StringStream& out,
                       const ast::CallExpression* expr,
-                      const sem::Builtin* builtin);
+                      const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `frexp()` builtin
     /// @param out the output of the expression stream
     /// @param expr the call expression
@@ -206,7 +206,7 @@
     /// @returns true if the call expression is emitted
     bool EmitFrexpCall(StringStream& out,
                        const ast::CallExpression* expr,
-                       const sem::Builtin* builtin);
+                       const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `degrees()` builtin
     /// @param out the output of the expression stream
     /// @param expr the call expression
@@ -214,7 +214,7 @@
     /// @returns true if the call expression is emitted
     bool EmitDegreesCall(StringStream& out,
                          const ast::CallExpression* expr,
-                         const sem::Builtin* builtin);
+                         const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `radians()` builtin
     /// @param out the output of the expression stream
     /// @param expr the call expression
@@ -222,7 +222,7 @@
     /// @returns true if the call expression is emitted
     bool EmitRadiansCall(StringStream& out,
                          const ast::CallExpression* expr,
-                         const sem::Builtin* builtin);
+                         const sem::BuiltinFn* builtin);
     /// Handles a case statement
     /// @param stmt the statement
     /// @returns true if the statement was emitted successfully
@@ -355,7 +355,7 @@
     /// @returns true if the call expression is emitted
     bool EmitDot4I8PackedCall(StringStream& out,
                               const ast::CallExpression* expr,
-                              const sem::Builtin* builtin);
+                              const sem::BuiltinFn* builtin);
     /// Handles generating a call to the `dot4U8Packed()` builtin
     /// @param out the output of the expression stream
     /// @param expr the call expression
@@ -363,12 +363,12 @@
     /// @returns true if the call expression is emitted
     bool EmitDot4U8PackedCall(StringStream& out,
                               const ast::CallExpression* expr,
-                              const sem::Builtin* builtin);
+                              const sem::BuiltinFn* builtin);
 
     /// Handles generating a builtin name
     /// @param builtin the semantic info for the builtin
     /// @returns the name or "" if not valid
-    std::string generate_builtin_name(const sem::Builtin* builtin);
+    std::string generate_builtin_name(const sem::BuiltinFn* builtin);
 
   private:
     /// CallBuiltinHelper will call the builtin helper function, creating it
@@ -387,7 +387,7 @@
     template <typename F>
     bool CallBuiltinHelper(StringStream& out,
                            const ast::CallExpression* call,
-                           const sem::Builtin* builtin,
+                           const sem::BuiltinFn* builtin,
                            F&& build);
 
     /// @returns the name of the templated tint_array helper type, generating it if this is the
@@ -442,7 +442,7 @@
     /// should be created for that index.
     std::unordered_map<std::string, std::vector<uint32_t>> workgroup_allocations_;
 
-    std::unordered_map<const sem::Builtin*, std::string> builtins_;
+    std::unordered_map<const sem::BuiltinFn*, std::string> builtins_;
     std::unordered_map<const core::type::Type*, std::string> unary_minus_funcs_;
     std::unordered_map<uint32_t, std::string> int_dot_funcs_;
     std::unordered_set<const core::type::Struct*> emitted_structs_;
diff --git a/src/tint/lang/msl/writer/ast_printer/builtin_test.cc b/src/tint/lang/msl/writer/ast_printer/builtin_test.cc
index f596fd5..a137075 100644
--- a/src/tint/lang/msl/writer/ast_printer/builtin_test.cc
+++ b/src/tint/lang/msl/writer/ast_printer/builtin_test.cc
@@ -33,7 +33,7 @@
 };
 
 struct BuiltinData {
-    core::Function builtin;
+    core::BuiltinFn builtin;
     CallParamType type;
     const char* msl_name;
 };
@@ -57,88 +57,88 @@
     return out;
 }
 
-const ast::CallExpression* GenerateCall(core::Function builtin,
+const ast::CallExpression* GenerateCall(core::BuiltinFn builtin,
                                         CallParamType type,
                                         ProgramBuilder* builder) {
     std::string name;
     StringStream str;
     str << name << builtin;
     switch (builtin) {
-        case core::Function::kAcos:
-        case core::Function::kAsin:
-        case core::Function::kAtan:
-        case core::Function::kCeil:
-        case core::Function::kCos:
-        case core::Function::kCosh:
-        case core::Function::kDpdx:
-        case core::Function::kDpdxCoarse:
-        case core::Function::kDpdxFine:
-        case core::Function::kDpdy:
-        case core::Function::kDpdyCoarse:
-        case core::Function::kDpdyFine:
-        case core::Function::kExp:
-        case core::Function::kExp2:
-        case core::Function::kFloor:
-        case core::Function::kFract:
-        case core::Function::kFwidth:
-        case core::Function::kFwidthCoarse:
-        case core::Function::kFwidthFine:
-        case core::Function::kInverseSqrt:
-        case core::Function::kLength:
-        case core::Function::kLog:
-        case core::Function::kLog2:
-        case core::Function::kNormalize:
-        case core::Function::kRound:
-        case core::Function::kSin:
-        case core::Function::kSinh:
-        case core::Function::kSqrt:
-        case core::Function::kTan:
-        case core::Function::kTanh:
-        case core::Function::kTrunc:
-        case core::Function::kSign:
+        case core::BuiltinFn::kAcos:
+        case core::BuiltinFn::kAsin:
+        case core::BuiltinFn::kAtan:
+        case core::BuiltinFn::kCeil:
+        case core::BuiltinFn::kCos:
+        case core::BuiltinFn::kCosh:
+        case core::BuiltinFn::kDpdx:
+        case core::BuiltinFn::kDpdxCoarse:
+        case core::BuiltinFn::kDpdxFine:
+        case core::BuiltinFn::kDpdy:
+        case core::BuiltinFn::kDpdyCoarse:
+        case core::BuiltinFn::kDpdyFine:
+        case core::BuiltinFn::kExp:
+        case core::BuiltinFn::kExp2:
+        case core::BuiltinFn::kFloor:
+        case core::BuiltinFn::kFract:
+        case core::BuiltinFn::kFwidth:
+        case core::BuiltinFn::kFwidthCoarse:
+        case core::BuiltinFn::kFwidthFine:
+        case core::BuiltinFn::kInverseSqrt:
+        case core::BuiltinFn::kLength:
+        case core::BuiltinFn::kLog:
+        case core::BuiltinFn::kLog2:
+        case core::BuiltinFn::kNormalize:
+        case core::BuiltinFn::kRound:
+        case core::BuiltinFn::kSin:
+        case core::BuiltinFn::kSinh:
+        case core::BuiltinFn::kSqrt:
+        case core::BuiltinFn::kTan:
+        case core::BuiltinFn::kTanh:
+        case core::BuiltinFn::kTrunc:
+        case core::BuiltinFn::kSign:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2");
             } else {
                 return builder->Call(str.str(), "f2");
             }
-        case core::Function::kLdexp:
+        case core::BuiltinFn::kLdexp:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "i2");
             } else {
                 return builder->Call(str.str(), "f2", "i2");
             }
-        case core::Function::kAtan2:
-        case core::Function::kDot:
-        case core::Function::kDistance:
-        case core::Function::kPow:
-        case core::Function::kReflect:
-        case core::Function::kStep:
+        case core::BuiltinFn::kAtan2:
+        case core::BuiltinFn::kDot:
+        case core::BuiltinFn::kDistance:
+        case core::BuiltinFn::kPow:
+        case core::BuiltinFn::kReflect:
+        case core::BuiltinFn::kStep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2");
             }
-        case core::Function::kStorageBarrier:
+        case core::BuiltinFn::kStorageBarrier:
             return builder->Call(str.str());
-        case core::Function::kCross:
+        case core::BuiltinFn::kCross:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h3", "h3");
             } else {
                 return builder->Call(str.str(), "f3", "f3");
             }
-        case core::Function::kFma:
-        case core::Function::kMix:
-        case core::Function::kFaceForward:
-        case core::Function::kSmoothstep:
+        case core::BuiltinFn::kFma:
+        case core::BuiltinFn::kMix:
+        case core::BuiltinFn::kFaceForward:
+        case core::BuiltinFn::kSmoothstep:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "h2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             }
-        case core::Function::kAll:
-        case core::Function::kAny:
+        case core::BuiltinFn::kAll:
+        case core::BuiltinFn::kAny:
             return builder->Call(str.str(), "b2");
-        case core::Function::kAbs:
+        case core::BuiltinFn::kAbs:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2");
             } else if (type == CallParamType::kF16) {
@@ -146,17 +146,17 @@
             } else {
                 return builder->Call(str.str(), "u2");
             }
-        case core::Function::kCountLeadingZeros:
-        case core::Function::kCountOneBits:
-        case core::Function::kCountTrailingZeros:
-        case core::Function::kReverseBits:
+        case core::BuiltinFn::kCountLeadingZeros:
+        case core::BuiltinFn::kCountOneBits:
+        case core::BuiltinFn::kCountTrailingZeros:
+        case core::BuiltinFn::kReverseBits:
             return builder->Call(str.str(), "u2");
-        case core::Function::kExtractBits:
+        case core::BuiltinFn::kExtractBits:
             return builder->Call(str.str(), "u2", "u1", "u1");
-        case core::Function::kInsertBits:
+        case core::BuiltinFn::kInsertBits:
             return builder->Call(str.str(), "u2", "u2", "u1", "u1");
-        case core::Function::kMax:
-        case core::Function::kMin:
+        case core::BuiltinFn::kMax:
+        case core::BuiltinFn::kMin:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -164,7 +164,7 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2");
             }
-        case core::Function::kClamp:
+        case core::BuiltinFn::kClamp:
             if (type == CallParamType::kF32) {
                 return builder->Call(str.str(), "f2", "f2", "f2");
             } else if (type == CallParamType::kF16) {
@@ -172,32 +172,32 @@
             } else {
                 return builder->Call(str.str(), "u2", "u2", "u2");
             }
-        case core::Function::kSelect:
+        case core::BuiltinFn::kSelect:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "h2", "h2", "b2");
             } else {
                 return builder->Call(str.str(), "f2", "f2", "b2");
             }
-        case core::Function::kDeterminant:
+        case core::BuiltinFn::kDeterminant:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm2x2");
             } else {
                 return builder->Call(str.str(), "m2x2");
             }
-        case core::Function::kPack2X16Snorm:
-        case core::Function::kPack2X16Unorm:
+        case core::BuiltinFn::kPack2X16Snorm:
+        case core::BuiltinFn::kPack2X16Unorm:
             return builder->Call(str.str(), "f2");
-        case core::Function::kPack4X8Snorm:
-        case core::Function::kPack4X8Unorm:
+        case core::BuiltinFn::kPack4X8Snorm:
+        case core::BuiltinFn::kPack4X8Unorm:
             return builder->Call(str.str(), "f4");
-        case core::Function::kUnpack4X8Snorm:
-        case core::Function::kUnpack4X8Unorm:
-        case core::Function::kUnpack2X16Snorm:
-        case core::Function::kUnpack2X16Unorm:
+        case core::BuiltinFn::kUnpack4X8Snorm:
+        case core::BuiltinFn::kUnpack4X8Unorm:
+        case core::BuiltinFn::kUnpack2X16Snorm:
+        case core::BuiltinFn::kUnpack2X16Unorm:
             return builder->Call(str.str(), "u1");
-        case core::Function::kWorkgroupBarrier:
+        case core::BuiltinFn::kWorkgroupBarrier:
             return builder->Call(str.str());
-        case core::Function::kTranspose:
+        case core::BuiltinFn::kTranspose:
             if (type == CallParamType::kF16) {
                 return builder->Call(str.str(), "hm3x2");
             } else {
@@ -243,7 +243,7 @@
     ASSERT_NE(sem, nullptr);
     auto* target = sem->Target();
     ASSERT_NE(target, nullptr);
-    auto* builtin = target->As<sem::Builtin>();
+    auto* builtin = target->As<sem::BuiltinFn>();
     ASSERT_NE(builtin, nullptr);
 
     EXPECT_EQ(gen.generate_builtin_name(builtin), param.msl_name);
@@ -253,122 +253,124 @@
     MslBuiltinTest,
     testing::Values(
         /* Logical built-in */
-        BuiltinData{core::Function::kAll, CallParamType::kBool, "all"},
-        BuiltinData{core::Function::kAny, CallParamType::kBool, "any"},
-        BuiltinData{core::Function::kSelect, CallParamType::kF32, "select"},
+        BuiltinData{core::BuiltinFn::kAll, CallParamType::kBool, "all"},
+        BuiltinData{core::BuiltinFn::kAny, CallParamType::kBool, "any"},
+        BuiltinData{core::BuiltinFn::kSelect, CallParamType::kF32, "select"},
         /* Float built-in */
-        BuiltinData{core::Function::kAbs, CallParamType::kF32, "fabs"},
-        BuiltinData{core::Function::kAbs, CallParamType::kF16, "fabs"},
-        BuiltinData{core::Function::kAcos, CallParamType::kF32, "acos"},
-        BuiltinData{core::Function::kAcos, CallParamType::kF16, "acos"},
-        BuiltinData{core::Function::kAsin, CallParamType::kF32, "asin"},
-        BuiltinData{core::Function::kAsin, CallParamType::kF16, "asin"},
-        BuiltinData{core::Function::kAtan, CallParamType::kF32, "atan"},
-        BuiltinData{core::Function::kAtan, CallParamType::kF16, "atan"},
-        BuiltinData{core::Function::kAtan2, CallParamType::kF32, "atan2"},
-        BuiltinData{core::Function::kAtan2, CallParamType::kF16, "atan2"},
-        BuiltinData{core::Function::kCeil, CallParamType::kF32, "ceil"},
-        BuiltinData{core::Function::kCeil, CallParamType::kF16, "ceil"},
-        BuiltinData{core::Function::kClamp, CallParamType::kF32, "clamp"},
-        BuiltinData{core::Function::kClamp, CallParamType::kF16, "clamp"},
-        BuiltinData{core::Function::kCos, CallParamType::kF32, "cos"},
-        BuiltinData{core::Function::kCos, CallParamType::kF16, "cos"},
-        BuiltinData{core::Function::kCosh, CallParamType::kF32, "cosh"},
-        BuiltinData{core::Function::kCosh, CallParamType::kF16, "cosh"},
-        BuiltinData{core::Function::kCross, CallParamType::kF32, "cross"},
-        BuiltinData{core::Function::kCross, CallParamType::kF16, "cross"},
-        BuiltinData{core::Function::kDistance, CallParamType::kF32, "distance"},
-        BuiltinData{core::Function::kDistance, CallParamType::kF16, "distance"},
-        BuiltinData{core::Function::kExp, CallParamType::kF32, "exp"},
-        BuiltinData{core::Function::kExp, CallParamType::kF16, "exp"},
-        BuiltinData{core::Function::kExp2, CallParamType::kF32, "exp2"},
-        BuiltinData{core::Function::kExp2, CallParamType::kF16, "exp2"},
-        BuiltinData{core::Function::kFaceForward, CallParamType::kF32, "faceforward"},
-        BuiltinData{core::Function::kFaceForward, CallParamType::kF16, "faceforward"},
-        BuiltinData{core::Function::kFloor, CallParamType::kF32, "floor"},
-        BuiltinData{core::Function::kFloor, CallParamType::kF16, "floor"},
-        BuiltinData{core::Function::kFma, CallParamType::kF32, "fma"},
-        BuiltinData{core::Function::kFma, CallParamType::kF16, "fma"},
-        BuiltinData{core::Function::kFract, CallParamType::kF32, "fract"},
-        BuiltinData{core::Function::kFract, CallParamType::kF16, "fract"},
-        BuiltinData{core::Function::kInverseSqrt, CallParamType::kF32, "rsqrt"},
-        BuiltinData{core::Function::kInverseSqrt, CallParamType::kF16, "rsqrt"},
-        BuiltinData{core::Function::kLdexp, CallParamType::kF32, "ldexp"},
-        BuiltinData{core::Function::kLdexp, CallParamType::kF16, "ldexp"},
-        BuiltinData{core::Function::kLength, CallParamType::kF32, "length"},
-        BuiltinData{core::Function::kLength, CallParamType::kF16, "length"},
-        BuiltinData{core::Function::kLog, CallParamType::kF32, "log"},
-        BuiltinData{core::Function::kLog, CallParamType::kF16, "log"},
-        BuiltinData{core::Function::kLog2, CallParamType::kF32, "log2"},
-        BuiltinData{core::Function::kLog2, CallParamType::kF16, "log2"},
-        BuiltinData{core::Function::kMax, CallParamType::kF32, "fmax"},
-        BuiltinData{core::Function::kMax, CallParamType::kF16, "fmax"},
-        BuiltinData{core::Function::kMin, CallParamType::kF32, "fmin"},
-        BuiltinData{core::Function::kMin, CallParamType::kF16, "fmin"},
-        BuiltinData{core::Function::kNormalize, CallParamType::kF32, "normalize"},
-        BuiltinData{core::Function::kNormalize, CallParamType::kF16, "normalize"},
-        BuiltinData{core::Function::kPow, CallParamType::kF32, "pow"},
-        BuiltinData{core::Function::kPow, CallParamType::kF16, "pow"},
-        BuiltinData{core::Function::kReflect, CallParamType::kF32, "reflect"},
-        BuiltinData{core::Function::kReflect, CallParamType::kF16, "reflect"},
-        BuiltinData{core::Function::kSign, CallParamType::kF32, "sign"},
-        BuiltinData{core::Function::kSign, CallParamType::kF16, "sign"},
-        BuiltinData{core::Function::kSin, CallParamType::kF32, "sin"},
-        BuiltinData{core::Function::kSin, CallParamType::kF16, "sin"},
-        BuiltinData{core::Function::kSinh, CallParamType::kF32, "sinh"},
-        BuiltinData{core::Function::kSinh, CallParamType::kF16, "sinh"},
-        BuiltinData{core::Function::kSmoothstep, CallParamType::kF32, "smoothstep"},
-        BuiltinData{core::Function::kSmoothstep, CallParamType::kF16, "smoothstep"},
-        BuiltinData{core::Function::kSqrt, CallParamType::kF32, "sqrt"},
-        BuiltinData{core::Function::kSqrt, CallParamType::kF16, "sqrt"},
-        BuiltinData{core::Function::kStep, CallParamType::kF32, "step"},
-        BuiltinData{core::Function::kStep, CallParamType::kF16, "step"},
-        BuiltinData{core::Function::kTan, CallParamType::kF32, "tan"},
-        BuiltinData{core::Function::kTan, CallParamType::kF16, "tan"},
-        BuiltinData{core::Function::kTanh, CallParamType::kF32, "tanh"},
-        BuiltinData{core::Function::kTanh, CallParamType::kF16, "tanh"},
-        BuiltinData{core::Function::kTrunc, CallParamType::kF32, "trunc"},
-        BuiltinData{core::Function::kTrunc, CallParamType::kF16, "trunc"},
+        BuiltinData{core::BuiltinFn::kAbs, CallParamType::kF32, "fabs"},
+        BuiltinData{core::BuiltinFn::kAbs, CallParamType::kF16, "fabs"},
+        BuiltinData{core::BuiltinFn::kAcos, CallParamType::kF32, "acos"},
+        BuiltinData{core::BuiltinFn::kAcos, CallParamType::kF16, "acos"},
+        BuiltinData{core::BuiltinFn::kAsin, CallParamType::kF32, "asin"},
+        BuiltinData{core::BuiltinFn::kAsin, CallParamType::kF16, "asin"},
+        BuiltinData{core::BuiltinFn::kAtan, CallParamType::kF32, "atan"},
+        BuiltinData{core::BuiltinFn::kAtan, CallParamType::kF16, "atan"},
+        BuiltinData{core::BuiltinFn::kAtan2, CallParamType::kF32, "atan2"},
+        BuiltinData{core::BuiltinFn::kAtan2, CallParamType::kF16, "atan2"},
+        BuiltinData{core::BuiltinFn::kCeil, CallParamType::kF32, "ceil"},
+        BuiltinData{core::BuiltinFn::kCeil, CallParamType::kF16, "ceil"},
+        BuiltinData{core::BuiltinFn::kClamp, CallParamType::kF32, "clamp"},
+        BuiltinData{core::BuiltinFn::kClamp, CallParamType::kF16, "clamp"},
+        BuiltinData{core::BuiltinFn::kCos, CallParamType::kF32, "cos"},
+        BuiltinData{core::BuiltinFn::kCos, CallParamType::kF16, "cos"},
+        BuiltinData{core::BuiltinFn::kCosh, CallParamType::kF32, "cosh"},
+        BuiltinData{core::BuiltinFn::kCosh, CallParamType::kF16, "cosh"},
+        BuiltinData{core::BuiltinFn::kCross, CallParamType::kF32, "cross"},
+        BuiltinData{core::BuiltinFn::kCross, CallParamType::kF16, "cross"},
+        BuiltinData{core::BuiltinFn::kDistance, CallParamType::kF32, "distance"},
+        BuiltinData{core::BuiltinFn::kDistance, CallParamType::kF16, "distance"},
+        BuiltinData{core::BuiltinFn::kExp, CallParamType::kF32, "exp"},
+        BuiltinData{core::BuiltinFn::kExp, CallParamType::kF16, "exp"},
+        BuiltinData{core::BuiltinFn::kExp2, CallParamType::kF32, "exp2"},
+        BuiltinData{core::BuiltinFn::kExp2, CallParamType::kF16, "exp2"},
+        BuiltinData{core::BuiltinFn::kFaceForward, CallParamType::kF32, "faceforward"},
+        BuiltinData{core::BuiltinFn::kFaceForward, CallParamType::kF16, "faceforward"},
+        BuiltinData{core::BuiltinFn::kFloor, CallParamType::kF32, "floor"},
+        BuiltinData{core::BuiltinFn::kFloor, CallParamType::kF16, "floor"},
+        BuiltinData{core::BuiltinFn::kFma, CallParamType::kF32, "fma"},
+        BuiltinData{core::BuiltinFn::kFma, CallParamType::kF16, "fma"},
+        BuiltinData{core::BuiltinFn::kFract, CallParamType::kF32, "fract"},
+        BuiltinData{core::BuiltinFn::kFract, CallParamType::kF16, "fract"},
+        BuiltinData{core::BuiltinFn::kInverseSqrt, CallParamType::kF32, "rsqrt"},
+        BuiltinData{core::BuiltinFn::kInverseSqrt, CallParamType::kF16, "rsqrt"},
+        BuiltinData{core::BuiltinFn::kLdexp, CallParamType::kF32, "ldexp"},
+        BuiltinData{core::BuiltinFn::kLdexp, CallParamType::kF16, "ldexp"},
+        BuiltinData{core::BuiltinFn::kLength, CallParamType::kF32, "length"},
+        BuiltinData{core::BuiltinFn::kLength, CallParamType::kF16, "length"},
+        BuiltinData{core::BuiltinFn::kLog, CallParamType::kF32, "log"},
+        BuiltinData{core::BuiltinFn::kLog, CallParamType::kF16, "log"},
+        BuiltinData{core::BuiltinFn::kLog2, CallParamType::kF32, "log2"},
+        BuiltinData{core::BuiltinFn::kLog2, CallParamType::kF16, "log2"},
+        BuiltinData{core::BuiltinFn::kMax, CallParamType::kF32, "fmax"},
+        BuiltinData{core::BuiltinFn::kMax, CallParamType::kF16, "fmax"},
+        BuiltinData{core::BuiltinFn::kMin, CallParamType::kF32, "fmin"},
+        BuiltinData{core::BuiltinFn::kMin, CallParamType::kF16, "fmin"},
+        BuiltinData{core::BuiltinFn::kNormalize, CallParamType::kF32, "normalize"},
+        BuiltinData{core::BuiltinFn::kNormalize, CallParamType::kF16, "normalize"},
+        BuiltinData{core::BuiltinFn::kPow, CallParamType::kF32, "pow"},
+        BuiltinData{core::BuiltinFn::kPow, CallParamType::kF16, "pow"},
+        BuiltinData{core::BuiltinFn::kReflect, CallParamType::kF32, "reflect"},
+        BuiltinData{core::BuiltinFn::kReflect, CallParamType::kF16, "reflect"},
+        BuiltinData{core::BuiltinFn::kSign, CallParamType::kF32, "sign"},
+        BuiltinData{core::BuiltinFn::kSign, CallParamType::kF16, "sign"},
+        BuiltinData{core::BuiltinFn::kSin, CallParamType::kF32, "sin"},
+        BuiltinData{core::BuiltinFn::kSin, CallParamType::kF16, "sin"},
+        BuiltinData{core::BuiltinFn::kSinh, CallParamType::kF32, "sinh"},
+        BuiltinData{core::BuiltinFn::kSinh, CallParamType::kF16, "sinh"},
+        BuiltinData{core::BuiltinFn::kSmoothstep, CallParamType::kF32, "smoothstep"},
+        BuiltinData{core::BuiltinFn::kSmoothstep, CallParamType::kF16, "smoothstep"},
+        BuiltinData{core::BuiltinFn::kSqrt, CallParamType::kF32, "sqrt"},
+        BuiltinData{core::BuiltinFn::kSqrt, CallParamType::kF16, "sqrt"},
+        BuiltinData{core::BuiltinFn::kStep, CallParamType::kF32, "step"},
+        BuiltinData{core::BuiltinFn::kStep, CallParamType::kF16, "step"},
+        BuiltinData{core::BuiltinFn::kTan, CallParamType::kF32, "tan"},
+        BuiltinData{core::BuiltinFn::kTan, CallParamType::kF16, "tan"},
+        BuiltinData{core::BuiltinFn::kTanh, CallParamType::kF32, "tanh"},
+        BuiltinData{core::BuiltinFn::kTanh, CallParamType::kF16, "tanh"},
+        BuiltinData{core::BuiltinFn::kTrunc, CallParamType::kF32, "trunc"},
+        BuiltinData{core::BuiltinFn::kTrunc, CallParamType::kF16, "trunc"},
         /* Integer built-in */
-        BuiltinData{core::Function::kAbs, CallParamType::kU32, "abs"},
-        BuiltinData{core::Function::kClamp, CallParamType::kU32, "clamp"},
-        BuiltinData{core::Function::kCountLeadingZeros, CallParamType::kU32, "clz"},
-        BuiltinData{core::Function::kCountOneBits, CallParamType::kU32, "popcount"},
-        BuiltinData{core::Function::kCountTrailingZeros, CallParamType::kU32, "ctz"},
-        BuiltinData{core::Function::kExtractBits, CallParamType::kU32, "extract_bits"},
-        BuiltinData{core::Function::kInsertBits, CallParamType::kU32, "insert_bits"},
-        BuiltinData{core::Function::kMax, CallParamType::kU32, "max"},
-        BuiltinData{core::Function::kMin, CallParamType::kU32, "min"},
-        BuiltinData{core::Function::kReverseBits, CallParamType::kU32, "reverse_bits"},
-        BuiltinData{core::Function::kRound, CallParamType::kU32, "rint"},
+        BuiltinData{core::BuiltinFn::kAbs, CallParamType::kU32, "abs"},
+        BuiltinData{core::BuiltinFn::kClamp, CallParamType::kU32, "clamp"},
+        BuiltinData{core::BuiltinFn::kCountLeadingZeros, CallParamType::kU32, "clz"},
+        BuiltinData{core::BuiltinFn::kCountOneBits, CallParamType::kU32, "popcount"},
+        BuiltinData{core::BuiltinFn::kCountTrailingZeros, CallParamType::kU32, "ctz"},
+        BuiltinData{core::BuiltinFn::kExtractBits, CallParamType::kU32, "extract_bits"},
+        BuiltinData{core::BuiltinFn::kInsertBits, CallParamType::kU32, "insert_bits"},
+        BuiltinData{core::BuiltinFn::kMax, CallParamType::kU32, "max"},
+        BuiltinData{core::BuiltinFn::kMin, CallParamType::kU32, "min"},
+        BuiltinData{core::BuiltinFn::kReverseBits, CallParamType::kU32, "reverse_bits"},
+        BuiltinData{core::BuiltinFn::kRound, CallParamType::kU32, "rint"},
         /* Matrix built-in */
-        BuiltinData{core::Function::kDeterminant, CallParamType::kF32, "determinant"},
-        BuiltinData{core::Function::kTranspose, CallParamType::kF32, "transpose"},
+        BuiltinData{core::BuiltinFn::kDeterminant, CallParamType::kF32, "determinant"},
+        BuiltinData{core::BuiltinFn::kTranspose, CallParamType::kF32, "transpose"},
         /* Vector built-in */
-        BuiltinData{core::Function::kDot, CallParamType::kF32, "dot"},
+        BuiltinData{core::BuiltinFn::kDot, CallParamType::kF32, "dot"},
         /* Derivate built-in */
-        BuiltinData{core::Function::kDpdx, CallParamType::kF32, "dfdx"},
-        BuiltinData{core::Function::kDpdxCoarse, CallParamType::kF32, "dfdx"},
-        BuiltinData{core::Function::kDpdxFine, CallParamType::kF32, "dfdx"},
-        BuiltinData{core::Function::kDpdy, CallParamType::kF32, "dfdy"},
-        BuiltinData{core::Function::kDpdyCoarse, CallParamType::kF32, "dfdy"},
-        BuiltinData{core::Function::kDpdyFine, CallParamType::kF32, "dfdy"},
-        BuiltinData{core::Function::kFwidth, CallParamType::kF32, "fwidth"},
-        BuiltinData{core::Function::kFwidthCoarse, CallParamType::kF32, "fwidth"},
-        BuiltinData{core::Function::kFwidthFine, CallParamType::kF32, "fwidth"},
+        BuiltinData{core::BuiltinFn::kDpdx, CallParamType::kF32, "dfdx"},
+        BuiltinData{core::BuiltinFn::kDpdxCoarse, CallParamType::kF32, "dfdx"},
+        BuiltinData{core::BuiltinFn::kDpdxFine, CallParamType::kF32, "dfdx"},
+        BuiltinData{core::BuiltinFn::kDpdy, CallParamType::kF32, "dfdy"},
+        BuiltinData{core::BuiltinFn::kDpdyCoarse, CallParamType::kF32, "dfdy"},
+        BuiltinData{core::BuiltinFn::kDpdyFine, CallParamType::kF32, "dfdy"},
+        BuiltinData{core::BuiltinFn::kFwidth, CallParamType::kF32, "fwidth"},
+        BuiltinData{core::BuiltinFn::kFwidthCoarse, CallParamType::kF32, "fwidth"},
+        BuiltinData{core::BuiltinFn::kFwidthFine, CallParamType::kF32, "fwidth"},
         /* Data packing builtin */
-        BuiltinData{core::Function::kPack4X8Snorm, CallParamType::kF32, "pack_float_to_snorm4x8"},
-        BuiltinData{core::Function::kPack4X8Unorm, CallParamType::kF32, "pack_float_to_unorm4x8"},
-        BuiltinData{core::Function::kPack2X16Snorm, CallParamType::kF32, "pack_float_to_snorm2x16"},
-        BuiltinData{core::Function::kPack2X16Unorm, CallParamType::kF32, "pack_float_to_unorm2x16"},
+        BuiltinData{core::BuiltinFn::kPack4X8Snorm, CallParamType::kF32, "pack_float_to_snorm4x8"},
+        BuiltinData{core::BuiltinFn::kPack4X8Unorm, CallParamType::kF32, "pack_float_to_unorm4x8"},
+        BuiltinData{core::BuiltinFn::kPack2X16Snorm, CallParamType::kF32,
+                    "pack_float_to_snorm2x16"},
+        BuiltinData{core::BuiltinFn::kPack2X16Unorm, CallParamType::kF32,
+                    "pack_float_to_unorm2x16"},
         /* Data unpacking builtin */
-        BuiltinData{core::Function::kUnpack4X8Snorm, CallParamType::kU32,
+        BuiltinData{core::BuiltinFn::kUnpack4X8Snorm, CallParamType::kU32,
                     "unpack_snorm4x8_to_float"},
-        BuiltinData{core::Function::kUnpack4X8Unorm, CallParamType::kU32,
+        BuiltinData{core::BuiltinFn::kUnpack4X8Unorm, CallParamType::kU32,
                     "unpack_unorm4x8_to_float"},
-        BuiltinData{core::Function::kUnpack2X16Snorm, CallParamType::kU32,
+        BuiltinData{core::BuiltinFn::kUnpack2X16Snorm, CallParamType::kU32,
                     "unpack_snorm2x16_to_float"},
-        BuiltinData{core::Function::kUnpack2X16Unorm, CallParamType::kU32,
+        BuiltinData{core::BuiltinFn::kUnpack2X16Unorm, CallParamType::kU32,
                     "unpack_unorm2x16_to_float"}));
 
 TEST_F(MslASTPrinterTest, Builtin_Call) {
diff --git a/src/tint/lang/msl/writer/ast_printer/import_test.cc b/src/tint/lang/msl/writer/ast_printer/import_test.cc
index f77ddec..a3f501d 100644
--- a/src/tint/lang/msl/writer/ast_printer/import_test.cc
+++ b/src/tint/lang/msl/writer/ast_printer/import_test.cc
@@ -46,7 +46,7 @@
     ASSERT_NE(sem, nullptr);
     auto* target = sem->Target();
     ASSERT_NE(target, nullptr);
-    auto* builtin = target->As<sem::Builtin>();
+    auto* builtin = target->As<sem::BuiltinFn>();
     ASSERT_NE(builtin, nullptr);
 
     ASSERT_EQ(gen.generate_builtin_name(builtin), param.msl_name);
diff --git a/src/tint/lang/msl/writer/ast_raise/subgroup_ballot.cc b/src/tint/lang/msl/writer/ast_raise/subgroup_ballot.cc
index e15bf24..3ed8cba 100644
--- a/src/tint/lang/msl/writer/ast_raise/subgroup_ballot.cc
+++ b/src/tint/lang/msl/writer/ast_raise/subgroup_ballot.cc
@@ -65,8 +65,8 @@
             if (call) {
                 // If this is a call to a `subgroupBallot()` builtin, replace it with a call to the
                 // helper function and make a note of the function that we are in.
-                auto* builtin = call->Target()->As<sem::Builtin>();
-                if (builtin && builtin->Type() == core::Function::kSubgroupBallot) {
+                auto* builtin = call->Target()->As<sem::BuiltinFn>();
+                if (builtin && builtin->Fn() == core::BuiltinFn::kSubgroupBallot) {
                     ctx.Replace(call->Declaration(), b.Call(GetHelper()));
                     ballot_callers.Add(call->Stmt()->Function());
                     made_changes = true;
diff --git a/src/tint/lang/spirv/reader/ast_lower/atomics.cc b/src/tint/lang/spirv/reader/ast_lower/atomics.cc
index bd2aee4..c62df89 100644
--- a/src/tint/lang/spirv/reader/ast_lower/atomics.cc
+++ b/src/tint/lang/spirv/reader/ast_lower/atomics.cc
@@ -87,7 +87,7 @@
                     out_args[0] = b.AddressOf(out_args[0]);
 
                     // Replace all callsites of this stub to a call to the real builtin
-                    if (stub->builtin == core::Function::kAtomicCompareExchangeWeak) {
+                    if (stub->builtin == core::BuiltinFn::kAtomicCompareExchangeWeak) {
                         // atomicCompareExchangeWeak returns a struct, so insert a call to it above
                         // the current statement, and replace the current call with the struct's
                         // `old_value` member.
@@ -255,7 +255,7 @@
                 if (is_ref_to_atomic_var(load->Reference())) {
                     ctx.Replace(load->Reference()->Declaration(), [=] {
                         auto* expr = ctx.CloneWithoutTransform(load->Reference()->Declaration());
-                        return b.Call(core::str(core::Function::kAtomicLoad), b.AddressOf(expr));
+                        return b.Call(core::str(core::BuiltinFn::kAtomicLoad), b.AddressOf(expr));
                     });
                 }
             } else if (auto* assign = node->As<ast::AssignmentStatement>()) {
@@ -265,7 +265,7 @@
                         auto* lhs = ctx.CloneWithoutTransform(assign->lhs);
                         auto* rhs = ctx.CloneWithoutTransform(assign->rhs);
                         auto* call =
-                            b.Call(core::str(core::Function::kAtomicStore), b.AddressOf(lhs), rhs);
+                            b.Call(core::str(core::BuiltinFn::kAtomicStore), b.AddressOf(lhs), rhs);
                         return b.CallStmt(call);
                     });
                 }
@@ -277,7 +277,7 @@
 Atomics::Atomics() = default;
 Atomics::~Atomics() = default;
 
-Atomics::Stub::Stub(GenerationID pid, ast::NodeID nid, core::Function b)
+Atomics::Stub::Stub(GenerationID pid, ast::NodeID nid, core::BuiltinFn b)
     : Base(pid, nid, tint::Empty), builtin(b) {}
 Atomics::Stub::~Stub() = default;
 std::string Atomics::Stub::InternalName() const {
diff --git a/src/tint/lang/spirv/reader/ast_lower/atomics.h b/src/tint/lang/spirv/reader/ast_lower/atomics.h
index e349095..d1902f6 100644
--- a/src/tint/lang/spirv/reader/ast_lower/atomics.h
+++ b/src/tint/lang/spirv/reader/ast_lower/atomics.h
@@ -17,7 +17,7 @@
 
 #include <string>
 
-#include "src/tint/lang/core/function.h"
+#include "src/tint/lang/core/builtin_fn.h"
 #include "src/tint/lang/wgsl/ast/internal_attribute.h"
 #include "src/tint/lang/wgsl/ast/transform/transform.h"
 
@@ -41,7 +41,7 @@
         /// @param pid the identifier of the program that owns this node
         /// @param nid the unique node identifier
         /// @param builtin the atomic builtin this stub represents
-        Stub(GenerationID pid, ast::NodeID nid, core::Function builtin);
+        Stub(GenerationID pid, ast::NodeID nid, core::BuiltinFn builtin);
         /// Destructor
         ~Stub() override;
 
@@ -55,7 +55,7 @@
         const Stub* Clone(ast::CloneContext& ctx) const override;
 
         /// The type of the intrinsic
-        const core::Function builtin;
+        const core::BuiltinFn builtin;
     };
 
     /// @copydoc ast::transform::Transform::Apply
diff --git a/src/tint/lang/spirv/reader/ast_lower/atomics_test.cc b/src/tint/lang/spirv/reader/ast_lower/atomics_test.cc
index 8898c52..6f67a21 100644
--- a/src/tint/lang/spirv/reader/ast_lower/atomics_test.cc
+++ b/src/tint/lang/spirv/reader/ast_lower/atomics_test.cc
@@ -37,10 +37,11 @@
 
         auto& b = parser.builder();
 
-        core::Function two_params[] = {
-            core::Function::kAtomicExchange, core::Function::kAtomicAdd, core::Function::kAtomicSub,
-            core::Function::kAtomicMin,      core::Function::kAtomicMax, core::Function::kAtomicAnd,
-            core::Function::kAtomicOr,       core::Function::kAtomicXor,
+        core::BuiltinFn two_params[] = {
+            core::BuiltinFn::kAtomicExchange, core::BuiltinFn::kAtomicAdd,
+            core::BuiltinFn::kAtomicSub,      core::BuiltinFn::kAtomicMin,
+            core::BuiltinFn::kAtomicMax,      core::BuiltinFn::kAtomicAnd,
+            core::BuiltinFn::kAtomicOr,       core::BuiltinFn::kAtomicXor,
         };
         for (auto& a : two_params) {
             b.Func(std::string{"stub_"} + core::str(a) + "_u32",
@@ -79,7 +80,7 @@
                },
                tint::Vector{
                    b.ASTNodes().Create<Atomics::Stub>(b.ID(), b.AllocateNodeID(),
-                                                      core::Function::kAtomicLoad),
+                                                      core::BuiltinFn::kAtomicLoad),
                });
         b.Func("stub_atomicLoad_i32",
                tint::Vector{
@@ -91,7 +92,7 @@
                },
                tint::Vector{
                    b.ASTNodes().Create<Atomics::Stub>(b.ID(), b.AllocateNodeID(),
-                                                      core::Function::kAtomicLoad),
+                                                      core::BuiltinFn::kAtomicLoad),
                });
 
         b.Func("stub_atomicStore_u32",
@@ -102,7 +103,7 @@
                b.ty.void_(), tint::Empty,
                tint::Vector{
                    b.ASTNodes().Create<Atomics::Stub>(b.ID(), b.AllocateNodeID(),
-                                                      core::Function::kAtomicStore),
+                                                      core::BuiltinFn::kAtomicStore),
                });
         b.Func("stub_atomicStore_i32",
                tint::Vector{
@@ -112,7 +113,7 @@
                b.ty.void_(), tint::Empty,
                tint::Vector{
                    b.ASTNodes().Create<Atomics::Stub>(b.ID(), b.AllocateNodeID(),
-                                                      core::Function::kAtomicStore),
+                                                      core::BuiltinFn::kAtomicStore),
                });
 
         b.Func("stub_atomic_compare_exchange_weak_u32",
@@ -127,7 +128,7 @@
                },
                tint::Vector{
                    b.ASTNodes().Create<Atomics::Stub>(b.ID(), b.AllocateNodeID(),
-                                                      core::Function::kAtomicCompareExchangeWeak),
+                                                      core::BuiltinFn::kAtomicCompareExchangeWeak),
                });
         b.Func("stub_atomic_compare_exchange_weak_i32",
                tint::Vector{b.Param("p0", b.ty.i32()), b.Param("p1", b.ty.i32()),
@@ -138,7 +139,7 @@
                },
                tint::Vector{
                    b.ASTNodes().Create<Atomics::Stub>(b.ID(), b.AllocateNodeID(),
-                                                      core::Function::kAtomicCompareExchangeWeak),
+                                                      core::BuiltinFn::kAtomicCompareExchangeWeak),
                });
 
         // Keep this pointer alive after Transform() returns
diff --git a/src/tint/lang/spirv/reader/ast_parser/barrier_test.cc b/src/tint/lang/spirv/reader/ast_parser/barrier_test.cc
index 66247db..ff4191c 100644
--- a/src/tint/lang/spirv/reader/ast_parser/barrier_test.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/barrier_test.cc
@@ -71,9 +71,9 @@
     EXPECT_EQ(call->expr->args.Length(), 0u);
     auto* sem_call = program.Sem().Get<sem::Call>(call->expr);
     ASSERT_NE(sem_call, nullptr);
-    auto* builtin = sem_call->Target()->As<sem::Builtin>();
+    auto* builtin = sem_call->Target()->As<sem::BuiltinFn>();
     ASSERT_NE(builtin, nullptr);
-    EXPECT_EQ(builtin->Type(), core::Function::kWorkgroupBarrier);
+    EXPECT_EQ(builtin->Fn(), core::BuiltinFn::kWorkgroupBarrier);
 }
 
 TEST_F(SpirvASTParserTest, StorageBarrier) {
@@ -104,9 +104,9 @@
     EXPECT_EQ(call->expr->args.Length(), 0u);
     auto* sem_call = program.Sem().Get<sem::Call>(call->expr);
     ASSERT_NE(sem_call, nullptr);
-    auto* builtin = sem_call->Target()->As<sem::Builtin>();
+    auto* builtin = sem_call->Target()->As<sem::BuiltinFn>();
     ASSERT_NE(builtin, nullptr);
-    EXPECT_EQ(builtin->Type(), core::Function::kStorageBarrier);
+    EXPECT_EQ(builtin->Fn(), core::BuiltinFn::kStorageBarrier);
 }
 
 TEST_F(SpirvASTParserTest, TextureBarrier) {
@@ -137,9 +137,9 @@
     EXPECT_EQ(call->expr->args.Length(), 0u);
     auto* sem_call = program.Sem().Get<sem::Call>(call->expr);
     ASSERT_NE(sem_call, nullptr);
-    auto* builtin = sem_call->Target()->As<sem::Builtin>();
+    auto* builtin = sem_call->Target()->As<sem::BuiltinFn>();
     ASSERT_NE(builtin, nullptr);
-    EXPECT_EQ(builtin->Type(), core::Function::kTextureBarrier);
+    EXPECT_EQ(builtin->Fn(), core::BuiltinFn::kTextureBarrier);
 }
 
 TEST_F(SpirvASTParserTest, WorkgroupAndTextureAndStorageBarrier) {
@@ -173,9 +173,9 @@
         EXPECT_EQ(call->expr->args.Length(), 0u);
         auto* sem_call = program.Sem().Get<sem::Call>(call->expr);
         ASSERT_NE(sem_call, nullptr);
-        auto* builtin = sem_call->Target()->As<sem::Builtin>();
+        auto* builtin = sem_call->Target()->As<sem::BuiltinFn>();
         ASSERT_NE(builtin, nullptr);
-        EXPECT_EQ(builtin->Type(), core::Function::kWorkgroupBarrier);
+        EXPECT_EQ(builtin->Fn(), core::BuiltinFn::kWorkgroupBarrier);
     }
     {
         auto* call = helper->body->statements[1]->As<ast::CallStatement>();
@@ -183,9 +183,9 @@
         EXPECT_EQ(call->expr->args.Length(), 0u);
         auto* sem_call = program.Sem().Get<sem::Call>(call->expr);
         ASSERT_NE(sem_call, nullptr);
-        auto* builtin = sem_call->Target()->As<sem::Builtin>();
+        auto* builtin = sem_call->Target()->As<sem::BuiltinFn>();
         ASSERT_NE(builtin, nullptr);
-        EXPECT_EQ(builtin->Type(), core::Function::kStorageBarrier);
+        EXPECT_EQ(builtin->Fn(), core::BuiltinFn::kStorageBarrier);
     }
     {
         auto* call = helper->body->statements[2]->As<ast::CallStatement>();
@@ -193,9 +193,9 @@
         EXPECT_EQ(call->expr->args.Length(), 0u);
         auto* sem_call = program.Sem().Get<sem::Call>(call->expr);
         ASSERT_NE(sem_call, nullptr);
-        auto* builtin = sem_call->Target()->As<sem::Builtin>();
+        auto* builtin = sem_call->Target()->As<sem::BuiltinFn>();
         ASSERT_NE(builtin, nullptr);
-        EXPECT_EQ(builtin->Type(), core::Function::kTextureBarrier);
+        EXPECT_EQ(builtin->Fn(), core::BuiltinFn::kTextureBarrier);
     }
 }
 
diff --git a/src/tint/lang/spirv/reader/ast_parser/function.cc b/src/tint/lang/spirv/reader/ast_parser/function.cc
index 754fff5..311f9b24 100644
--- a/src/tint/lang/spirv/reader/ast_parser/function.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/function.cc
@@ -17,9 +17,9 @@
 #include <algorithm>
 #include <array>
 
+#include "src/tint/lang/core/builtin_fn.h"
 #include "src/tint/lang/core/builtin_value.h"
 #include "src/tint/lang/core/fluent_types.h"
-#include "src/tint/lang/core/function.h"
 #include "src/tint/lang/core/type/depth_texture.h"
 #include "src/tint/lang/core/type/sampled_texture.h"
 #include "src/tint/lang/core/type/texture_dimension.h"
@@ -456,42 +456,42 @@
 }
 
 // Returns the WGSL standard library function builtin for the
-// given instruction, or core::Function::kNone
-core::Function GetBuiltin(spv::Op opcode) {
+// given instruction, or core::BuiltinFn::kNone
+core::BuiltinFn GetBuiltin(spv::Op opcode) {
     switch (opcode) {
         case spv::Op::OpBitCount:
-            return core::Function::kCountOneBits;
+            return core::BuiltinFn::kCountOneBits;
         case spv::Op::OpBitFieldInsert:
-            return core::Function::kInsertBits;
+            return core::BuiltinFn::kInsertBits;
         case spv::Op::OpBitFieldSExtract:
         case spv::Op::OpBitFieldUExtract:
-            return core::Function::kExtractBits;
+            return core::BuiltinFn::kExtractBits;
         case spv::Op::OpBitReverse:
-            return core::Function::kReverseBits;
+            return core::BuiltinFn::kReverseBits;
         case spv::Op::OpDot:
-            return core::Function::kDot;
+            return core::BuiltinFn::kDot;
         case spv::Op::OpDPdx:
-            return core::Function::kDpdx;
+            return core::BuiltinFn::kDpdx;
         case spv::Op::OpDPdy:
-            return core::Function::kDpdy;
+            return core::BuiltinFn::kDpdy;
         case spv::Op::OpFwidth:
-            return core::Function::kFwidth;
+            return core::BuiltinFn::kFwidth;
         case spv::Op::OpDPdxFine:
-            return core::Function::kDpdxFine;
+            return core::BuiltinFn::kDpdxFine;
         case spv::Op::OpDPdyFine:
-            return core::Function::kDpdyFine;
+            return core::BuiltinFn::kDpdyFine;
         case spv::Op::OpFwidthFine:
-            return core::Function::kFwidthFine;
+            return core::BuiltinFn::kFwidthFine;
         case spv::Op::OpDPdxCoarse:
-            return core::Function::kDpdxCoarse;
+            return core::BuiltinFn::kDpdxCoarse;
         case spv::Op::OpDPdyCoarse:
-            return core::Function::kDpdyCoarse;
+            return core::BuiltinFn::kDpdyCoarse;
         case spv::Op::OpFwidthCoarse:
-            return core::Function::kFwidthCoarse;
+            return core::BuiltinFn::kFwidthCoarse;
         default:
             break;
     }
-    return core::Function::kNone;
+    return core::BuiltinFn::kNone;
 }
 
 // @param opcode a SPIR-V opcode
@@ -3819,11 +3819,11 @@
     }
 
     const auto builtin = GetBuiltin(op);
-    if (builtin != core::Function::kNone) {
+    if (builtin != core::BuiltinFn::kNone) {
         switch (builtin) {
-            case core::Function::kExtractBits:
+            case core::BuiltinFn::kExtractBits:
                 return MakeExtractBitsCall(inst);
-            case core::Function::kInsertBits:
+            case core::BuiltinFn::kInsertBits:
                 return MakeInsertBitsCall(inst);
             default:
                 return MakeBuiltinCall(inst);
@@ -5852,7 +5852,7 @@
 }
 
 bool FunctionEmitter::EmitAtomicOp(const spvtools::opt::Instruction& inst) {
-    auto emit_atomic = [&](core::Function builtin, std::initializer_list<TypedExpression> args) {
+    auto emit_atomic = [&](core::BuiltinFn builtin, std::initializer_list<TypedExpression> args) {
         // Split args into params and expressions
         ParameterList params;
         params.Reserve(args.size());
@@ -5911,38 +5911,38 @@
 
     switch (opcode(inst)) {
         case spv::Op::OpAtomicLoad:
-            return emit_atomic(core::Function::kAtomicLoad, {oper(/*ptr*/ 0)});
+            return emit_atomic(core::BuiltinFn::kAtomicLoad, {oper(/*ptr*/ 0)});
         case spv::Op::OpAtomicStore:
-            return emit_atomic(core::Function::kAtomicStore, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(core::BuiltinFn::kAtomicStore, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicExchange:
-            return emit_atomic(core::Function::kAtomicExchange,
+            return emit_atomic(core::BuiltinFn::kAtomicExchange,
                                {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicCompareExchange:
         case spv::Op::OpAtomicCompareExchangeWeak:
-            return emit_atomic(core::Function::kAtomicCompareExchangeWeak,
+            return emit_atomic(core::BuiltinFn::kAtomicCompareExchangeWeak,
                                {oper(/*ptr*/ 0), /*value*/ oper(5), /*comparator*/ oper(4)});
         case spv::Op::OpAtomicIIncrement:
-            return emit_atomic(core::Function::kAtomicAdd, {oper(/*ptr*/ 0), lit(1)});
+            return emit_atomic(core::BuiltinFn::kAtomicAdd, {oper(/*ptr*/ 0), lit(1)});
         case spv::Op::OpAtomicIDecrement:
-            return emit_atomic(core::Function::kAtomicSub, {oper(/*ptr*/ 0), lit(1)});
+            return emit_atomic(core::BuiltinFn::kAtomicSub, {oper(/*ptr*/ 0), lit(1)});
         case spv::Op::OpAtomicIAdd:
-            return emit_atomic(core::Function::kAtomicAdd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(core::BuiltinFn::kAtomicAdd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicISub:
-            return emit_atomic(core::Function::kAtomicSub, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(core::BuiltinFn::kAtomicSub, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicSMin:
-            return emit_atomic(core::Function::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(core::BuiltinFn::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicUMin:
-            return emit_atomic(core::Function::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(core::BuiltinFn::kAtomicMin, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicSMax:
-            return emit_atomic(core::Function::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(core::BuiltinFn::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicUMax:
-            return emit_atomic(core::Function::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(core::BuiltinFn::kAtomicMax, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicAnd:
-            return emit_atomic(core::Function::kAtomicAnd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(core::BuiltinFn::kAtomicAnd, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicOr:
-            return emit_atomic(core::Function::kAtomicOr, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(core::BuiltinFn::kAtomicOr, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicXor:
-            return emit_atomic(core::Function::kAtomicXor, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
+            return emit_atomic(core::BuiltinFn::kAtomicXor, {oper(/*ptr*/ 0), oper(/*value*/ 3)});
         case spv::Op::OpAtomicFlagTestAndSet:
         case spv::Op::OpAtomicFlagClear:
         case spv::Op::OpAtomicFMinEXT:
diff --git a/src/tint/lang/spirv/reader/ast_parser/namer.cc b/src/tint/lang/spirv/reader/ast_parser/namer.cc
index aaa1ba6..6039a55 100644
--- a/src/tint/lang/spirv/reader/ast_parser/namer.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/namer.cc
@@ -17,7 +17,7 @@
 #include <algorithm>
 #include <unordered_set>
 
-#include "src/tint/lang/core/function.h"
+#include "src/tint/lang/core/builtin_fn.h"
 #include "src/tint/utils/ice/ice.h"
 #include "src/tint/utils/text/string_stream.h"
 
@@ -176,7 +176,7 @@
     for (const auto* reserved : kWGSLReservedWords) {
         name_to_id_[std::string(reserved)] = 0;
     }
-    for (const auto* builtin_function : core::kFunctionStrings) {
+    for (const auto* builtin_function : core::kBuiltinFnStrings) {
         name_to_id_[std::string(builtin_function)] = 0;
     }
 }
diff --git a/src/tint/lang/spirv/reader/ast_parser/namer_test.cc b/src/tint/lang/spirv/reader/ast_parser/namer_test.cc
index f6af2c7..14ff1dc 100644
--- a/src/tint/lang/spirv/reader/ast_parser/namer_test.cc
+++ b/src/tint/lang/spirv/reader/ast_parser/namer_test.cc
@@ -15,7 +15,7 @@
 #include "src/tint/lang/spirv/reader/ast_parser/namer.h"
 
 #include "gmock/gmock.h"
-#include "src/tint/lang/core/function.h"
+#include "src/tint/lang/core/builtin_fn.h"
 #include "src/tint/utils/text/string_stream.h"
 
 namespace tint::spirv::reader::ast_parser {
@@ -408,7 +408,7 @@
 
 INSTANTIATE_TEST_SUITE_P(SpirvASTParserTest_BuiltinFunctions,
                          SpvNamerBuiltinFunctionTest,
-                         ::testing::ValuesIn(core::kFunctionStrings));
+                         ::testing::ValuesIn(core::kBuiltinFnStrings));
 
 }  // namespace
 }  // namespace tint::spirv::reader::ast_parser
diff --git a/src/tint/lang/spirv/writer/ast_printer/builder.cc b/src/tint/lang/spirv/writer/ast_printer/builder.cc
index 9756664..beb9b39 100644
--- a/src/tint/lang/spirv/writer/ast_printer/builder.cc
+++ b/src/tint/lang/spirv/writer/ast_printer/builder.cc
@@ -36,7 +36,7 @@
 #include "src/tint/lang/wgsl/ast/traverse_expressions.h"
 #include "src/tint/lang/wgsl/helpers/append_vector.h"
 #include "src/tint/lang/wgsl/helpers/check_supported_extensions.h"
-#include "src/tint/lang/wgsl/sem/builtin.h"
+#include "src/tint/lang/wgsl/sem/builtin_fn.h"
 #include "src/tint/lang/wgsl/sem/call.h"
 #include "src/tint/lang/wgsl/sem/function.h"
 #include "src/tint/lang/wgsl/sem/load.h"
@@ -92,25 +92,25 @@
     return type->As<core::type::Matrix>();
 }
 
-uint32_t builtin_to_glsl_method(const sem::Builtin* builtin) {
-    switch (builtin->Type()) {
-        case core::Function::kAcos:
+uint32_t builtin_to_glsl_method(const sem::BuiltinFn* builtin) {
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kAcos:
             return GLSLstd450Acos;
-        case core::Function::kAcosh:
+        case core::BuiltinFn::kAcosh:
             return GLSLstd450Acosh;
-        case core::Function::kAsin:
+        case core::BuiltinFn::kAsin:
             return GLSLstd450Asin;
-        case core::Function::kAsinh:
+        case core::BuiltinFn::kAsinh:
             return GLSLstd450Asinh;
-        case core::Function::kAtan:
+        case core::BuiltinFn::kAtan:
             return GLSLstd450Atan;
-        case core::Function::kAtan2:
+        case core::BuiltinFn::kAtan2:
             return GLSLstd450Atan2;
-        case core::Function::kAtanh:
+        case core::BuiltinFn::kAtanh:
             return GLSLstd450Atanh;
-        case core::Function::kCeil:
+        case core::BuiltinFn::kCeil:
             return GLSLstd450Ceil;
-        case core::Function::kClamp:
+        case core::BuiltinFn::kClamp:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 return GLSLstd450NClamp;
             } else if (builtin->ReturnType()->is_unsigned_integer_scalar_or_vector()) {
@@ -118,43 +118,43 @@
             } else {
                 return GLSLstd450SClamp;
             }
-        case core::Function::kCos:
+        case core::BuiltinFn::kCos:
             return GLSLstd450Cos;
-        case core::Function::kCosh:
+        case core::BuiltinFn::kCosh:
             return GLSLstd450Cosh;
-        case core::Function::kCross:
+        case core::BuiltinFn::kCross:
             return GLSLstd450Cross;
-        case core::Function::kDegrees:
+        case core::BuiltinFn::kDegrees:
             return GLSLstd450Degrees;
-        case core::Function::kDeterminant:
+        case core::BuiltinFn::kDeterminant:
             return GLSLstd450Determinant;
-        case core::Function::kDistance:
+        case core::BuiltinFn::kDistance:
             return GLSLstd450Distance;
-        case core::Function::kExp:
+        case core::BuiltinFn::kExp:
             return GLSLstd450Exp;
-        case core::Function::kExp2:
+        case core::BuiltinFn::kExp2:
             return GLSLstd450Exp2;
-        case core::Function::kFaceForward:
+        case core::BuiltinFn::kFaceForward:
             return GLSLstd450FaceForward;
-        case core::Function::kFloor:
+        case core::BuiltinFn::kFloor:
             return GLSLstd450Floor;
-        case core::Function::kFma:
+        case core::BuiltinFn::kFma:
             return GLSLstd450Fma;
-        case core::Function::kFract:
+        case core::BuiltinFn::kFract:
             return GLSLstd450Fract;
-        case core::Function::kFrexp:
+        case core::BuiltinFn::kFrexp:
             return GLSLstd450FrexpStruct;
-        case core::Function::kInverseSqrt:
+        case core::BuiltinFn::kInverseSqrt:
             return GLSLstd450InverseSqrt;
-        case core::Function::kLdexp:
+        case core::BuiltinFn::kLdexp:
             return GLSLstd450Ldexp;
-        case core::Function::kLength:
+        case core::BuiltinFn::kLength:
             return GLSLstd450Length;
-        case core::Function::kLog:
+        case core::BuiltinFn::kLog:
             return GLSLstd450Log;
-        case core::Function::kLog2:
+        case core::BuiltinFn::kLog2:
             return GLSLstd450Log2;
-        case core::Function::kMax:
+        case core::BuiltinFn::kMax:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 return GLSLstd450NMax;
             } else if (builtin->ReturnType()->is_unsigned_integer_scalar_or_vector()) {
@@ -162,7 +162,7 @@
             } else {
                 return GLSLstd450SMax;
             }
-        case core::Function::kMin:
+        case core::BuiltinFn::kMin:
             if (builtin->ReturnType()->is_float_scalar_or_vector()) {
                 return GLSLstd450NMin;
             } else if (builtin->ReturnType()->is_unsigned_integer_scalar_or_vector()) {
@@ -170,63 +170,63 @@
             } else {
                 return GLSLstd450SMin;
             }
-        case core::Function::kMix:
+        case core::BuiltinFn::kMix:
             return GLSLstd450FMix;
-        case core::Function::kModf:
+        case core::BuiltinFn::kModf:
             return GLSLstd450ModfStruct;
-        case core::Function::kNormalize:
+        case core::BuiltinFn::kNormalize:
             return GLSLstd450Normalize;
-        case core::Function::kPack4X8Snorm:
+        case core::BuiltinFn::kPack4X8Snorm:
             return GLSLstd450PackSnorm4x8;
-        case core::Function::kPack4X8Unorm:
+        case core::BuiltinFn::kPack4X8Unorm:
             return GLSLstd450PackUnorm4x8;
-        case core::Function::kPack2X16Snorm:
+        case core::BuiltinFn::kPack2X16Snorm:
             return GLSLstd450PackSnorm2x16;
-        case core::Function::kPack2X16Unorm:
+        case core::BuiltinFn::kPack2X16Unorm:
             return GLSLstd450PackUnorm2x16;
-        case core::Function::kPack2X16Float:
+        case core::BuiltinFn::kPack2X16Float:
             return GLSLstd450PackHalf2x16;
-        case core::Function::kPow:
+        case core::BuiltinFn::kPow:
             return GLSLstd450Pow;
-        case core::Function::kRadians:
+        case core::BuiltinFn::kRadians:
             return GLSLstd450Radians;
-        case core::Function::kReflect:
+        case core::BuiltinFn::kReflect:
             return GLSLstd450Reflect;
-        case core::Function::kRefract:
+        case core::BuiltinFn::kRefract:
             return GLSLstd450Refract;
-        case core::Function::kRound:
+        case core::BuiltinFn::kRound:
             return GLSLstd450RoundEven;
-        case core::Function::kSign:
+        case core::BuiltinFn::kSign:
             if (builtin->ReturnType()->is_signed_integer_scalar_or_vector()) {
                 return GLSLstd450SSign;
             } else {
                 return GLSLstd450FSign;
             }
-        case core::Function::kSin:
+        case core::BuiltinFn::kSin:
             return GLSLstd450Sin;
-        case core::Function::kSinh:
+        case core::BuiltinFn::kSinh:
             return GLSLstd450Sinh;
-        case core::Function::kSmoothstep:
+        case core::BuiltinFn::kSmoothstep:
             return GLSLstd450SmoothStep;
-        case core::Function::kSqrt:
+        case core::BuiltinFn::kSqrt:
             return GLSLstd450Sqrt;
-        case core::Function::kStep:
+        case core::BuiltinFn::kStep:
             return GLSLstd450Step;
-        case core::Function::kTan:
+        case core::BuiltinFn::kTan:
             return GLSLstd450Tan;
-        case core::Function::kTanh:
+        case core::BuiltinFn::kTanh:
             return GLSLstd450Tanh;
-        case core::Function::kTrunc:
+        case core::BuiltinFn::kTrunc:
             return GLSLstd450Trunc;
-        case core::Function::kUnpack4X8Snorm:
+        case core::BuiltinFn::kUnpack4X8Snorm:
             return GLSLstd450UnpackSnorm4x8;
-        case core::Function::kUnpack4X8Unorm:
+        case core::BuiltinFn::kUnpack4X8Unorm:
             return GLSLstd450UnpackUnorm4x8;
-        case core::Function::kUnpack2X16Snorm:
+        case core::BuiltinFn::kUnpack2X16Snorm:
             return GLSLstd450UnpackSnorm2x16;
-        case core::Function::kUnpack2X16Unorm:
+        case core::BuiltinFn::kUnpack2X16Unorm:
             return GLSLstd450UnpackUnorm2x16;
-        case core::Function::kUnpack2X16Float:
+        case core::BuiltinFn::kUnpack2X16Float:
             return GLSLstd450UnpackHalf2x16;
         default:
             break;
@@ -2213,7 +2213,7 @@
     return Switch(
         target,  //
         [&](const sem::Function* func) { return GenerateFunctionCall(call, func); },
-        [&](const sem::Builtin* builtin) { return GenerateBuiltinCall(call, builtin); },
+        [&](const sem::BuiltinFn* builtin) { return GenerateBuiltinCall(call, builtin); },
         [&](const sem::ValueConversion*) {
             return GenerateValueConstructorOrConversion(call, nullptr);
         },
@@ -2262,7 +2262,7 @@
     return result_id;
 }
 
-uint32_t Builder::GenerateBuiltinCall(const sem::Call* call, const sem::Builtin* builtin) {
+uint32_t Builder::GenerateBuiltinCall(const sem::Call* call, const sem::BuiltinFn* builtin) {
     auto result = result_op();
     auto result_id = std::get<uint32_t>(result);
 
@@ -2328,22 +2328,22 @@
         op = spv::Op::OpExtInst;
     };
 
-    switch (builtin->Type()) {
-        case core::Function::kAny:
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kAny:
             if (builtin->Parameters()[0]->Type()->Is<core::type::Bool>()) {
                 // any(v: bool) just resolves to v.
                 return get_arg_as_value_id(0);
             }
             op = spv::Op::OpAny;
             break;
-        case core::Function::kAll:
+        case core::BuiltinFn::kAll:
             if (builtin->Parameters()[0]->Type()->Is<core::type::Bool>()) {
                 // all(v: bool) just resolves to v.
                 return get_arg_as_value_id(0);
             }
             op = spv::Op::OpAll;
             break;
-        case core::Function::kArrayLength: {
+        case core::BuiltinFn::kArrayLength: {
             auto* address_of = call->Arguments()[0]->Declaration()->As<ast::UnaryOpExpression>();
             if (!address_of || address_of->op != core::UnaryOp::kAddressOf) {
                 TINT_ICE() << "arrayLength() expected pointer to member access, got " +
@@ -2380,10 +2380,10 @@
             }
             return result_id;
         }
-        case core::Function::kCountOneBits:
+        case core::BuiltinFn::kCountOneBits:
             op = spv::Op::OpBitCount;
             break;
-        case core::Function::kDot: {
+        case core::BuiltinFn::kDot: {
             op = spv::Op::OpDot;
             auto* vec_ty = builtin->Parameters()[0]->Type()->As<core::type::Vector>();
             if (vec_ty->type()->is_integer_scalar()) {
@@ -2424,42 +2424,42 @@
             }
             break;
         }
-        case core::Function::kDpdx:
+        case core::BuiltinFn::kDpdx:
             op = spv::Op::OpDPdx;
             break;
-        case core::Function::kDpdxCoarse:
+        case core::BuiltinFn::kDpdxCoarse:
             op = spv::Op::OpDPdxCoarse;
             break;
-        case core::Function::kDpdxFine:
+        case core::BuiltinFn::kDpdxFine:
             op = spv::Op::OpDPdxFine;
             break;
-        case core::Function::kDpdy:
+        case core::BuiltinFn::kDpdy:
             op = spv::Op::OpDPdy;
             break;
-        case core::Function::kDpdyCoarse:
+        case core::BuiltinFn::kDpdyCoarse:
             op = spv::Op::OpDPdyCoarse;
             break;
-        case core::Function::kDpdyFine:
+        case core::BuiltinFn::kDpdyFine:
             op = spv::Op::OpDPdyFine;
             break;
-        case core::Function::kExtractBits:
+        case core::BuiltinFn::kExtractBits:
             op = builtin->Parameters()[0]->Type()->is_unsigned_integer_scalar_or_vector()
                      ? spv::Op::OpBitFieldUExtract
                      : spv::Op::OpBitFieldSExtract;
             break;
-        case core::Function::kFwidth:
+        case core::BuiltinFn::kFwidth:
             op = spv::Op::OpFwidth;
             break;
-        case core::Function::kFwidthCoarse:
+        case core::BuiltinFn::kFwidthCoarse:
             op = spv::Op::OpFwidthCoarse;
             break;
-        case core::Function::kFwidthFine:
+        case core::BuiltinFn::kFwidthFine:
             op = spv::Op::OpFwidthFine;
             break;
-        case core::Function::kInsertBits:
+        case core::BuiltinFn::kInsertBits:
             op = spv::Op::OpBitFieldInsert;
             break;
-        case core::Function::kMix: {
+        case core::BuiltinFn::kMix: {
             auto std450 = Operand(GetGLSLstd450Import());
 
             auto a_id = get_arg_as_value_id(0);
@@ -2486,13 +2486,13 @@
             }
             return result_id;
         }
-        case core::Function::kQuantizeToF16:
+        case core::BuiltinFn::kQuantizeToF16:
             op = spv::Op::OpQuantizeToF16;
             break;
-        case core::Function::kReverseBits:
+        case core::BuiltinFn::kReverseBits:
             op = spv::Op::OpBitReverse;
             break;
-        case core::Function::kSelect: {
+        case core::BuiltinFn::kSelect: {
             // Note: Argument order is different in WGSL and SPIR-V
             auto cond_id = get_arg_as_value_id(2);
             auto true_id = get_arg_as_value_id(1);
@@ -2524,10 +2524,10 @@
             }
             return result_id;
         }
-        case core::Function::kTranspose:
+        case core::BuiltinFn::kTranspose:
             op = spv::Op::OpTranspose;
             break;
-        case core::Function::kAbs:
+        case core::BuiltinFn::kAbs:
             if (builtin->ReturnType()->is_unsigned_integer_scalar_or_vector()) {
                 // abs() only operates on *signed* integers.
                 // This is a no-op for unsigned integers.
@@ -2539,7 +2539,7 @@
                 glsl_std450(GLSLstd450SAbs);
             }
             break;
-        case core::Function::kDot4I8Packed: {
+        case core::BuiltinFn::kDot4I8Packed: {
             auto first_param_id = get_arg_as_value_id(0);
             auto second_param_id = get_arg_as_value_id(1);
             if (!push_function_inst(spv::Op::OpSDotKHR,
@@ -2551,7 +2551,7 @@
             }
             return result_id;
         }
-        case core::Function::kDot4U8Packed: {
+        case core::BuiltinFn::kDot4U8Packed: {
             auto first_param_id = get_arg_as_value_id(0);
             auto second_param_id = get_arg_as_value_id(1);
             if (!push_function_inst(spv::Op::OpUDotKHR,
@@ -2563,7 +2563,7 @@
             }
             return result_id;
         }
-        case core::Function::kSubgroupBallot: {
+        case core::BuiltinFn::kSubgroupBallot: {
             module_.PushCapability(SpvCapabilityGroupNonUniformBallot);
             if (!push_function_inst(
                     spv::Op::OpGroupNonUniformBallot,
@@ -2574,7 +2574,7 @@
             }
             return result_id;
         }
-        case core::Function::kSubgroupBroadcast: {
+        case core::BuiltinFn::kSubgroupBroadcast: {
             module_.PushCapability(SpvCapabilityGroupNonUniformBallot);
             auto first_param_id = get_arg_as_value_id(0);
             auto second_param_id = get_arg_as_value_id(1);
@@ -2619,7 +2619,7 @@
 }
 
 bool Builder::GenerateTextureBuiltin(const sem::Call* call,
-                                     const sem::Builtin* builtin,
+                                     const sem::BuiltinFn* builtin,
                                      Operand result_type,
                                      Operand result_id) {
     using Usage = core::ParameterUsage;
@@ -2777,8 +2777,8 @@
         return append_coords_to_spirv_params();
     };
 
-    switch (builtin->Type()) {
-        case core::Function::kTextureDimensions: {
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kTextureDimensions: {
             // Number of returned elements from OpImageQuerySize[Lod] may not match
             // those of textureDimensions().
             // This might be due to an extra vector scalar describing the number of
@@ -2823,7 +2823,7 @@
             }
             break;
         }
-        case core::Function::kTextureNumLayers: {
+        case core::BuiltinFn::kTextureNumLayers: {
             uint32_t spirv_dims = 0;
             switch (texture_type->dim()) {
                 default:
@@ -2853,19 +2853,19 @@
             }
             break;
         }
-        case core::Function::kTextureNumLevels: {
+        case core::BuiltinFn::kTextureNumLevels: {
             op = spv::Op::OpImageQueryLevels;
             append_result_type_and_id_to_spirv_params();
             spirv_params.emplace_back(gen_arg(Usage::kTexture));
             break;
         }
-        case core::Function::kTextureNumSamples: {
+        case core::BuiltinFn::kTextureNumSamples: {
             op = spv::Op::OpImageQuerySamples;
             append_result_type_and_id_to_spirv_params();
             spirv_params.emplace_back(gen_arg(Usage::kTexture));
             break;
         }
-        case core::Function::kTextureLoad: {
+        case core::BuiltinFn::kTextureLoad: {
             op = texture_type->Is<core::type::StorageTexture>() ? spv::Op::OpImageRead
                                                                 : spv::Op::OpImageFetch;
             append_result_type_and_id_to_spirv_params_for_read();
@@ -2885,7 +2885,7 @@
 
             break;
         }
-        case core::Function::kTextureStore: {
+        case core::BuiltinFn::kTextureStore: {
             op = spv::Op::OpImageWrite;
             spirv_params.emplace_back(gen_arg(Usage::kTexture));
             if (!append_coords_to_spirv_params()) {
@@ -2894,7 +2894,7 @@
             spirv_params.emplace_back(gen_arg(Usage::kValue));
             break;
         }
-        case core::Function::kTextureGather: {
+        case core::BuiltinFn::kTextureGather: {
             op = spv::Op::OpImageGather;
             append_result_type_and_id_to_spirv_params();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2908,7 +2908,7 @@
             }
             break;
         }
-        case core::Function::kTextureGatherCompare: {
+        case core::BuiltinFn::kTextureGatherCompare: {
             op = spv::Op::OpImageDrefGather;
             append_result_type_and_id_to_spirv_params();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2917,7 +2917,7 @@
             spirv_params.emplace_back(gen_arg(Usage::kDepthRef));
             break;
         }
-        case core::Function::kTextureSample: {
+        case core::BuiltinFn::kTextureSample: {
             op = spv::Op::OpImageSampleImplicitLod;
             append_result_type_and_id_to_spirv_params_for_read();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2925,7 +2925,7 @@
             }
             break;
         }
-        case core::Function::kTextureSampleBias: {
+        case core::BuiltinFn::kTextureSampleBias: {
             op = spv::Op::OpImageSampleImplicitLod;
             append_result_type_and_id_to_spirv_params_for_read();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2935,7 +2935,7 @@
                 ImageOperand{SpvImageOperandsBiasMask, gen_arg(Usage::kBias)});
             break;
         }
-        case core::Function::kTextureSampleLevel: {
+        case core::BuiltinFn::kTextureSampleLevel: {
             op = spv::Op::OpImageSampleExplicitLod;
             append_result_type_and_id_to_spirv_params_for_read();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2963,7 +2963,7 @@
             image_operands.emplace_back(ImageOperand{SpvImageOperandsLodMask, level});
             break;
         }
-        case core::Function::kTextureSampleGrad: {
+        case core::BuiltinFn::kTextureSampleGrad: {
             op = spv::Op::OpImageSampleExplicitLod;
             append_result_type_and_id_to_spirv_params_for_read();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2975,7 +2975,7 @@
                 ImageOperand{SpvImageOperandsGradMask, gen_arg(Usage::kDdy)});
             break;
         }
-        case core::Function::kTextureSampleCompare: {
+        case core::BuiltinFn::kTextureSampleCompare: {
             op = spv::Op::OpImageSampleDrefImplicitLod;
             append_result_type_and_id_to_spirv_params();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -2984,7 +2984,7 @@
             spirv_params.emplace_back(gen_arg(Usage::kDepthRef));
             break;
         }
-        case core::Function::kTextureSampleCompareLevel: {
+        case core::BuiltinFn::kTextureSampleCompareLevel: {
             op = spv::Op::OpImageSampleDrefExplicitLod;
             append_result_type_and_id_to_spirv_params();
             if (!append_image_and_coords_to_spirv_params()) {
@@ -3031,7 +3031,7 @@
     return post_emission();
 }
 
-bool Builder::GenerateControlBarrierBuiltin(const sem::Builtin* builtin) {
+bool Builder::GenerateControlBarrierBuiltin(const sem::BuiltinFn* builtin) {
     auto const op = spv::Op::OpControlBarrier;
     uint32_t execution = 0;
     uint32_t memory = 0;
@@ -3039,23 +3039,23 @@
 
     // TODO(crbug.com/tint/661): Combine sequential barriers to a single
     // instruction.
-    if (builtin->Type() == core::Function::kWorkgroupBarrier) {
+    if (builtin->Fn() == core::BuiltinFn::kWorkgroupBarrier) {
         execution = static_cast<uint32_t>(spv::Scope::Workgroup);
         memory = static_cast<uint32_t>(spv::Scope::Workgroup);
         semantics = static_cast<uint32_t>(spv::MemorySemanticsMask::AcquireRelease) |
                     static_cast<uint32_t>(spv::MemorySemanticsMask::WorkgroupMemory);
-    } else if (builtin->Type() == core::Function::kStorageBarrier) {
+    } else if (builtin->Fn() == core::BuiltinFn::kStorageBarrier) {
         execution = static_cast<uint32_t>(spv::Scope::Workgroup);
         memory = static_cast<uint32_t>(spv::Scope::Workgroup);
         semantics = static_cast<uint32_t>(spv::MemorySemanticsMask::AcquireRelease) |
                     static_cast<uint32_t>(spv::MemorySemanticsMask::UniformMemory);
-    } else if (builtin->Type() == core::Function::kTextureBarrier) {
+    } else if (builtin->Fn() == core::BuiltinFn::kTextureBarrier) {
         execution = static_cast<uint32_t>(spv::Scope::Workgroup);
         memory = static_cast<uint32_t>(spv::Scope::Workgroup);
         semantics = static_cast<uint32_t>(spv::MemorySemanticsMask::AcquireRelease) |
                     static_cast<uint32_t>(spv::MemorySemanticsMask::ImageMemory);
     } else {
-        TINT_ICE() << "unexpected barrier builtin type " << core::str(builtin->Type());
+        TINT_ICE() << "unexpected barrier builtin type " << core::str(builtin->Fn());
         return false;
     }
 
@@ -3074,7 +3074,7 @@
 }
 
 bool Builder::GenerateAtomicBuiltin(const sem::Call* call,
-                                    const sem::Builtin* builtin,
+                                    const sem::BuiltinFn* builtin,
                                     Operand result_type,
                                     Operand result_id) {
     auto is_value_signed = [&] { return builtin->Parameters()[1]->Type()->Is<core::type::I32>(); };
@@ -3124,8 +3124,8 @@
     Operand memory = Operand(memory_id);
     Operand semantics = Operand(semantics_id);
 
-    switch (builtin->Type()) {
-        case core::Function::kAtomicLoad:
+    switch (builtin->Fn()) {
+        case core::BuiltinFn::kAtomicLoad:
             return push_function_inst(spv::Op::OpAtomicLoad, {
                                                                  result_type,
                                                                  result_id,
@@ -3133,14 +3133,14 @@
                                                                  memory,
                                                                  semantics,
                                                              });
-        case core::Function::kAtomicStore:
+        case core::BuiltinFn::kAtomicStore:
             return push_function_inst(spv::Op::OpAtomicStore, {
                                                                   pointer,
                                                                   memory,
                                                                   semantics,
                                                                   value,
                                                               });
-        case core::Function::kAtomicAdd:
+        case core::BuiltinFn::kAtomicAdd:
             return push_function_inst(spv::Op::OpAtomicIAdd, {
                                                                  result_type,
                                                                  result_id,
@@ -3149,7 +3149,7 @@
                                                                  semantics,
                                                                  value,
                                                              });
-        case core::Function::kAtomicSub:
+        case core::BuiltinFn::kAtomicSub:
             return push_function_inst(spv::Op::OpAtomicISub, {
                                                                  result_type,
                                                                  result_id,
@@ -3158,7 +3158,7 @@
                                                                  semantics,
                                                                  value,
                                                              });
-        case core::Function::kAtomicMax:
+        case core::BuiltinFn::kAtomicMax:
             return push_function_inst(
                 is_value_signed() ? spv::Op::OpAtomicSMax : spv::Op::OpAtomicUMax, {
                                                                                        result_type,
@@ -3168,7 +3168,7 @@
                                                                                        semantics,
                                                                                        value,
                                                                                    });
-        case core::Function::kAtomicMin:
+        case core::BuiltinFn::kAtomicMin:
             return push_function_inst(
                 is_value_signed() ? spv::Op::OpAtomicSMin : spv::Op::OpAtomicUMin, {
                                                                                        result_type,
@@ -3178,7 +3178,7 @@
                                                                                        semantics,
                                                                                        value,
                                                                                    });
-        case core::Function::kAtomicAnd:
+        case core::BuiltinFn::kAtomicAnd:
             return push_function_inst(spv::Op::OpAtomicAnd, {
                                                                 result_type,
                                                                 result_id,
@@ -3187,7 +3187,7 @@
                                                                 semantics,
                                                                 value,
                                                             });
-        case core::Function::kAtomicOr:
+        case core::BuiltinFn::kAtomicOr:
             return push_function_inst(spv::Op::OpAtomicOr, {
                                                                result_type,
                                                                result_id,
@@ -3196,7 +3196,7 @@
                                                                semantics,
                                                                value,
                                                            });
-        case core::Function::kAtomicXor:
+        case core::BuiltinFn::kAtomicXor:
             return push_function_inst(spv::Op::OpAtomicXor, {
                                                                 result_type,
                                                                 result_id,
@@ -3205,7 +3205,7 @@
                                                                 semantics,
                                                                 value,
                                                             });
-        case core::Function::kAtomicExchange:
+        case core::BuiltinFn::kAtomicExchange:
             return push_function_inst(spv::Op::OpAtomicExchange, {
                                                                      result_type,
                                                                      result_id,
@@ -3214,7 +3214,7 @@
                                                                      semantics,
                                                                      value,
                                                                  });
-        case core::Function::kAtomicCompareExchangeWeak: {
+        case core::BuiltinFn::kAtomicCompareExchangeWeak: {
             auto comparator = GenerateExpression(call->Arguments()[1]);
             if (comparator == 0) {
                 return false;
@@ -3275,7 +3275,7 @@
                                                                      });
         }
         default:
-            TINT_UNREACHABLE() << "unhandled atomic builtin " << builtin->Type();
+            TINT_UNREACHABLE() << "unhandled atomic builtin " << builtin->Fn();
             return false;
     }
 }
diff --git a/src/tint/lang/spirv/writer/ast_printer/builder.h b/src/tint/lang/spirv/writer/ast_printer/builder.h
index c736697..ec5066e 100644
--- a/src/tint/lang/spirv/writer/ast_printer/builder.h
+++ b/src/tint/lang/spirv/writer/ast_printer/builder.h
@@ -40,7 +40,7 @@
 #include "src/tint/lang/wgsl/ast/unary_op_expression.h"
 #include "src/tint/lang/wgsl/ast/variable_decl_statement.h"
 #include "src/tint/lang/wgsl/program/program_builder.h"
-#include "src/tint/lang/wgsl/sem/builtin.h"
+#include "src/tint/lang/wgsl/sem/builtin_fn.h"
 #include "src/tint/utils/containers/scope_stack.h"
 
 // Forward declarations
@@ -296,7 +296,7 @@
     /// @param call the call expression
     /// @param builtin the builtin being called
     /// @returns the expression ID on success or 0 otherwise
-    uint32_t GenerateBuiltinCall(const sem::Call* call, const sem::Builtin* builtin);
+    uint32_t GenerateBuiltinCall(const sem::Call* call, const sem::BuiltinFn* builtin);
     /// Handles generating a value constructor or value conversion expression
     /// @param call the call expression
     /// @param var the variable that is being initialized. May be null.
@@ -311,13 +311,13 @@
     /// parameters
     /// @returns true on success
     bool GenerateTextureBuiltin(const sem::Call* call,
-                                const sem::Builtin* builtin,
+                                const sem::BuiltinFn* builtin,
                                 Operand result_type,
                                 Operand result_id);
     /// Generates a control barrier statement.
     /// @param builtin the semantic information for the barrier builtin call
     /// @returns true on success
-    bool GenerateControlBarrierBuiltin(const sem::Builtin* builtin);
+    bool GenerateControlBarrierBuiltin(const sem::BuiltinFn* builtin);
     /// Generates an atomic builtin call.
     /// @param call the call expression
     /// @param builtin the semantic information for the atomic builtin call
@@ -325,7 +325,7 @@
     /// @param result_id result identifier operand of the texture instruction
     /// @returns true on success
     bool GenerateAtomicBuiltin(const sem::Call* call,
-                               const sem::Builtin* builtin,
+                               const sem::BuiltinFn* builtin,
                                Operand result_type,
                                Operand result_id);
     /// Generates a sampled image
diff --git a/src/tint/lang/spirv/writer/atomic_builtin_test.cc b/src/tint/lang/spirv/writer/atomic_builtin_test.cc
index 5352fd1..2cbc65f 100644
--- a/src/tint/lang/spirv/writer/atomic_builtin_test.cc
+++ b/src/tint/lang/spirv/writer/atomic_builtin_test.cc
@@ -15,7 +15,7 @@
 #include "src/tint/lang/core/type/builtin_structs.h"
 #include "src/tint/lang/spirv/writer/common/helper_test.h"
 
-#include "src/tint/lang/core/function.h"
+#include "src/tint/lang/core/builtin_fn.h"
 
 using namespace tint::core::fluent_types;     // NOLINT
 using namespace tint::core::number_suffixes;  // NOLINT
@@ -34,7 +34,7 @@
 
     b.Append(func->Block(), [&] {
         auto* ptr = b.Let("ptr", var);
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicAdd, ptr, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicAdd, ptr, arg1);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -51,7 +51,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicAdd, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicAdd, var, arg1);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -68,7 +68,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicAnd, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicAnd, var, arg1);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -87,7 +87,8 @@
 
     b.Append(func->Block(), [&] {
         auto* result_ty = core::type::CreateAtomicCompareExchangeResult(ty, mod.symbols, ty.i32());
-        auto* result = b.Call(result_ty, core::Function::kAtomicCompareExchangeWeak, var, cmp, val);
+        auto* result =
+            b.Call(result_ty, core::BuiltinFn::kAtomicCompareExchangeWeak, var, cmp, val);
         auto* original = b.Access(ty.i32(), result, 0_u);
         b.Return(func, original);
         mod.SetName(result, "result");
@@ -109,7 +110,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicExchange, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicExchange, var, arg1);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -124,7 +125,7 @@
     auto* func = b.Function("foo", ty.i32());
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicLoad, var);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicLoad, var);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -141,7 +142,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicMax, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicMax, var, arg1);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -158,7 +159,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kAtomicMax, var, arg1);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kAtomicMax, var, arg1);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -175,7 +176,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicMin, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicMin, var, arg1);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -192,7 +193,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kAtomicMin, var, arg1);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kAtomicMin, var, arg1);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -209,7 +210,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicOr, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicOr, var, arg1);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -226,7 +227,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        b.Call(ty.void_(), core::Function::kAtomicStore, var, arg1);
+        b.Call(ty.void_(), core::BuiltinFn::kAtomicStore, var, arg1);
         b.Return(func);
     });
 
@@ -242,7 +243,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicSub, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicSub, var, arg1);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -259,7 +260,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicXor, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicXor, var, arg1);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
diff --git a/src/tint/lang/spirv/writer/builtin_test.cc b/src/tint/lang/spirv/writer/builtin_test.cc
index 7e51a65..3b84143 100644
--- a/src/tint/lang/spirv/writer/builtin_test.cc
+++ b/src/tint/lang/spirv/writer/builtin_test.cc
@@ -14,7 +14,7 @@
 
 #include "src/tint/lang/spirv/writer/common/helper_test.h"
 
-#include "src/tint/lang/core/function.h"
+#include "src/tint/lang/core/builtin_fn.h"
 #include "src/tint/lang/core/type/builtin_structs.h"
 
 using namespace tint::core::number_suffixes;  // NOLINT
@@ -28,7 +28,7 @@
     /// The element type to test.
     TestElementType type;
     /// The builtin function.
-    enum core::Function function;
+    enum core::BuiltinFn function;
     /// The expected SPIR-V instruction string.
     std::string spirv_inst;
 };
@@ -62,83 +62,83 @@
 INSTANTIATE_TEST_SUITE_P(
     SpirvWriterTest,
     Builtin_1arg,
-    testing::Values(BuiltinTestCase{kI32, core::Function::kAbs, "SAbs"},
-                    BuiltinTestCase{kF32, core::Function::kAbs, "FAbs"},
-                    BuiltinTestCase{kF16, core::Function::kAbs, "FAbs"},
-                    BuiltinTestCase{kF32, core::Function::kAcos, "Acos"},
-                    BuiltinTestCase{kF16, core::Function::kAcos, "Acos"},
-                    BuiltinTestCase{kF32, core::Function::kAsinh, "Asinh"},
-                    BuiltinTestCase{kF16, core::Function::kAsinh, "Asinh"},
-                    BuiltinTestCase{kF32, core::Function::kAcos, "Acos"},
-                    BuiltinTestCase{kF16, core::Function::kAcos, "Acos"},
-                    BuiltinTestCase{kF32, core::Function::kAsinh, "Asinh"},
-                    BuiltinTestCase{kF16, core::Function::kAsinh, "Asinh"},
-                    BuiltinTestCase{kF32, core::Function::kAtan, "Atan"},
-                    BuiltinTestCase{kF16, core::Function::kAtan, "Atan"},
-                    BuiltinTestCase{kF32, core::Function::kAtanh, "Atanh"},
-                    BuiltinTestCase{kF16, core::Function::kAtanh, "Atanh"},
-                    BuiltinTestCase{kF32, core::Function::kCeil, "Ceil"},
-                    BuiltinTestCase{kF16, core::Function::kCeil, "Ceil"},
-                    BuiltinTestCase{kF32, core::Function::kCos, "Cos"},
-                    BuiltinTestCase{kF16, core::Function::kCos, "Cos"},
-                    BuiltinTestCase{kI32, core::Function::kCountOneBits, "OpBitCount"},
-                    BuiltinTestCase{kU32, core::Function::kCountOneBits, "OpBitCount"},
-                    BuiltinTestCase{kF32, core::Function::kDpdx, "OpDPdx"},
-                    BuiltinTestCase{kF32, core::Function::kDpdxCoarse, "OpDPdxCoarse"},
-                    BuiltinTestCase{kF32, core::Function::kDpdxFine, "OpDPdxFine"},
-                    BuiltinTestCase{kF32, core::Function::kDpdy, "OpDPdy"},
-                    BuiltinTestCase{kF32, core::Function::kDpdyCoarse, "OpDPdyCoarse"},
-                    BuiltinTestCase{kF32, core::Function::kDpdyFine, "OpDPdyFine"},
-                    BuiltinTestCase{kF32, core::Function::kDegrees, "Degrees"},
-                    BuiltinTestCase{kF16, core::Function::kDegrees, "Degrees"},
-                    BuiltinTestCase{kF32, core::Function::kExp, "Exp"},
-                    BuiltinTestCase{kF16, core::Function::kExp, "Exp"},
-                    BuiltinTestCase{kF32, core::Function::kExp2, "Exp2"},
-                    BuiltinTestCase{kF16, core::Function::kExp2, "Exp2"},
-                    BuiltinTestCase{kF32, core::Function::kFloor, "Floor"},
-                    BuiltinTestCase{kF16, core::Function::kFloor, "Floor"},
-                    BuiltinTestCase{kF32, core::Function::kFract, "Fract"},
-                    BuiltinTestCase{kF16, core::Function::kFract, "Fract"},
-                    BuiltinTestCase{kF32, core::Function::kFwidth, "OpFwidth"},
-                    BuiltinTestCase{kF32, core::Function::kFwidthCoarse, "OpFwidthCoarse"},
-                    BuiltinTestCase{kF32, core::Function::kFwidthFine, "OpFwidthFine"},
-                    BuiltinTestCase{kF32, core::Function::kInverseSqrt, "InverseSqrt"},
-                    BuiltinTestCase{kF16, core::Function::kInverseSqrt, "InverseSqrt"},
-                    BuiltinTestCase{kF32, core::Function::kLog, "Log"},
-                    BuiltinTestCase{kF16, core::Function::kLog, "Log"},
-                    BuiltinTestCase{kF32, core::Function::kLog2, "Log2"},
-                    BuiltinTestCase{kF16, core::Function::kLog2, "Log2"},
-                    BuiltinTestCase{kF32, core::Function::kQuantizeToF16, "OpQuantizeToF16"},
-                    BuiltinTestCase{kF32, core::Function::kRadians, "Radians"},
-                    BuiltinTestCase{kF16, core::Function::kRadians, "Radians"},
-                    BuiltinTestCase{kI32, core::Function::kReverseBits, "OpBitReverse"},
-                    BuiltinTestCase{kU32, core::Function::kReverseBits, "OpBitReverse"},
-                    BuiltinTestCase{kF32, core::Function::kRound, "RoundEven"},
-                    BuiltinTestCase{kF16, core::Function::kRound, "RoundEven"},
-                    BuiltinTestCase{kF32, core::Function::kSign, "FSign"},
-                    BuiltinTestCase{kF16, core::Function::kSign, "FSign"},
-                    BuiltinTestCase{kI32, core::Function::kSign, "SSign"},
-                    BuiltinTestCase{kF32, core::Function::kSin, "Sin"},
-                    BuiltinTestCase{kF16, core::Function::kSin, "Sin"},
-                    BuiltinTestCase{kF32, core::Function::kSqrt, "Sqrt"},
-                    BuiltinTestCase{kF16, core::Function::kSqrt, "Sqrt"},
-                    BuiltinTestCase{kF32, core::Function::kTan, "Tan"},
-                    BuiltinTestCase{kF16, core::Function::kTan, "Tan"},
-                    BuiltinTestCase{kF32, core::Function::kTrunc, "Trunc"},
-                    BuiltinTestCase{kF16, core::Function::kTrunc, "Trunc"},
-                    BuiltinTestCase{kF32, core::Function::kCosh, "Cosh"},
-                    BuiltinTestCase{kF16, core::Function::kCosh, "Cosh"},
-                    BuiltinTestCase{kF32, core::Function::kSinh, "Sinh"},
-                    BuiltinTestCase{kF16, core::Function::kSinh, "Sinh"},
-                    BuiltinTestCase{kF32, core::Function::kTanh, "Tanh"},
-                    BuiltinTestCase{kF16, core::Function::kTanh, "Tanh"}));
+    testing::Values(BuiltinTestCase{kI32, core::BuiltinFn::kAbs, "SAbs"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kAbs, "FAbs"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kAbs, "FAbs"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kAcos, "Acos"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kAcos, "Acos"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kAsinh, "Asinh"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kAsinh, "Asinh"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kAcos, "Acos"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kAcos, "Acos"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kAsinh, "Asinh"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kAsinh, "Asinh"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kAtan, "Atan"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kAtan, "Atan"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kAtanh, "Atanh"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kAtanh, "Atanh"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kCeil, "Ceil"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kCeil, "Ceil"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kCos, "Cos"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kCos, "Cos"},
+                    BuiltinTestCase{kI32, core::BuiltinFn::kCountOneBits, "OpBitCount"},
+                    BuiltinTestCase{kU32, core::BuiltinFn::kCountOneBits, "OpBitCount"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kDpdx, "OpDPdx"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kDpdxCoarse, "OpDPdxCoarse"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kDpdxFine, "OpDPdxFine"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kDpdy, "OpDPdy"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kDpdyCoarse, "OpDPdyCoarse"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kDpdyFine, "OpDPdyFine"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kDegrees, "Degrees"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kDegrees, "Degrees"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kExp, "Exp"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kExp, "Exp"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kExp2, "Exp2"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kExp2, "Exp2"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kFloor, "Floor"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kFloor, "Floor"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kFract, "Fract"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kFract, "Fract"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kFwidth, "OpFwidth"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kFwidthCoarse, "OpFwidthCoarse"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kFwidthFine, "OpFwidthFine"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kInverseSqrt, "InverseSqrt"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kInverseSqrt, "InverseSqrt"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kLog, "Log"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kLog, "Log"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kLog2, "Log2"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kLog2, "Log2"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kQuantizeToF16, "OpQuantizeToF16"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kRadians, "Radians"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kRadians, "Radians"},
+                    BuiltinTestCase{kI32, core::BuiltinFn::kReverseBits, "OpBitReverse"},
+                    BuiltinTestCase{kU32, core::BuiltinFn::kReverseBits, "OpBitReverse"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kRound, "RoundEven"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kRound, "RoundEven"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kSign, "FSign"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kSign, "FSign"},
+                    BuiltinTestCase{kI32, core::BuiltinFn::kSign, "SSign"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kSin, "Sin"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kSin, "Sin"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kSqrt, "Sqrt"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kSqrt, "Sqrt"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kTan, "Tan"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kTan, "Tan"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kTrunc, "Trunc"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kTrunc, "Trunc"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kCosh, "Cosh"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kCosh, "Cosh"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kSinh, "Sinh"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kSinh, "Sinh"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kTanh, "Tanh"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kTanh, "Tanh"}));
 
 // Test that abs of an unsigned value just folds away.
 TEST_F(SpirvWriterTest, Builtin_Abs_u32) {
     auto* func = b.Function("foo", MakeScalarType(kU32));
     b.Append(func->Block(), [&] {
         auto* arg = MakeScalarValue(kU32);
-        auto* result = b.Call(MakeScalarType(kU32), core::Function::kAbs, arg);
+        auto* result = b.Call(MakeScalarType(kU32), core::BuiltinFn::kAbs, arg);
         b.Return(func, result);
         mod.SetName(arg, "arg");
     });
@@ -156,7 +156,7 @@
     auto* func = b.Function("foo", MakeVectorType(kU32));
     b.Append(func->Block(), [&] {
         auto* arg = MakeVectorValue(kU32);
-        auto* result = b.Call(MakeVectorType(kU32), core::Function::kAbs, arg);
+        auto* result = b.Call(MakeVectorType(kU32), core::BuiltinFn::kAbs, arg);
         b.Return(func, result);
         mod.SetName(arg, "arg");
     });
@@ -176,7 +176,7 @@
     auto* func = b.Function("foo", ty.bool_());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.bool_(), core::Function::kAll, arg);
+        auto* result = b.Call(ty.bool_(), core::BuiltinFn::kAll, arg);
         b.Return(func, result);
     });
 
@@ -189,7 +189,7 @@
     auto* func = b.Function("foo", ty.bool_());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.bool_(), core::Function::kAll, arg);
+        auto* result = b.Call(ty.bool_(), core::BuiltinFn::kAll, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -204,7 +204,7 @@
     auto* func = b.Function("foo", ty.bool_());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.bool_(), core::Function::kAny, arg);
+        auto* result = b.Call(ty.bool_(), core::BuiltinFn::kAny, arg);
         b.Return(func, result);
     });
 
@@ -217,7 +217,7 @@
     auto* func = b.Function("foo", ty.bool_());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.bool_(), core::Function::kAny, arg);
+        auto* result = b.Call(ty.bool_(), core::BuiltinFn::kAny, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -231,7 +231,7 @@
     auto* func = b.Function("foo", ty.f32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f32(), core::Function::kDeterminant, arg);
+        auto* result = b.Call(ty.f32(), core::BuiltinFn::kDeterminant, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -245,7 +245,7 @@
     auto* func = b.Function("foo", ty.f16());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f16(), core::Function::kDeterminant, arg);
+        auto* result = b.Call(ty.f16(), core::BuiltinFn::kDeterminant, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -260,7 +260,7 @@
     auto* func = b.Function("foo", str);
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(str, core::Function::kFrexp, arg);
+        auto* result = b.Call(str, core::BuiltinFn::kFrexp, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -275,7 +275,7 @@
     auto* func = b.Function("foo", str);
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(str, core::Function::kFrexp, arg);
+        auto* result = b.Call(str, core::BuiltinFn::kFrexp, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -290,7 +290,7 @@
     auto* func = b.Function("foo", str);
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(str, core::Function::kFrexp, arg);
+        auto* result = b.Call(str, core::BuiltinFn::kFrexp, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -305,7 +305,7 @@
     auto* func = b.Function("foo", str);
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(str, core::Function::kFrexp, arg);
+        auto* result = b.Call(str, core::BuiltinFn::kFrexp, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -319,7 +319,7 @@
     auto* func = b.Function("foo", ty.f32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f32(), core::Function::kLength, arg);
+        auto* result = b.Call(ty.f32(), core::BuiltinFn::kLength, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -334,7 +334,7 @@
     auto* func = b.Function("foo", str);
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(str, core::Function::kModf, arg);
+        auto* result = b.Call(str, core::BuiltinFn::kModf, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -349,7 +349,7 @@
     auto* func = b.Function("foo", str);
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(str, core::Function::kModf, arg);
+        auto* result = b.Call(str, core::BuiltinFn::kModf, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -364,7 +364,7 @@
     auto* func = b.Function("foo", str);
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(str, core::Function::kModf, arg);
+        auto* result = b.Call(str, core::BuiltinFn::kModf, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -379,7 +379,7 @@
     auto* func = b.Function("foo", str);
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(str, core::Function::kModf, arg);
+        auto* result = b.Call(str, core::BuiltinFn::kModf, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -393,7 +393,7 @@
     auto* func = b.Function("foo", ty.vec4<f32>());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kNormalize, arg);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kNormalize, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -407,7 +407,7 @@
     auto* func = b.Function("foo", ty.mat3x2<f32>());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.mat3x2<f32>(), core::Function::kTranspose, arg);
+        auto* result = b.Call(ty.mat3x2<f32>(), core::BuiltinFn::kTranspose, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -421,7 +421,7 @@
     auto* func = b.Function("foo", ty.mat4x4<f32>());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.mat4x4<f32>(), core::Function::kTranspose, arg);
+        auto* result = b.Call(ty.mat4x4<f32>(), core::BuiltinFn::kTranspose, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -435,7 +435,7 @@
     auto* func = b.Function("foo", ty.mat3x4<f16>());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.mat3x4<f16>(), core::Function::kTranspose, arg);
+        auto* result = b.Call(ty.mat3x4<f16>(), core::BuiltinFn::kTranspose, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -449,7 +449,7 @@
     auto* func = b.Function("foo", ty.mat2x2<f16>());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.mat2x2<f16>(), core::Function::kTranspose, arg);
+        auto* result = b.Call(ty.mat2x2<f16>(), core::BuiltinFn::kTranspose, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -463,7 +463,7 @@
     auto* func = b.Function("foo", ty.u32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kPack2X16Float, arg);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kPack2X16Float, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -477,7 +477,7 @@
     auto* func = b.Function("foo", ty.u32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kPack2X16Snorm, arg);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kPack2X16Snorm, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -491,7 +491,7 @@
     auto* func = b.Function("foo", ty.u32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kPack2X16Unorm, arg);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kPack2X16Unorm, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -505,7 +505,7 @@
     auto* func = b.Function("foo", ty.u32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kPack4X8Snorm, arg);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kPack4X8Snorm, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -519,7 +519,7 @@
     auto* func = b.Function("foo", ty.u32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kPack4X8Unorm, arg);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kPack4X8Unorm, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -533,7 +533,7 @@
     auto* func = b.Function("foo", ty.vec2<f32>());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec2<f32>(), core::Function::kUnpack2X16Float, arg);
+        auto* result = b.Call(ty.vec2<f32>(), core::BuiltinFn::kUnpack2X16Float, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -547,7 +547,7 @@
     auto* func = b.Function("foo", ty.vec2<f32>());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec2<f32>(), core::Function::kUnpack2X16Snorm, arg);
+        auto* result = b.Call(ty.vec2<f32>(), core::BuiltinFn::kUnpack2X16Snorm, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -561,7 +561,7 @@
     auto* func = b.Function("foo", ty.vec2<f32>());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec2<f32>(), core::Function::kUnpack2X16Unorm, arg);
+        auto* result = b.Call(ty.vec2<f32>(), core::BuiltinFn::kUnpack2X16Unorm, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -575,7 +575,7 @@
     auto* func = b.Function("foo", ty.vec4<f32>());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kUnpack4X8Snorm, arg);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kUnpack4X8Snorm, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -589,7 +589,7 @@
     auto* func = b.Function("foo", ty.vec4<f32>());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kUnpack4X8Unorm, arg);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kUnpack4X8Unorm, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -603,7 +603,7 @@
     auto* func = b.Function("foo", ty.u32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kCountLeadingZeros, arg);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kCountLeadingZeros, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -640,7 +640,7 @@
     auto* func = b.Function("foo", ty.i32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kCountLeadingZeros, arg);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kCountLeadingZeros, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -679,7 +679,7 @@
     auto* func = b.Function("foo", ty.vec2<u32>());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec2<u32>(), core::Function::kCountLeadingZeros, arg);
+        auto* result = b.Call(ty.vec2<u32>(), core::BuiltinFn::kCountLeadingZeros, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -727,7 +727,7 @@
     auto* func = b.Function("foo", ty.u32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kCountTrailingZeros, arg);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kCountTrailingZeros, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -768,7 +768,7 @@
     auto* func = b.Function("foo", ty.i32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kCountTrailingZeros, arg);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kCountTrailingZeros, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -811,7 +811,7 @@
     auto* func = b.Function("foo", ty.vec2<u32>());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec2<u32>(), core::Function::kCountTrailingZeros, arg);
+        auto* result = b.Call(ty.vec2<u32>(), core::BuiltinFn::kCountTrailingZeros, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -862,7 +862,7 @@
     auto* func = b.Function("foo", ty.u32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kFirstLeadingBit, arg);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kFirstLeadingBit, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -902,7 +902,7 @@
     auto* func = b.Function("foo", ty.i32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kFirstLeadingBit, arg);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kFirstLeadingBit, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -947,7 +947,7 @@
     auto* func = b.Function("foo", ty.vec2<u32>());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec2<u32>(), core::Function::kFirstLeadingBit, arg);
+        auto* result = b.Call(ty.vec2<u32>(), core::BuiltinFn::kFirstLeadingBit, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -998,7 +998,7 @@
     auto* func = b.Function("foo", ty.u32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kFirstTrailingBit, arg);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kFirstTrailingBit, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1038,7 +1038,7 @@
     auto* func = b.Function("foo", ty.i32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kFirstTrailingBit, arg);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kFirstTrailingBit, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1080,7 +1080,7 @@
     auto* func = b.Function("foo", ty.vec2<u32>());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec2<u32>(), core::Function::kFirstTrailingBit, arg);
+        auto* result = b.Call(ty.vec2<u32>(), core::BuiltinFn::kFirstTrailingBit, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1131,7 +1131,7 @@
     auto* func = b.Function("foo", ty.f32());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f32(), core::Function::kSaturate, arg);
+        auto* result = b.Call(ty.f32(), core::BuiltinFn::kSaturate, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1145,7 +1145,7 @@
     auto* func = b.Function("foo", ty.vec4<f16>());
     func->SetParams({arg});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f16>(), core::Function::kSaturate, arg);
+        auto* result = b.Call(ty.vec4<f16>(), core::BuiltinFn::kSaturate, arg);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1188,17 +1188,17 @@
 }
 INSTANTIATE_TEST_SUITE_P(SpirvWriterTest,
                          Builtin_2arg,
-                         testing::Values(BuiltinTestCase{kF32, core::Function::kAtan2, "Atan2"},
-                                         BuiltinTestCase{kF32, core::Function::kMax, "FMax"},
-                                         BuiltinTestCase{kI32, core::Function::kMax, "SMax"},
-                                         BuiltinTestCase{kU32, core::Function::kMax, "UMax"},
-                                         BuiltinTestCase{kF32, core::Function::kMin, "FMin"},
-                                         BuiltinTestCase{kI32, core::Function::kMin, "SMin"},
-                                         BuiltinTestCase{kU32, core::Function::kMin, "UMin"},
-                                         BuiltinTestCase{kF32, core::Function::kPow, "Pow"},
-                                         BuiltinTestCase{kF16, core::Function::kPow, "Pow"},
-                                         BuiltinTestCase{kF32, core::Function::kStep, "Step"},
-                                         BuiltinTestCase{kF16, core::Function::kStep, "Step"}));
+                         testing::Values(BuiltinTestCase{kF32, core::BuiltinFn::kAtan2, "Atan2"},
+                                         BuiltinTestCase{kF32, core::BuiltinFn::kMax, "FMax"},
+                                         BuiltinTestCase{kI32, core::BuiltinFn::kMax, "SMax"},
+                                         BuiltinTestCase{kU32, core::BuiltinFn::kMax, "UMax"},
+                                         BuiltinTestCase{kF32, core::BuiltinFn::kMin, "FMin"},
+                                         BuiltinTestCase{kI32, core::BuiltinFn::kMin, "SMin"},
+                                         BuiltinTestCase{kU32, core::BuiltinFn::kMin, "UMin"},
+                                         BuiltinTestCase{kF32, core::BuiltinFn::kPow, "Pow"},
+                                         BuiltinTestCase{kF16, core::BuiltinFn::kPow, "Pow"},
+                                         BuiltinTestCase{kF32, core::BuiltinFn::kStep, "Step"},
+                                         BuiltinTestCase{kF16, core::BuiltinFn::kStep, "Step"}));
 
 TEST_F(SpirvWriterTest, Builtin_Cross_vec3f) {
     auto* arg1 = b.FunctionParam("arg1", ty.vec3<f32>());
@@ -1206,7 +1206,7 @@
     auto* func = b.Function("foo", ty.vec3<f32>());
     func->SetParams({arg1, arg2});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec3<f32>(), core::Function::kCross, arg1, arg2);
+        auto* result = b.Call(ty.vec3<f32>(), core::BuiltinFn::kCross, arg1, arg2);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1221,7 +1221,7 @@
     auto* func = b.Function("foo", MakeScalarType(kF32));
     func->SetParams({arg1, arg2});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(MakeScalarType(kF32), core::Function::kDistance, arg1, arg2);
+        auto* result = b.Call(MakeScalarType(kF32), core::BuiltinFn::kDistance, arg1, arg2);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1236,7 +1236,7 @@
     auto* func = b.Function("foo", MakeScalarType(kF16));
     func->SetParams({arg1, arg2});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(MakeScalarType(kF16), core::Function::kDistance, arg1, arg2);
+        auto* result = b.Call(MakeScalarType(kF16), core::BuiltinFn::kDistance, arg1, arg2);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1251,7 +1251,7 @@
     auto* func = b.Function("foo", ty.f32());
     func->SetParams({arg1, arg2});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f32(), core::Function::kDot, arg1, arg2);
+        auto* result = b.Call(ty.f32(), core::BuiltinFn::kDot, arg1, arg2);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1266,7 +1266,7 @@
     auto* func = b.Function("foo", ty.i32());
     func->SetParams({arg1, arg2});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kDot, arg1, arg2);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kDot, arg1, arg2);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1289,7 +1289,7 @@
     auto* func = b.Function("foo", ty.u32());
     func->SetParams({arg1, arg2});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kDot, arg1, arg2);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kDot, arg1, arg2);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1320,7 +1320,7 @@
     auto* func = b.Function("foo", ty.f32());
     func->SetParams({arg1, arg2});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f32(), core::Function::kLdexp, arg1, arg2);
+        auto* result = b.Call(ty.f32(), core::BuiltinFn::kLdexp, arg1, arg2);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1335,7 +1335,7 @@
     auto* func = b.Function("foo", ty.f16());
     func->SetParams({arg1, arg2});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f16(), core::Function::kLdexp, arg1, arg2);
+        auto* result = b.Call(ty.f16(), core::BuiltinFn::kLdexp, arg1, arg2);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1350,7 +1350,7 @@
     auto* func = b.Function("foo", ty.vec2<f32>());
     func->SetParams({arg1, arg2});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec2<f32>(), core::Function::kLdexp, arg1, arg2);
+        auto* result = b.Call(ty.vec2<f32>(), core::BuiltinFn::kLdexp, arg1, arg2);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1365,7 +1365,7 @@
     auto* func = b.Function("foo", ty.vec3<f16>());
     func->SetParams({arg1, arg2});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec3<f16>(), core::Function::kLdexp, arg1, arg2);
+        auto* result = b.Call(ty.vec3<f16>(), core::BuiltinFn::kLdexp, arg1, arg2);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1380,7 +1380,7 @@
     auto* func = b.Function("foo", ty.vec3<f32>());
     func->SetParams({arg1, arg2});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec3<f32>(), core::Function::kReflect, arg1, arg2);
+        auto* result = b.Call(ty.vec3<f32>(), core::BuiltinFn::kReflect, arg1, arg2);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1395,7 +1395,7 @@
     auto* func = b.Function("foo", ty.vec4<f16>());
     func->SetParams({arg1, arg2});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f16>(), core::Function::kReflect, arg1, arg2);
+        auto* result = b.Call(ty.vec4<f16>(), core::BuiltinFn::kReflect, arg1, arg2);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1435,15 +1435,15 @@
 INSTANTIATE_TEST_SUITE_P(
     SpirvWriterTest,
     Builtin_3arg,
-    testing::Values(BuiltinTestCase{kF32, core::Function::kClamp, "NClamp"},
-                    BuiltinTestCase{kI32, core::Function::kClamp, "SClamp"},
-                    BuiltinTestCase{kU32, core::Function::kClamp, "UClamp"},
-                    BuiltinTestCase{kF32, core::Function::kFma, "Fma"},
-                    BuiltinTestCase{kF16, core::Function::kFma, "Fma"},
-                    BuiltinTestCase{kF32, core::Function::kMix, "Mix"},
-                    BuiltinTestCase{kF16, core::Function::kMix, "Mix"},
-                    BuiltinTestCase{kF32, core::Function::kSmoothstep, "SmoothStep"},
-                    BuiltinTestCase{kF16, core::Function::kSmoothstep, "SmoothStep"}));
+    testing::Values(BuiltinTestCase{kF32, core::BuiltinFn::kClamp, "NClamp"},
+                    BuiltinTestCase{kI32, core::BuiltinFn::kClamp, "SClamp"},
+                    BuiltinTestCase{kU32, core::BuiltinFn::kClamp, "UClamp"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kFma, "Fma"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kFma, "Fma"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kMix, "Mix"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kMix, "Mix"},
+                    BuiltinTestCase{kF32, core::BuiltinFn::kSmoothstep, "SmoothStep"},
+                    BuiltinTestCase{kF16, core::BuiltinFn::kSmoothstep, "SmoothStep"}));
 
 TEST_F(SpirvWriterTest, Builtin_ExtractBits_Scalar_I32) {
     auto* arg = b.FunctionParam("arg", ty.i32());
@@ -1453,7 +1453,7 @@
     func->SetParams({arg, offset, count});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kExtractBits, arg, offset, count);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kExtractBits, arg, offset, count);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1470,7 +1470,7 @@
     func->SetParams({arg, offset, count});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kExtractBits, arg, offset, count);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kExtractBits, arg, offset, count);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1487,7 +1487,7 @@
     func->SetParams({arg, offset, count});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<i32>(), core::Function::kExtractBits, arg, offset, count);
+        auto* result = b.Call(ty.vec4<i32>(), core::BuiltinFn::kExtractBits, arg, offset, count);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1504,7 +1504,7 @@
     func->SetParams({arg, offset, count});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec2<u32>(), core::Function::kExtractBits, arg, offset, count);
+        auto* result = b.Call(ty.vec2<u32>(), core::BuiltinFn::kExtractBits, arg, offset, count);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1522,7 +1522,7 @@
     func->SetParams({arg, newbits, offset, count});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kInsertBits, arg, newbits, offset, count);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kInsertBits, arg, newbits, offset, count);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1540,7 +1540,7 @@
     func->SetParams({arg, newbits, offset, count});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kInsertBits, arg, newbits, offset, count);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kInsertBits, arg, newbits, offset, count);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1559,7 +1559,7 @@
 
     b.Append(func->Block(), [&] {
         auto* result =
-            b.Call(ty.vec4<i32>(), core::Function::kInsertBits, arg, newbits, offset, count);
+            b.Call(ty.vec4<i32>(), core::BuiltinFn::kInsertBits, arg, newbits, offset, count);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1578,7 +1578,7 @@
 
     b.Append(func->Block(), [&] {
         auto* result =
-            b.Call(ty.vec2<u32>(), core::Function::kInsertBits, arg, newbits, offset, count);
+            b.Call(ty.vec2<u32>(), core::BuiltinFn::kInsertBits, arg, newbits, offset, count);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1594,7 +1594,7 @@
     auto* func = b.Function("foo", ty.vec3<f32>());
     func->SetParams({arg1, arg2, arg3});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec3<f32>(), core::Function::kFaceForward, arg1, arg2, arg3);
+        auto* result = b.Call(ty.vec3<f32>(), core::BuiltinFn::kFaceForward, arg1, arg2, arg3);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1610,7 +1610,7 @@
     auto* func = b.Function("foo", ty.vec4<f16>());
     func->SetParams({arg1, arg2, arg3});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f16>(), core::Function::kFaceForward, arg1, arg2, arg3);
+        auto* result = b.Call(ty.vec4<f16>(), core::BuiltinFn::kFaceForward, arg1, arg2, arg3);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1627,7 +1627,7 @@
     func->SetParams({arg1, arg2, factor});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kMix, arg1, arg2, factor);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kMix, arg1, arg2, factor);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1645,7 +1645,7 @@
     func->SetParams({arg1, arg2, factor});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kMix, arg1, arg2, factor);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kMix, arg1, arg2, factor);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1662,7 +1662,7 @@
     func->SetParams({arg1, arg2, i});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kRefract, arg1, arg2, i);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kRefract, arg1, arg2, i);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1679,7 +1679,7 @@
     func->SetParams({arg1, arg2, i});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f16>(), core::Function::kRefract, arg1, arg2, i);
+        auto* result = b.Call(ty.vec4<f16>(), core::BuiltinFn::kRefract, arg1, arg2, i);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1696,7 +1696,7 @@
     func->SetParams({argf, argt, cond});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kSelect, argf, argt, cond);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kSelect, argf, argt, cond);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1713,7 +1713,7 @@
     func->SetParams({argf, argt, cond});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<i32>(), core::Function::kSelect, argf, argt, cond);
+        auto* result = b.Call(ty.vec4<i32>(), core::BuiltinFn::kSelect, argf, argt, cond);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1730,7 +1730,7 @@
     func->SetParams({argf, argt, cond});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<i32>(), core::Function::kSelect, argf, argt, cond);
+        auto* result = b.Call(ty.vec4<i32>(), core::BuiltinFn::kSelect, argf, argt, cond);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1743,7 +1743,7 @@
 TEST_F(SpirvWriterTest, Builtin_StorageBarrier) {
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        b.Call(ty.void_(), core::Function::kStorageBarrier);
+        b.Call(ty.void_(), core::BuiltinFn::kStorageBarrier);
         b.Return(func);
     });
 
@@ -1754,7 +1754,7 @@
 TEST_F(SpirvWriterTest, Builtin_TextureBarrier) {
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        b.Call(ty.void_(), core::Function::kTextureBarrier);
+        b.Call(ty.void_(), core::BuiltinFn::kTextureBarrier);
         b.Return(func);
     });
 
@@ -1765,7 +1765,7 @@
 TEST_F(SpirvWriterTest, Builtin_WorkgroupBarrier) {
     auto* func = b.Function("foo", ty.void_());
     b.Append(func->Block(), [&] {
-        b.Call(ty.void_(), core::Function::kWorkgroupBarrier);
+        b.Call(ty.void_(), core::BuiltinFn::kWorkgroupBarrier);
         b.Return(func);
     });
 
@@ -1776,7 +1776,7 @@
 TEST_F(SpirvWriterTest, Builtin_SubgroupBallot) {
     auto* func = b.Function("foo", ty.vec4<u32>());
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<u32>(), core::Function::kSubgroupBallot);
+        auto* result = b.Call(ty.vec4<u32>(), core::BuiltinFn::kSubgroupBallot);
         mod.SetName(result, "result");
         b.Return(func, result);
     });
@@ -1789,7 +1789,7 @@
 TEST_F(SpirvWriterTest, Builtin_SubgroupBroadcastValueF32) {
     auto* func = b.Function("foo", ty.f32());
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f32(), core::Function::kSubgroupBroadcast, 1_f, 0_u);
+        auto* result = b.Call(ty.f32(), core::BuiltinFn::kSubgroupBroadcast, 1_f, 0_u);
         mod.SetName(result, "result");
         b.Return(func, result);
     });
@@ -1802,7 +1802,7 @@
 TEST_F(SpirvWriterTest, Builtin_SubgroupBroadcastValueI32) {
     auto* func = b.Function("foo", ty.i32());
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kSubgroupBroadcast, 1_i, 0_u);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kSubgroupBroadcast, 1_i, 0_u);
         mod.SetName(result, "result");
         b.Return(func, result);
     });
@@ -1815,7 +1815,7 @@
 TEST_F(SpirvWriterTest, Builtin_SubgroupBroadcastValueU32) {
     auto* func = b.Function("foo", ty.u32());
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kSubgroupBroadcast, 1_u, 0_u);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kSubgroupBroadcast, 1_u, 0_u);
         mod.SetName(result, "result");
         b.Return(func, result);
     });
@@ -1833,7 +1833,7 @@
     auto* func = b.Function("foo", ty.u32());
     b.Append(func->Block(), [&] {
         auto* ptr = b.Let("ptr", var);
-        auto* result = b.Call(ty.u32(), core::Function::kArrayLength, ptr);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, ptr);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1857,7 +1857,7 @@
     auto* func = b.Function("foo", ty.u32());
     b.Append(func->Block(), [&] {
         auto* ptr = b.Let("ptr", b.Access(ty.ptr(storage, arr), var, 2_u));
-        auto* result = b.Call(ty.u32(), core::Function::kArrayLength, ptr);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, ptr);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
diff --git a/src/tint/lang/spirv/writer/printer/printer.cc b/src/tint/lang/spirv/writer/printer/printer.cc
index d5b2d92..33da5de 100644
--- a/src/tint/lang/spirv/writer/printer/printer.cc
+++ b/src/tint/lang/spirv/writer/printer/printer.cc
@@ -1140,13 +1140,13 @@
 void Printer::EmitCoreBuiltinCall(core::ir::CoreBuiltinCall* builtin) {
     auto* result_ty = builtin->Result()->Type();
 
-    if (builtin->Func() == core::Function::kAbs &&
+    if (builtin->Func() == core::BuiltinFn::kAbs &&
         result_ty->is_unsigned_integer_scalar_or_vector()) {
         // abs() is a no-op for unsigned integers.
         values_.Add(builtin->Result(), Value(builtin->Args()[0]));
         return;
     }
-    if ((builtin->Func() == core::Function::kAll || builtin->Func() == core::Function::kAny) &&
+    if ((builtin->Func() == core::BuiltinFn::kAll || builtin->Func() == core::BuiltinFn::kAny) &&
         builtin->Args()[0]->Type()->Is<core::type::Bool>()) {
         // all() and any() are passthroughs for scalar arguments.
         values_.Add(builtin->Result(), Value(builtin->Args()[0]));
@@ -1173,41 +1173,41 @@
 
     // Determine the opcode.
     switch (builtin->Func()) {
-        case core::Function::kAbs:
+        case core::BuiltinFn::kAbs:
             if (result_ty->is_float_scalar_or_vector()) {
                 glsl_ext_inst(GLSLstd450FAbs);
             } else if (result_ty->is_signed_integer_scalar_or_vector()) {
                 glsl_ext_inst(GLSLstd450SAbs);
             }
             break;
-        case core::Function::kAll:
+        case core::BuiltinFn::kAll:
             op = spv::Op::OpAll;
             break;
-        case core::Function::kAny:
+        case core::BuiltinFn::kAny:
             op = spv::Op::OpAny;
             break;
-        case core::Function::kAcos:
+        case core::BuiltinFn::kAcos:
             glsl_ext_inst(GLSLstd450Acos);
             break;
-        case core::Function::kAcosh:
+        case core::BuiltinFn::kAcosh:
             glsl_ext_inst(GLSLstd450Acosh);
             break;
-        case core::Function::kAsin:
+        case core::BuiltinFn::kAsin:
             glsl_ext_inst(GLSLstd450Asin);
             break;
-        case core::Function::kAsinh:
+        case core::BuiltinFn::kAsinh:
             glsl_ext_inst(GLSLstd450Asinh);
             break;
-        case core::Function::kAtan:
+        case core::BuiltinFn::kAtan:
             glsl_ext_inst(GLSLstd450Atan);
             break;
-        case core::Function::kAtan2:
+        case core::BuiltinFn::kAtan2:
             glsl_ext_inst(GLSLstd450Atan2);
             break;
-        case core::Function::kAtanh:
+        case core::BuiltinFn::kAtanh:
             glsl_ext_inst(GLSLstd450Atanh);
             break;
-        case core::Function::kClamp:
+        case core::BuiltinFn::kClamp:
             if (result_ty->is_float_scalar_or_vector()) {
                 glsl_ext_inst(GLSLstd450NClamp);
             } else if (result_ty->is_unsigned_integer_scalar_or_vector()) {
@@ -1216,107 +1216,107 @@
                 glsl_ext_inst(GLSLstd450SClamp);
             }
             break;
-        case core::Function::kCeil:
+        case core::BuiltinFn::kCeil:
             glsl_ext_inst(GLSLstd450Ceil);
             break;
-        case core::Function::kCos:
+        case core::BuiltinFn::kCos:
             glsl_ext_inst(GLSLstd450Cos);
             break;
-        case core::Function::kCosh:
+        case core::BuiltinFn::kCosh:
             glsl_ext_inst(GLSLstd450Cosh);
             break;
-        case core::Function::kCountOneBits:
+        case core::BuiltinFn::kCountOneBits:
             op = spv::Op::OpBitCount;
             break;
-        case core::Function::kCross:
+        case core::BuiltinFn::kCross:
             glsl_ext_inst(GLSLstd450Cross);
             break;
-        case core::Function::kDegrees:
+        case core::BuiltinFn::kDegrees:
             glsl_ext_inst(GLSLstd450Degrees);
             break;
-        case core::Function::kDeterminant:
+        case core::BuiltinFn::kDeterminant:
             glsl_ext_inst(GLSLstd450Determinant);
             break;
-        case core::Function::kDistance:
+        case core::BuiltinFn::kDistance:
             glsl_ext_inst(GLSLstd450Distance);
             break;
-        case core::Function::kDpdx:
+        case core::BuiltinFn::kDpdx:
             op = spv::Op::OpDPdx;
             break;
-        case core::Function::kDpdxCoarse:
+        case core::BuiltinFn::kDpdxCoarse:
             module_.PushCapability(SpvCapabilityDerivativeControl);
             op = spv::Op::OpDPdxCoarse;
             break;
-        case core::Function::kDpdxFine:
+        case core::BuiltinFn::kDpdxFine:
             module_.PushCapability(SpvCapabilityDerivativeControl);
             op = spv::Op::OpDPdxFine;
             break;
-        case core::Function::kDpdy:
+        case core::BuiltinFn::kDpdy:
             op = spv::Op::OpDPdy;
             break;
-        case core::Function::kDpdyCoarse:
+        case core::BuiltinFn::kDpdyCoarse:
             module_.PushCapability(SpvCapabilityDerivativeControl);
             op = spv::Op::OpDPdyCoarse;
             break;
-        case core::Function::kDpdyFine:
+        case core::BuiltinFn::kDpdyFine:
             module_.PushCapability(SpvCapabilityDerivativeControl);
             op = spv::Op::OpDPdyFine;
             break;
-        case core::Function::kExp:
+        case core::BuiltinFn::kExp:
             glsl_ext_inst(GLSLstd450Exp);
             break;
-        case core::Function::kExp2:
+        case core::BuiltinFn::kExp2:
             glsl_ext_inst(GLSLstd450Exp2);
             break;
-        case core::Function::kExtractBits:
+        case core::BuiltinFn::kExtractBits:
             op = result_ty->is_signed_integer_scalar_or_vector() ? spv::Op::OpBitFieldSExtract
                                                                  : spv::Op::OpBitFieldUExtract;
             break;
-        case core::Function::kFaceForward:
+        case core::BuiltinFn::kFaceForward:
             glsl_ext_inst(GLSLstd450FaceForward);
             break;
-        case core::Function::kFloor:
+        case core::BuiltinFn::kFloor:
             glsl_ext_inst(GLSLstd450Floor);
             break;
-        case core::Function::kFma:
+        case core::BuiltinFn::kFma:
             glsl_ext_inst(GLSLstd450Fma);
             break;
-        case core::Function::kFract:
+        case core::BuiltinFn::kFract:
             glsl_ext_inst(GLSLstd450Fract);
             break;
-        case core::Function::kFrexp:
+        case core::BuiltinFn::kFrexp:
             glsl_ext_inst(GLSLstd450FrexpStruct);
             break;
-        case core::Function::kFwidth:
+        case core::BuiltinFn::kFwidth:
             op = spv::Op::OpFwidth;
             break;
-        case core::Function::kFwidthCoarse:
+        case core::BuiltinFn::kFwidthCoarse:
             module_.PushCapability(SpvCapabilityDerivativeControl);
             op = spv::Op::OpFwidthCoarse;
             break;
-        case core::Function::kFwidthFine:
+        case core::BuiltinFn::kFwidthFine:
             module_.PushCapability(SpvCapabilityDerivativeControl);
             op = spv::Op::OpFwidthFine;
             break;
-        case core::Function::kInsertBits:
+        case core::BuiltinFn::kInsertBits:
             op = spv::Op::OpBitFieldInsert;
             break;
-        case core::Function::kInverseSqrt:
+        case core::BuiltinFn::kInverseSqrt:
             glsl_ext_inst(GLSLstd450InverseSqrt);
             break;
-        case core::Function::kLdexp:
+        case core::BuiltinFn::kLdexp:
             glsl_ext_inst(GLSLstd450Ldexp);
             break;
-        case core::Function::kLength:
+        case core::BuiltinFn::kLength:
             glsl_ext_inst(GLSLstd450Length);
             break;
-        case core::Function::kLog:
+        case core::BuiltinFn::kLog:
             glsl_ext_inst(GLSLstd450Log);
             break;
-        case core::Function::kLog2:
+        case core::BuiltinFn::kLog2:
             glsl_ext_inst(GLSLstd450Log2);
             break;
-        case core::Function::kMax:
+        case core::BuiltinFn::kMax:
             if (result_ty->is_float_scalar_or_vector()) {
                 glsl_ext_inst(GLSLstd450FMax);
             } else if (result_ty->is_signed_integer_scalar_or_vector()) {
@@ -1325,7 +1325,7 @@
                 glsl_ext_inst(GLSLstd450UMax);
             }
             break;
-        case core::Function::kMin:
+        case core::BuiltinFn::kMin:
             if (result_ty->is_float_scalar_or_vector()) {
                 glsl_ext_inst(GLSLstd450FMin);
             } else if (result_ty->is_signed_integer_scalar_or_vector()) {
@@ -1334,74 +1334,74 @@
                 glsl_ext_inst(GLSLstd450UMin);
             }
             break;
-        case core::Function::kMix:
+        case core::BuiltinFn::kMix:
             glsl_ext_inst(GLSLstd450FMix);
             break;
-        case core::Function::kModf:
+        case core::BuiltinFn::kModf:
             glsl_ext_inst(GLSLstd450ModfStruct);
             break;
-        case core::Function::kNormalize:
+        case core::BuiltinFn::kNormalize:
             glsl_ext_inst(GLSLstd450Normalize);
             break;
-        case core::Function::kPack2X16Float:
+        case core::BuiltinFn::kPack2X16Float:
             glsl_ext_inst(GLSLstd450PackHalf2x16);
             break;
-        case core::Function::kPack2X16Snorm:
+        case core::BuiltinFn::kPack2X16Snorm:
             glsl_ext_inst(GLSLstd450PackSnorm2x16);
             break;
-        case core::Function::kPack2X16Unorm:
+        case core::BuiltinFn::kPack2X16Unorm:
             glsl_ext_inst(GLSLstd450PackUnorm2x16);
             break;
-        case core::Function::kPack4X8Snorm:
+        case core::BuiltinFn::kPack4X8Snorm:
             glsl_ext_inst(GLSLstd450PackSnorm4x8);
             break;
-        case core::Function::kPack4X8Unorm:
+        case core::BuiltinFn::kPack4X8Unorm:
             glsl_ext_inst(GLSLstd450PackUnorm4x8);
             break;
-        case core::Function::kPow:
+        case core::BuiltinFn::kPow:
             glsl_ext_inst(GLSLstd450Pow);
             break;
-        case core::Function::kQuantizeToF16:
+        case core::BuiltinFn::kQuantizeToF16:
             op = spv::Op::OpQuantizeToF16;
             break;
-        case core::Function::kRadians:
+        case core::BuiltinFn::kRadians:
             glsl_ext_inst(GLSLstd450Radians);
             break;
-        case core::Function::kReflect:
+        case core::BuiltinFn::kReflect:
             glsl_ext_inst(GLSLstd450Reflect);
             break;
-        case core::Function::kRefract:
+        case core::BuiltinFn::kRefract:
             glsl_ext_inst(GLSLstd450Refract);
             break;
-        case core::Function::kReverseBits:
+        case core::BuiltinFn::kReverseBits:
             op = spv::Op::OpBitReverse;
             break;
-        case core::Function::kRound:
+        case core::BuiltinFn::kRound:
             glsl_ext_inst(GLSLstd450RoundEven);
             break;
-        case core::Function::kSign:
+        case core::BuiltinFn::kSign:
             if (result_ty->is_float_scalar_or_vector()) {
                 glsl_ext_inst(GLSLstd450FSign);
             } else if (result_ty->is_signed_integer_scalar_or_vector()) {
                 glsl_ext_inst(GLSLstd450SSign);
             }
             break;
-        case core::Function::kSin:
+        case core::BuiltinFn::kSin:
             glsl_ext_inst(GLSLstd450Sin);
             break;
-        case core::Function::kSinh:
+        case core::BuiltinFn::kSinh:
             glsl_ext_inst(GLSLstd450Sinh);
             break;
-        case core::Function::kSmoothstep:
+        case core::BuiltinFn::kSmoothstep:
             glsl_ext_inst(GLSLstd450SmoothStep);
             break;
-        case core::Function::kSqrt:
+        case core::BuiltinFn::kSqrt:
             glsl_ext_inst(GLSLstd450Sqrt);
             break;
-        case core::Function::kStep:
+        case core::BuiltinFn::kStep:
             glsl_ext_inst(GLSLstd450Step);
             break;
-        case core::Function::kStorageBarrier:
+        case core::BuiltinFn::kStorageBarrier:
             op = spv::Op::OpControlBarrier;
             operands.clear();
             operands.push_back(Constant(b_.ConstantValue(u32(spv::Scope::Workgroup))));
@@ -1410,24 +1410,24 @@
                 Constant(b_.ConstantValue(u32(spv::MemorySemanticsMask::UniformMemory |
                                               spv::MemorySemanticsMask::AcquireRelease))));
             break;
-        case core::Function::kSubgroupBallot:
+        case core::BuiltinFn::kSubgroupBallot:
             module_.PushCapability(SpvCapabilityGroupNonUniformBallot);
             op = spv::Op::OpGroupNonUniformBallot;
             operands.push_back(Constant(ir_->constant_values.Get(u32(spv::Scope::Subgroup))));
             operands.push_back(Constant(ir_->constant_values.Get(true)));
             break;
-        case core::Function::kSubgroupBroadcast:
+        case core::BuiltinFn::kSubgroupBroadcast:
             module_.PushCapability(SpvCapabilityGroupNonUniformBallot);
             op = spv::Op::OpGroupNonUniformBroadcast;
             operands.push_back(Constant(ir_->constant_values.Get(u32(spv::Scope::Subgroup))));
             break;
-        case core::Function::kTan:
+        case core::BuiltinFn::kTan:
             glsl_ext_inst(GLSLstd450Tan);
             break;
-        case core::Function::kTanh:
+        case core::BuiltinFn::kTanh:
             glsl_ext_inst(GLSLstd450Tanh);
             break;
-        case core::Function::kTextureBarrier:
+        case core::BuiltinFn::kTextureBarrier:
             op = spv::Op::OpControlBarrier;
             operands.clear();
             operands.push_back(Constant(b_.ConstantValue(u32(spv::Scope::Workgroup))));
@@ -1436,36 +1436,36 @@
                 Constant(b_.ConstantValue(u32(spv::MemorySemanticsMask::ImageMemory |
                                               spv::MemorySemanticsMask::AcquireRelease))));
             break;
-        case core::Function::kTextureNumLevels:
+        case core::BuiltinFn::kTextureNumLevels:
             module_.PushCapability(SpvCapabilityImageQuery);
             op = spv::Op::OpImageQueryLevels;
             break;
-        case core::Function::kTextureNumSamples:
+        case core::BuiltinFn::kTextureNumSamples:
             module_.PushCapability(SpvCapabilityImageQuery);
             op = spv::Op::OpImageQuerySamples;
             break;
-        case core::Function::kTranspose:
+        case core::BuiltinFn::kTranspose:
             op = spv::Op::OpTranspose;
             break;
-        case core::Function::kTrunc:
+        case core::BuiltinFn::kTrunc:
             glsl_ext_inst(GLSLstd450Trunc);
             break;
-        case core::Function::kUnpack2X16Float:
+        case core::BuiltinFn::kUnpack2X16Float:
             glsl_ext_inst(GLSLstd450UnpackHalf2x16);
             break;
-        case core::Function::kUnpack2X16Snorm:
+        case core::BuiltinFn::kUnpack2X16Snorm:
             glsl_ext_inst(GLSLstd450UnpackSnorm2x16);
             break;
-        case core::Function::kUnpack2X16Unorm:
+        case core::BuiltinFn::kUnpack2X16Unorm:
             glsl_ext_inst(GLSLstd450UnpackUnorm2x16);
             break;
-        case core::Function::kUnpack4X8Snorm:
+        case core::BuiltinFn::kUnpack4X8Snorm:
             glsl_ext_inst(GLSLstd450UnpackSnorm4x8);
             break;
-        case core::Function::kUnpack4X8Unorm:
+        case core::BuiltinFn::kUnpack4X8Unorm:
             glsl_ext_inst(GLSLstd450UnpackUnorm4x8);
             break;
-        case core::Function::kWorkgroupBarrier:
+        case core::BuiltinFn::kWorkgroupBarrier:
             op = spv::Op::OpControlBarrier;
             operands.clear();
             operands.push_back(Constant(b_.ConstantValue(u32(spv::Scope::Workgroup))));
diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
index 5b06c9d..c42146e 100644
--- a/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
+++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill.cc
@@ -63,35 +63,35 @@
             }
             if (auto* builtin = inst->As<core::ir::CoreBuiltinCall>()) {
                 switch (builtin->Func()) {
-                    case core::Function::kArrayLength:
-                    case core::Function::kAtomicAdd:
-                    case core::Function::kAtomicAnd:
-                    case core::Function::kAtomicCompareExchangeWeak:
-                    case core::Function::kAtomicExchange:
-                    case core::Function::kAtomicLoad:
-                    case core::Function::kAtomicMax:
-                    case core::Function::kAtomicMin:
-                    case core::Function::kAtomicOr:
-                    case core::Function::kAtomicStore:
-                    case core::Function::kAtomicSub:
-                    case core::Function::kAtomicXor:
-                    case core::Function::kDot:
-                    case core::Function::kSelect:
-                    case core::Function::kTextureDimensions:
-                    case core::Function::kTextureGather:
-                    case core::Function::kTextureGatherCompare:
-                    case core::Function::kTextureLoad:
-                    case core::Function::kTextureNumLayers:
-                    case core::Function::kTextureSample:
-                    case core::Function::kTextureSampleBias:
-                    case core::Function::kTextureSampleCompare:
-                    case core::Function::kTextureSampleCompareLevel:
-                    case core::Function::kTextureSampleGrad:
-                    case core::Function::kTextureSampleLevel:
-                    case core::Function::kTextureStore:
+                    case core::BuiltinFn::kArrayLength:
+                    case core::BuiltinFn::kAtomicAdd:
+                    case core::BuiltinFn::kAtomicAnd:
+                    case core::BuiltinFn::kAtomicCompareExchangeWeak:
+                    case core::BuiltinFn::kAtomicExchange:
+                    case core::BuiltinFn::kAtomicLoad:
+                    case core::BuiltinFn::kAtomicMax:
+                    case core::BuiltinFn::kAtomicMin:
+                    case core::BuiltinFn::kAtomicOr:
+                    case core::BuiltinFn::kAtomicStore:
+                    case core::BuiltinFn::kAtomicSub:
+                    case core::BuiltinFn::kAtomicXor:
+                    case core::BuiltinFn::kDot:
+                    case core::BuiltinFn::kSelect:
+                    case core::BuiltinFn::kTextureDimensions:
+                    case core::BuiltinFn::kTextureGather:
+                    case core::BuiltinFn::kTextureGatherCompare:
+                    case core::BuiltinFn::kTextureLoad:
+                    case core::BuiltinFn::kTextureNumLayers:
+                    case core::BuiltinFn::kTextureSample:
+                    case core::BuiltinFn::kTextureSampleBias:
+                    case core::BuiltinFn::kTextureSampleCompare:
+                    case core::BuiltinFn::kTextureSampleCompareLevel:
+                    case core::BuiltinFn::kTextureSampleGrad:
+                    case core::BuiltinFn::kTextureSampleLevel:
+                    case core::BuiltinFn::kTextureStore:
                         worklist.Push(builtin);
                         break;
-                    case core::Function::kQuantizeToF16:
+                    case core::BuiltinFn::kQuantizeToF16:
                         if (builtin->Result()->Type()->Is<core::type::Vector>()) {
                             worklist.Push(builtin);
                         }
@@ -106,53 +106,53 @@
         for (auto* builtin : worklist) {
             core::ir::Value* replacement = nullptr;
             switch (builtin->Func()) {
-                case core::Function::kArrayLength:
+                case core::BuiltinFn::kArrayLength:
                     replacement = ArrayLength(builtin);
                     break;
-                case core::Function::kAtomicAdd:
-                case core::Function::kAtomicAnd:
-                case core::Function::kAtomicCompareExchangeWeak:
-                case core::Function::kAtomicExchange:
-                case core::Function::kAtomicLoad:
-                case core::Function::kAtomicMax:
-                case core::Function::kAtomicMin:
-                case core::Function::kAtomicOr:
-                case core::Function::kAtomicStore:
-                case core::Function::kAtomicSub:
-                case core::Function::kAtomicXor:
+                case core::BuiltinFn::kAtomicAdd:
+                case core::BuiltinFn::kAtomicAnd:
+                case core::BuiltinFn::kAtomicCompareExchangeWeak:
+                case core::BuiltinFn::kAtomicExchange:
+                case core::BuiltinFn::kAtomicLoad:
+                case core::BuiltinFn::kAtomicMax:
+                case core::BuiltinFn::kAtomicMin:
+                case core::BuiltinFn::kAtomicOr:
+                case core::BuiltinFn::kAtomicStore:
+                case core::BuiltinFn::kAtomicSub:
+                case core::BuiltinFn::kAtomicXor:
                     replacement = Atomic(builtin);
                     break;
-                case core::Function::kDot:
+                case core::BuiltinFn::kDot:
                     replacement = Dot(builtin);
                     break;
-                case core::Function::kSelect:
+                case core::BuiltinFn::kSelect:
                     replacement = Select(builtin);
                     break;
-                case core::Function::kTextureDimensions:
+                case core::BuiltinFn::kTextureDimensions:
                     replacement = TextureDimensions(builtin);
                     break;
-                case core::Function::kTextureGather:
-                case core::Function::kTextureGatherCompare:
+                case core::BuiltinFn::kTextureGather:
+                case core::BuiltinFn::kTextureGatherCompare:
                     replacement = TextureGather(builtin);
                     break;
-                case core::Function::kTextureLoad:
+                case core::BuiltinFn::kTextureLoad:
                     replacement = TextureLoad(builtin);
                     break;
-                case core::Function::kTextureNumLayers:
+                case core::BuiltinFn::kTextureNumLayers:
                     replacement = TextureNumLayers(builtin);
                     break;
-                case core::Function::kTextureSample:
-                case core::Function::kTextureSampleBias:
-                case core::Function::kTextureSampleCompare:
-                case core::Function::kTextureSampleCompareLevel:
-                case core::Function::kTextureSampleGrad:
-                case core::Function::kTextureSampleLevel:
+                case core::BuiltinFn::kTextureSample:
+                case core::BuiltinFn::kTextureSampleBias:
+                case core::BuiltinFn::kTextureSampleCompare:
+                case core::BuiltinFn::kTextureSampleCompareLevel:
+                case core::BuiltinFn::kTextureSampleGrad:
+                case core::BuiltinFn::kTextureSampleLevel:
                     replacement = TextureSample(builtin);
                     break;
-                case core::Function::kTextureStore:
+                case core::BuiltinFn::kTextureStore:
                     replacement = TextureStore(builtin);
                     break;
-                case core::Function::kQuantizeToF16:
+                case core::BuiltinFn::kQuantizeToF16:
                     replacement = QuantizeToF16Vec(builtin);
                     break;
                 default:
@@ -231,15 +231,15 @@
         // Create the replacement call instruction.
         core::ir::Call* call = nullptr;
         switch (builtin->Func()) {
-            case core::Function::kAtomicAdd:
+            case core::BuiltinFn::kAtomicAdd:
                 call = build(result_ty, spirv::ir::Function::kAtomicIadd);
                 call->AppendArg(builtin->Args()[1]);
                 break;
-            case core::Function::kAtomicAnd:
+            case core::BuiltinFn::kAtomicAnd:
                 call = build(result_ty, spirv::ir::Function::kAtomicAnd);
                 call->AppendArg(builtin->Args()[1]);
                 break;
-            case core::Function::kAtomicCompareExchangeWeak: {
+            case core::BuiltinFn::kAtomicCompareExchangeWeak: {
                 auto* cmp = builtin->Args()[1];
                 auto* value = builtin->Args()[2];
                 auto* int_ty = value->Type();
@@ -260,18 +260,18 @@
                     Vector{original, compare->Result()});
                 break;
             }
-            case core::Function::kAtomicExchange:
+            case core::BuiltinFn::kAtomicExchange:
                 call = build(result_ty, spirv::ir::Function::kAtomicExchange);
                 call->AppendArg(builtin->Args()[1]);
                 break;
-            case core::Function::kAtomicLoad:
+            case core::BuiltinFn::kAtomicLoad:
                 call = build(result_ty, spirv::ir::Function::kAtomicLoad);
                 break;
-            case core::Function::kAtomicOr:
+            case core::BuiltinFn::kAtomicOr:
                 call = build(result_ty, spirv::ir::Function::kAtomicOr);
                 call->AppendArg(builtin->Args()[1]);
                 break;
-            case core::Function::kAtomicMax:
+            case core::BuiltinFn::kAtomicMax:
                 if (result_ty->is_signed_integer_scalar()) {
                     call = build(result_ty, spirv::ir::Function::kAtomicSmax);
                 } else {
@@ -279,7 +279,7 @@
                 }
                 call->AppendArg(builtin->Args()[1]);
                 break;
-            case core::Function::kAtomicMin:
+            case core::BuiltinFn::kAtomicMin:
                 if (result_ty->is_signed_integer_scalar()) {
                     call = build(result_ty, spirv::ir::Function::kAtomicSmin);
                 } else {
@@ -287,15 +287,15 @@
                 }
                 call->AppendArg(builtin->Args()[1]);
                 break;
-            case core::Function::kAtomicStore:
+            case core::BuiltinFn::kAtomicStore:
                 call = build(result_ty, spirv::ir::Function::kAtomicStore);
                 call->AppendArg(builtin->Args()[1]);
                 break;
-            case core::Function::kAtomicSub:
+            case core::BuiltinFn::kAtomicSub:
                 call = build(result_ty, spirv::ir::Function::kAtomicIsub);
                 call->AppendArg(builtin->Args()[1]);
                 break;
-            case core::Function::kAtomicXor:
+            case core::BuiltinFn::kAtomicXor:
                 call = build(result_ty, spirv::ir::Function::kAtomicXor);
                 call->AppendArg(builtin->Args()[1]);
                 break;
@@ -495,33 +495,33 @@
         core::ir::Value* depth = nullptr;
         ImageOperands operands;
         switch (builtin->Func()) {
-            case core::Function::kTextureSample:
+            case core::BuiltinFn::kTextureSample:
                 intrinsic = spirv::ir::Intrinsic::kImageSampleImplicitLod;
                 operands.offset = next_arg();
                 break;
-            case core::Function::kTextureSampleBias:
+            case core::BuiltinFn::kTextureSampleBias:
                 intrinsic = spirv::ir::Intrinsic::kImageSampleImplicitLod;
                 operands.bias = next_arg();
                 operands.offset = next_arg();
                 break;
-            case core::Function::kTextureSampleCompare:
+            case core::BuiltinFn::kTextureSampleCompare:
                 intrinsic = spirv::ir::Intrinsic::kImageSampleDrefImplicitLod;
                 depth = next_arg();
                 operands.offset = next_arg();
                 break;
-            case core::Function::kTextureSampleCompareLevel:
+            case core::BuiltinFn::kTextureSampleCompareLevel:
                 intrinsic = spirv::ir::Intrinsic::kImageSampleDrefExplicitLod;
                 depth = next_arg();
                 operands.lod = b.Constant(0_f);
                 operands.offset = next_arg();
                 break;
-            case core::Function::kTextureSampleGrad:
+            case core::BuiltinFn::kTextureSampleGrad:
                 intrinsic = spirv::ir::Intrinsic::kImageSampleExplicitLod;
                 operands.ddx = next_arg();
                 operands.ddy = next_arg();
                 operands.offset = next_arg();
                 break;
-            case core::Function::kTextureSampleLevel:
+            case core::BuiltinFn::kTextureSampleLevel:
                 intrinsic = spirv::ir::Intrinsic::kImageSampleExplicitLod;
                 operands.lod = next_arg();
                 operands.offset = next_arg();
@@ -603,11 +603,11 @@
         core::ir::Value* depth = nullptr;
         ImageOperands operands;
         switch (builtin->Func()) {
-            case core::Function::kTextureGather:
+            case core::BuiltinFn::kTextureGather:
                 function = spirv::ir::Function::kImageGather;
                 operands.offset = next_arg();
                 break;
-            case core::Function::kTextureGatherCompare:
+            case core::BuiltinFn::kTextureGatherCompare:
                 function = spirv::ir::Function::kImageDrefGather;
                 depth = next_arg();
                 operands.offset = next_arg();
@@ -839,7 +839,7 @@
         Vector<core::ir::Value*, 4> args;
         for (uint32_t i = 0; i < vec->Width(); i++) {
             auto* el = b.Access(ty.f32(), arg, u32(i));
-            auto* scalar_call = b.Call(ty.f32(), core::Function::kQuantizeToF16, el);
+            auto* scalar_call = b.Call(ty.f32(), core::BuiltinFn::kQuantizeToF16, el);
             args.Push(scalar_call->Result());
             el->InsertBefore(builtin);
             scalar_call->InsertBefore(builtin);
diff --git a/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc b/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc
index d20393f..5bd292a 100644
--- a/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc
+++ b/src/tint/lang/spirv/writer/raise/builtin_polyfill_test.cc
@@ -47,7 +47,7 @@
     auto* func = b.Function("foo", ty.u32());
     b.Append(func->Block(), [&] {
         auto* access = b.Access(ty.ptr(storage, arr), var, 2_u);
-        auto* result = b.Call(ty.u32(), core::Function::kArrayLength, access);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, access);
         b.Return(func, result);
     });
 
@@ -113,7 +113,7 @@
         auto* let_a = b.Let("a", var);
         auto* let_b = b.Let("b", let_a);
         auto* access = b.Access(ty.ptr(storage, arr), let_b, 2_u);
-        auto* result = b.Call(ty.u32(), core::Function::kArrayLength, access);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, access);
         b.Return(func, result);
     });
 
@@ -183,7 +183,7 @@
         auto* access = b.Access(ty.ptr(storage, arr), var, 2_u);
         auto* let_a = b.Let("a", access);
         auto* let_b = b.Let("b", let_a);
-        auto* result = b.Call(ty.u32(), core::Function::kArrayLength, let_b);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kArrayLength, let_b);
         b.Return(func, result);
     });
 
@@ -247,7 +247,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicAdd, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicAdd, var, arg1);
         b.Return(func, result);
     });
 
@@ -291,7 +291,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicAdd, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicAdd, var, arg1);
         b.Return(func, result);
     });
 
@@ -335,7 +335,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicAnd, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicAnd, var, arg1);
         b.Return(func, result);
     });
 
@@ -381,7 +381,8 @@
 
     b.Append(func->Block(), [&] {
         auto* result_ty = core::type::CreateAtomicCompareExchangeResult(ty, mod.symbols, ty.i32());
-        auto* result = b.Call(result_ty, core::Function::kAtomicCompareExchangeWeak, var, cmp, val);
+        auto* result =
+            b.Call(result_ty, core::BuiltinFn::kAtomicCompareExchangeWeak, var, cmp, val);
         b.Return(func, b.Access(ty.i32(), result, 0_u));
     });
 
@@ -439,7 +440,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicExchange, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicExchange, var, arg1);
         b.Return(func, result);
     });
 
@@ -481,7 +482,7 @@
     auto* func = b.Function("foo", ty.i32());
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicLoad, var);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicLoad, var);
         b.Return(func, result);
     });
 
@@ -525,7 +526,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicMax, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicMax, var, arg1);
         b.Return(func, result);
     });
 
@@ -569,7 +570,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kAtomicMax, var, arg1);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kAtomicMax, var, arg1);
         b.Return(func, result);
     });
 
@@ -613,7 +614,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicMin, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicMin, var, arg1);
         b.Return(func, result);
     });
 
@@ -657,7 +658,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kAtomicMin, var, arg1);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kAtomicMin, var, arg1);
         b.Return(func, result);
     });
 
@@ -701,7 +702,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicOr, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicOr, var, arg1);
         b.Return(func, result);
     });
 
@@ -745,7 +746,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        b.Call(ty.void_(), core::Function::kAtomicStore, var, arg1);
+        b.Call(ty.void_(), core::BuiltinFn::kAtomicStore, var, arg1);
         b.Return(func);
     });
 
@@ -789,7 +790,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicSub, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicSub, var, arg1);
         b.Return(func, result);
     });
 
@@ -833,7 +834,7 @@
     func->SetParams({arg1});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kAtomicXor, var, arg1);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kAtomicXor, var, arg1);
         b.Return(func, result);
     });
 
@@ -876,7 +877,7 @@
     func->SetParams({arg1, arg2});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f32(), core::Function::kDot, arg1, arg2);
+        auto* result = b.Call(ty.f32(), core::BuiltinFn::kDot, arg1, arg2);
         b.Return(func, result);
     });
 
@@ -911,7 +912,7 @@
     func->SetParams({arg1, arg2});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kDot, arg1, arg2);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kDot, arg1, arg2);
         b.Return(func, result);
     });
 
@@ -952,7 +953,7 @@
     func->SetParams({arg1, arg2});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kDot, arg1, arg2);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kDot, arg1, arg2);
         b.Return(func, result);
     });
 
@@ -1002,7 +1003,7 @@
     func->SetParams({argf, argt, cond});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.i32(), core::Function::kSelect, argf, argt, cond);
+        auto* result = b.Call(ty.i32(), core::BuiltinFn::kSelect, argf, argt, cond);
         b.Return(func, result);
     });
 
@@ -1038,7 +1039,7 @@
     func->SetParams({argf, argt, cond});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<i32>(), core::Function::kSelect, argf, argt, cond);
+        auto* result = b.Call(ty.vec4<i32>(), core::BuiltinFn::kSelect, argf, argt, cond);
         b.Return(func, result);
     });
 
@@ -1074,7 +1075,7 @@
     func->SetParams({argf, argt, cond});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<i32>(), core::Function::kSelect, argf, argt, cond);
+        auto* result = b.Call(ty.vec4<i32>(), core::BuiltinFn::kSelect, argf, argt, cond);
         b.Return(func, result);
     });
 
@@ -1112,7 +1113,7 @@
     func->SetParams({t, coords, lod});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, t, coords, lod);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, t, coords, lod);
         b.Return(func, result);
     });
 
@@ -1151,7 +1152,7 @@
 
     b.Append(func->Block(), [&] {
         auto* result =
-            b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, t, coords, array_idx, lod);
+            b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, t, coords, array_idx, lod);
         b.Return(func, result);
     });
 
@@ -1191,7 +1192,7 @@
 
     b.Append(func->Block(), [&] {
         auto* result =
-            b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, t, coords, array_idx, lod);
+            b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, t, coords, array_idx, lod);
         b.Return(func, result);
     });
 
@@ -1230,7 +1231,7 @@
     func->SetParams({t, coords, sample_idx});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, t, coords, sample_idx);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, t, coords, sample_idx);
         b.Return(func, result);
     });
 
@@ -1267,7 +1268,7 @@
     func->SetParams({t, coords, lod});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f32(), core::Function::kTextureLoad, t, coords, lod);
+        auto* result = b.Call(ty.f32(), core::BuiltinFn::kTextureLoad, t, coords, lod);
         b.Return(func, result);
     });
 
@@ -1305,7 +1306,7 @@
     func->SetParams({t, s, coords});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureSample, t, s, coords);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSample, t, s, coords);
         b.Return(func, result);
     });
 
@@ -1343,7 +1344,7 @@
     func->SetParams({t, s, coords});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureSample, t, s, coords);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSample, t, s, coords);
         b.Return(func, result);
     });
 
@@ -1381,7 +1382,7 @@
     func->SetParams({t, s, coords});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureSample, t, s, coords,
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSample, t, s, coords,
                               b.Splat(ty.vec2<i32>(), 1_i, 2));
         b.Return(func, result);
     });
@@ -1421,7 +1422,7 @@
     func->SetParams({t, s, coords, array_idx});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureSample, t, s, coords,
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSample, t, s, coords,
                               array_idx, b.Splat(ty.vec2<i32>(), 1_i, 2));
         b.Return(func, result);
     });
@@ -1464,7 +1465,7 @@
 
     b.Append(func->Block(), [&] {
         auto* result =
-            b.Call(ty.vec4<f32>(), core::Function::kTextureSampleBias, t, s, coords, bias);
+            b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleBias, t, s, coords, bias);
         b.Return(func, result);
     });
 
@@ -1503,7 +1504,7 @@
     func->SetParams({t, s, coords, bias});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureSampleBias, t, s, coords,
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleBias, t, s, coords,
                               bias, b.Splat(ty.vec2<i32>(), 1_i, 2));
         b.Return(func, result);
     });
@@ -1544,7 +1545,7 @@
     func->SetParams({t, s, coords, array_idx, bias});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureSampleBias, t, s, coords,
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleBias, t, s, coords,
                               array_idx, bias, b.Splat(ty.vec2<i32>(), 1_i, 2));
         b.Return(func, result);
     });
@@ -1586,7 +1587,7 @@
     func->SetParams({t, s, coords, dref});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f32(), core::Function::kTextureSampleCompare, t, s, coords, dref);
+        auto* result = b.Call(ty.f32(), core::BuiltinFn::kTextureSampleCompare, t, s, coords, dref);
         b.Return(func, result);
     });
 
@@ -1625,7 +1626,7 @@
     func->SetParams({t, s, coords, dref});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f32(), core::Function::kTextureSampleCompare, t, s, coords, dref,
+        auto* result = b.Call(ty.f32(), core::BuiltinFn::kTextureSampleCompare, t, s, coords, dref,
                               b.Splat(ty.vec2<i32>(), 1_i, 2));
         b.Return(func, result);
     });
@@ -1666,7 +1667,7 @@
     func->SetParams({t, s, coords, array_idx, bias});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f32(), core::Function::kTextureSampleCompare, t, s, coords,
+        auto* result = b.Call(ty.f32(), core::BuiltinFn::kTextureSampleCompare, t, s, coords,
                               array_idx, bias, b.Splat(ty.vec2<i32>(), 1_i, 2));
         b.Return(func, result);
     });
@@ -1709,7 +1710,7 @@
 
     b.Append(func->Block(), [&] {
         auto* result =
-            b.Call(ty.f32(), core::Function::kTextureSampleCompareLevel, t, s, coords, dref);
+            b.Call(ty.f32(), core::BuiltinFn::kTextureSampleCompareLevel, t, s, coords, dref);
         b.Return(func, result);
     });
 
@@ -1748,7 +1749,7 @@
     func->SetParams({t, s, coords, dref});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f32(), core::Function::kTextureSampleCompareLevel, t, s, coords,
+        auto* result = b.Call(ty.f32(), core::BuiltinFn::kTextureSampleCompareLevel, t, s, coords,
                               dref, b.Splat(ty.vec2<i32>(), 1_i, 2));
         b.Return(func, result);
     });
@@ -1789,7 +1790,7 @@
     func->SetParams({t, s, coords, array_idx, bias});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f32(), core::Function::kTextureSampleCompareLevel, t, s, coords,
+        auto* result = b.Call(ty.f32(), core::BuiltinFn::kTextureSampleCompareLevel, t, s, coords,
                               array_idx, bias, b.Splat(ty.vec2<i32>(), 1_i, 2));
         b.Return(func, result);
     });
@@ -1833,7 +1834,7 @@
 
     b.Append(func->Block(), [&] {
         auto* result =
-            b.Call(ty.vec4<f32>(), core::Function::kTextureSampleGrad, t, s, coords, ddx, ddy);
+            b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleGrad, t, s, coords, ddx, ddy);
         b.Return(func, result);
     });
 
@@ -1873,8 +1874,8 @@
     func->SetParams({t, s, coords, ddx, ddy});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureSampleGrad, t, s, coords, ddx,
-                              ddy, b.Splat(ty.vec2<i32>(), 1_i, 2));
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleGrad, t, s, coords,
+                              ddx, ddy, b.Splat(ty.vec2<i32>(), 1_i, 2));
         b.Return(func, result);
     });
 
@@ -1915,7 +1916,7 @@
     func->SetParams({t, s, coords, array_idx, ddx, ddy});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureSampleGrad, t, s, coords,
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleGrad, t, s, coords,
                               array_idx, ddx, ddy, b.Splat(ty.vec2<i32>(), 1_i, 2));
         b.Return(func, result);
     });
@@ -1958,7 +1959,7 @@
 
     b.Append(func->Block(), [&] {
         auto* result =
-            b.Call(ty.vec4<f32>(), core::Function::kTextureSampleLevel, t, s, coords, lod);
+            b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleLevel, t, s, coords, lod);
         b.Return(func, result);
     });
 
@@ -1997,7 +1998,7 @@
     func->SetParams({t, s, coords, lod});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureSampleLevel, t, s, coords,
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleLevel, t, s, coords,
                               lod, b.Splat(ty.vec2<i32>(), 1_i, 2));
         b.Return(func, result);
     });
@@ -2038,7 +2039,7 @@
     func->SetParams({t, s, coords, array_idx, lod});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureSampleLevel, t, s, coords,
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleLevel, t, s, coords,
                               array_idx, lod, b.Splat(ty.vec2<i32>(), 1_i, 2));
         b.Return(func, result);
     });
@@ -2081,7 +2082,7 @@
 
     b.Append(func->Block(), [&] {
         auto* result =
-            b.Call(ty.vec4<f32>(), core::Function::kTextureGather, component, t, s, coords);
+            b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureGather, component, t, s, coords);
         b.Return(func, result);
     });
 
@@ -2120,7 +2121,7 @@
     func->SetParams({t, s, component, coords});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureGather, component, t, s,
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureGather, component, t, s,
                               coords, b.Splat(ty.vec2<i32>(), 1_i, 2));
         b.Return(func, result);
     });
@@ -2161,7 +2162,7 @@
     func->SetParams({t, s, component, coords, array_idx});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureGather, component, t, s,
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureGather, component, t, s,
                               coords, array_idx, b.Splat(ty.vec2<i32>(), 1_i, 2));
         b.Return(func, result);
     });
@@ -2202,7 +2203,7 @@
     func->SetParams({t, s, coords});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureGather, t, s, coords);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureGather, t, s, coords);
         b.Return(func, result);
     });
 
@@ -2242,7 +2243,7 @@
 
     b.Append(func->Block(), [&] {
         auto* result =
-            b.Call(ty.vec4<f32>(), core::Function::kTextureGatherCompare, t, s, coords, depth);
+            b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureGatherCompare, t, s, coords, depth);
         b.Return(func, result);
     });
 
@@ -2281,7 +2282,7 @@
     func->SetParams({t, s, coords, depth});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureGatherCompare, t, s, coords,
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureGatherCompare, t, s, coords,
                               depth, b.Splat(ty.vec2<i32>(), 1_i, 2));
         b.Return(func, result);
     });
@@ -2322,7 +2323,7 @@
     func->SetParams({t, s, coords, array_idx, depth});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureGatherCompare, t, s, coords,
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureGatherCompare, t, s, coords,
                               array_idx, depth);
         b.Return(func, result);
     });
@@ -2366,7 +2367,7 @@
     func->SetParams({t, coords, texel});
 
     b.Append(func->Block(), [&] {
-        b.Call(ty.void_(), core::Function::kTextureStore, t, coords, texel);
+        b.Call(ty.void_(), core::BuiltinFn::kTextureStore, t, coords, texel);
         b.Return(func);
     });
 
@@ -2407,7 +2408,7 @@
     func->SetParams({t, coords, array_idx, texel});
 
     b.Append(func->Block(), [&] {
-        b.Call(ty.void_(), core::Function::kTextureStore, t, coords, array_idx, texel);
+        b.Call(ty.void_(), core::BuiltinFn::kTextureStore, t, coords, array_idx, texel);
         b.Return(func);
     });
 
@@ -2449,7 +2450,7 @@
     func->SetParams({t, coords, array_idx, texel});
 
     b.Append(func->Block(), [&] {
-        b.Call(ty.void_(), core::Function::kTextureStore, t, coords, array_idx, texel);
+        b.Call(ty.void_(), core::BuiltinFn::kTextureStore, t, coords, array_idx, texel);
         b.Return(func);
     });
 
@@ -2486,7 +2487,7 @@
     func->SetParams({t});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec2<u32>(), core::Function::kTextureDimensions, t);
+        auto* result = b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, t);
         b.Return(func, result);
     });
 
@@ -2522,7 +2523,7 @@
     func->SetParams({t, lod});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec2<u32>(), core::Function::kTextureDimensions, t, lod);
+        auto* result = b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, t, lod);
         b.Return(func, result);
     });
 
@@ -2557,7 +2558,7 @@
     func->SetParams({t});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec2<u32>(), core::Function::kTextureDimensions, t);
+        auto* result = b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, t);
         b.Return(func, result);
     });
 
@@ -2593,7 +2594,7 @@
     func->SetParams({t});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec2<u32>(), core::Function::kTextureDimensions, t);
+        auto* result = b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, t);
         b.Return(func, result);
     });
 
@@ -2628,7 +2629,7 @@
     func->SetParams({t});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kTextureNumLayers, t);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kTextureNumLayers, t);
         b.Return(func, result);
     });
 
@@ -2664,7 +2665,7 @@
     func->SetParams({t});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kTextureNumLayers, t);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kTextureNumLayers, t);
         b.Return(func, result);
     });
 
@@ -2700,7 +2701,7 @@
     func->SetParams({t});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kTextureNumLayers, t);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kTextureNumLayers, t);
         b.Return(func, result);
     });
 
@@ -2736,7 +2737,7 @@
     func->SetParams({t});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kTextureNumLayers, t);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kTextureNumLayers, t);
         b.Return(func, result);
     });
 
@@ -2775,7 +2776,7 @@
     func->SetParams({t});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.u32(), core::Function::kTextureNumLayers, t);
+        auto* result = b.Call(ty.u32(), core::BuiltinFn::kTextureNumLayers, t);
         b.Return(func, result);
     });
 
@@ -2810,7 +2811,7 @@
     func->SetParams({arg});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.f32(), core::Function::kQuantizeToF16, arg);
+        auto* result = b.Call(ty.f32(), core::BuiltinFn::kQuantizeToF16, arg);
         b.Return(func, result);
     });
 
@@ -2837,7 +2838,7 @@
     func->SetParams({arg});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kQuantizeToF16, arg);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kQuantizeToF16, arg);
         b.Return(func, result);
     });
 
diff --git a/src/tint/lang/spirv/writer/raise/expand_implicit_splats.cc b/src/tint/lang/spirv/writer/raise/expand_implicit_splats.cc
index c222b71..cedf944 100644
--- a/src/tint/lang/spirv/writer/raise/expand_implicit_splats.cc
+++ b/src/tint/lang/spirv/writer/raise/expand_implicit_splats.cc
@@ -62,7 +62,7 @@
         } else if (auto* builtin = inst->As<core::ir::CoreBuiltinCall>()) {
             // A mix builtin call that mixes vector and scalar operands needs to have the scalar
             // operand replaced with an explicit vector constructor.
-            if (builtin->Func() == core::Function::kMix) {
+            if (builtin->Func() == core::BuiltinFn::kMix) {
                 if (builtin->Result()->Type()->Is<core::type::Vector>()) {
                     if (builtin->Args()[2]->Type()->Is<core::type::Scalar>()) {
                         builtin_worklist.Push(builtin);
@@ -118,7 +118,7 @@
     // Replace scalar arguments to builtin calls that produce vectors.
     for (auto* builtin : builtin_worklist) {
         switch (builtin->Func()) {
-            case core::Function::kMix:
+            case core::BuiltinFn::kMix:
                 // Expand the scalar argument into an explicitly constructed vector.
                 expand_operand(builtin, core::ir::CoreBuiltinCall::kArgsOperandOffset + 2);
                 break;
diff --git a/src/tint/lang/spirv/writer/raise/expand_implicit_splats_test.cc b/src/tint/lang/spirv/writer/raise/expand_implicit_splats_test.cc
index 9111271..79b83aa 100644
--- a/src/tint/lang/spirv/writer/raise/expand_implicit_splats_test.cc
+++ b/src/tint/lang/spirv/writer/raise/expand_implicit_splats_test.cc
@@ -639,7 +639,7 @@
     func->SetParams({arg1, arg2, factor});
 
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kMix, arg1, arg2, factor);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kMix, arg1, arg2, factor);
         b.Return(func, result);
     });
 
diff --git a/src/tint/lang/spirv/writer/raise/shader_io.cc b/src/tint/lang/spirv/writer/raise/shader_io.cc
index 0c7a3b2..d4c60ed 100644
--- a/src/tint/lang/spirv/writer/raise/shader_io.cc
+++ b/src/tint/lang/spirv/writer/raise/shader_io.cc
@@ -186,7 +186,7 @@
         auto* frag_depth_min = builder.Access(ty.f32(), args, 0_u);
         auto* frag_depth_max = builder.Access(ty.f32(), args, 1_u);
         return builder
-            .Call(ty.f32(), core::Function::kClamp, frag_depth, frag_depth_min, frag_depth_max)
+            .Call(ty.f32(), core::BuiltinFn::kClamp, frag_depth, frag_depth_min, frag_depth_max)
             ->Result();
     }
 
diff --git a/src/tint/lang/spirv/writer/texture_builtin_test.cc b/src/tint/lang/spirv/writer/texture_builtin_test.cc
index c77274b..db4f44f 100644
--- a/src/tint/lang/spirv/writer/texture_builtin_test.cc
+++ b/src/tint/lang/spirv/writer/texture_builtin_test.cc
@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/tint/lang/core/builtin_fn.h"
 #include "src/tint/lang/core/fluent_types.h"
-#include "src/tint/lang/core/function.h"
 #include "src/tint/lang/core/type/depth_multisampled_texture.h"
 #include "src/tint/lang/spirv/writer/common/helper_test.h"
 
@@ -130,11 +130,11 @@
         return nullptr;
     }
 
-    void Run(enum core::Function function, SamplerUsage sampler) {
+    void Run(enum core::BuiltinFn function, SamplerUsage sampler) {
         auto params = GetParam();
 
         auto* result_ty = MakeScalarType(params.result.type);
-        if (function == core::Function::kTextureStore) {
+        if (function == core::BuiltinFn::kTextureStore) {
             result_ty = ty.void_();
         }
         if (params.result.width > 1) {
@@ -162,7 +162,7 @@
             uint32_t arg_value = 1;
 
             Vector<core::ir::Value*, 4> args;
-            if (function == core::Function::kTextureGather &&
+            if (function == core::BuiltinFn::kTextureGather &&
                 params.texture_type != kDepthTexture) {
                 // Special case for textureGather, which has a component argument first.
                 auto* component = MakeScalarValue(kU32, arg_value++);
@@ -205,7 +205,7 @@
 ////////////////////////////////////////////////////////////////
 using TextureSample = TextureBuiltinTest;
 TEST_P(TextureSample, Emit) {
-    Run(core::Function::kTextureSample, kSampler);
+    Run(core::BuiltinFn::kTextureSample, kSampler);
 }
 INSTANTIATE_TEST_SUITE_P(
     SpirvWriterTest,
@@ -400,7 +400,7 @@
 ////////////////////////////////////////////////////////////////
 using TextureSampleBias = TextureBuiltinTest;
 TEST_P(TextureSampleBias, Emit) {
-    Run(core::Function::kTextureSampleBias, kSampler);
+    Run(core::BuiltinFn::kTextureSampleBias, kSampler);
 }
 INSTANTIATE_TEST_SUITE_P(
     SpirvWriterTest,
@@ -507,7 +507,7 @@
 ////////////////////////////////////////////////////////////////
 using TextureSampleGrad = TextureBuiltinTest;
 TEST_P(TextureSampleGrad, Emit) {
-    Run(core::Function::kTextureSampleGrad, kSampler);
+    Run(core::BuiltinFn::kTextureSampleGrad, kSampler);
 }
 INSTANTIATE_TEST_SUITE_P(
     SpirvWriterTest,
@@ -618,7 +618,7 @@
 ////////////////////////////////////////////////////////////////
 using TextureSampleLevel = TextureBuiltinTest;
 TEST_P(TextureSampleLevel, Emit) {
-    Run(core::Function::kTextureSampleLevel, kSampler);
+    Run(core::BuiltinFn::kTextureSampleLevel, kSampler);
 }
 INSTANTIATE_TEST_SUITE_P(
     SpirvWriterTest,
@@ -808,7 +808,7 @@
 ////////////////////////////////////////////////////////////////
 using TextureSampleCompare = TextureBuiltinTest;
 TEST_P(TextureSampleCompare, Emit) {
-    Run(core::Function::kTextureSampleCompare, kComparisonSampler);
+    Run(core::BuiltinFn::kTextureSampleCompare, kComparisonSampler);
 }
 INSTANTIATE_TEST_SUITE_P(
     SpirvWriterTest,
@@ -893,7 +893,7 @@
 ////////////////////////////////////////////////////////////////
 using TextureSampleCompareLevel = TextureBuiltinTest;
 TEST_P(TextureSampleCompareLevel, Emit) {
-    Run(core::Function::kTextureSampleCompareLevel, kComparisonSampler);
+    Run(core::BuiltinFn::kTextureSampleCompareLevel, kComparisonSampler);
 }
 INSTANTIATE_TEST_SUITE_P(
     SpirvWriterTest,
@@ -983,7 +983,7 @@
 ////////////////////////////////////////////////////////////////
 using TextureGather = TextureBuiltinTest;
 TEST_P(TextureGather, Emit) {
-    Run(core::Function::kTextureGather, kSampler);
+    Run(core::BuiltinFn::kTextureGather, kSampler);
 }
 INSTANTIATE_TEST_SUITE_P(
     SpirvWriterTest,
@@ -1164,7 +1164,7 @@
 ////////////////////////////////////////////////////////////////
 using TextureGatherCompare = TextureBuiltinTest;
 TEST_P(TextureGatherCompare, Emit) {
-    Run(core::Function::kTextureGatherCompare, kComparisonSampler);
+    Run(core::BuiltinFn::kTextureGatherCompare, kComparisonSampler);
 }
 INSTANTIATE_TEST_SUITE_P(
     SpirvWriterTest,
@@ -1249,7 +1249,7 @@
 ////////////////////////////////////////////////////////////////
 using TextureLoad = TextureBuiltinTest;
 TEST_P(TextureLoad, Emit) {
-    Run(core::Function::kTextureLoad, kNoSampler);
+    Run(core::BuiltinFn::kTextureLoad, kNoSampler);
 }
 INSTANTIATE_TEST_SUITE_P(SpirvWriterTest,
                          TextureLoad,
@@ -1368,7 +1368,7 @@
 ////////////////////////////////////////////////////////////////
 using TextureStore = TextureBuiltinTest;
 TEST_P(TextureStore, Emit) {
-    Run(core::Function::kTextureStore, kNoSampler);
+    Run(core::BuiltinFn::kTextureStore, kNoSampler);
 }
 INSTANTIATE_TEST_SUITE_P(SpirvWriterTest,
                          TextureStore,
@@ -1443,7 +1443,7 @@
 ////////////////////////////////////////////////////////////////
 using TextureDimensions = TextureBuiltinTest;
 TEST_P(TextureDimensions, Emit) {
-    Run(core::Function::kTextureDimensions, kNoSampler);
+    Run(core::BuiltinFn::kTextureDimensions, kNoSampler);
 }
 INSTANTIATE_TEST_SUITE_P(SpirvWriterTest,
                          TextureDimensions,
@@ -1693,7 +1693,7 @@
 ////////////////////////////////////////////////////////////////
 using TextureNumLayers = TextureBuiltinTest;
 TEST_P(TextureNumLayers, Emit) {
-    Run(core::Function::kTextureNumLayers, kNoSampler);
+    Run(core::BuiltinFn::kTextureNumLayers, kNoSampler);
 }
 INSTANTIATE_TEST_SUITE_P(SpirvWriterTest,
                          TextureNumLayers,
@@ -1760,7 +1760,7 @@
 ////////////////////////////////////////////////////////////////
 using TextureNumLevels = TextureBuiltinTest;
 TEST_P(TextureNumLevels, Emit) {
-    Run(core::Function::kTextureNumLevels, kNoSampler);
+    Run(core::BuiltinFn::kTextureNumLevels, kNoSampler);
 }
 INSTANTIATE_TEST_SUITE_P(SpirvWriterTest,
                          TextureNumLevels,
@@ -1852,7 +1852,7 @@
 ////////////////////////////////////////////////////////////////
 using TextureNumSamples = TextureBuiltinTest;
 TEST_P(TextureNumSamples, Emit) {
-    Run(core::Function::kTextureNumSamples, kNoSampler);
+    Run(core::BuiltinFn::kTextureNumSamples, kNoSampler);
 }
 INSTANTIATE_TEST_SUITE_P(SpirvWriterTest,
                          TextureNumSamples,
@@ -1891,7 +1891,7 @@
     auto* func = b.Function("foo", ty.vec4<f32>());
     func->SetParams(args);
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureSampleBaseClampToEdge, args);
+        auto* result = b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureSampleBaseClampToEdge, args);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -1926,7 +1926,7 @@
     auto* func = b.Function("foo", ty.void_());
     func->SetParams({texture, coords, value});
     b.Append(func->Block(), [&] {
-        b.Call(ty.void_(), core::Function::kTextureStore, texture, coords, value);
+        b.Call(ty.void_(), core::BuiltinFn::kTextureStore, texture, coords, value);
         b.Return(func);
     });
 
@@ -1952,7 +1952,7 @@
     auto* func = b.Function("foo", ty.vec2<u32>());
     func->SetParams({texture, level});
     b.Append(func->Block(), [&] {
-        auto* dims = b.Call(ty.vec2<u32>(), core::Function::kTextureDimensions, texture, level);
+        auto* dims = b.Call(ty.vec2<u32>(), core::BuiltinFn::kTextureDimensions, texture, level);
         b.Return(func, dims);
         mod.SetName(dims, "dims");
     });
@@ -1977,7 +1977,8 @@
     auto* func = b.Function("foo", ty.vec4<f32>());
     func->SetParams({texture, coords, level});
     b.Append(func->Block(), [&] {
-        auto* result = b.Call(ty.vec4<f32>(), core::Function::kTextureLoad, texture, coords, level);
+        auto* result =
+            b.Call(ty.vec4<f32>(), core::BuiltinFn::kTextureLoad, texture, coords, level);
         b.Return(func, result);
         mod.SetName(result, "result");
     });
@@ -2008,7 +2009,7 @@
     auto* func = b.Function("foo", ty.void_());
     func->SetParams({texture, coords, layer, value});
     b.Append(func->Block(), [&] {
-        b.Call(ty.void_(), core::Function::kTextureStore, texture, coords, layer, value);
+        b.Call(ty.void_(), core::BuiltinFn::kTextureStore, texture, coords, layer, value);
         b.Return(func);
     });
 
diff --git a/src/tint/lang/wgsl/ast/call_expression.h b/src/tint/lang/wgsl/ast/call_expression.h
index 07a3e5a..a26eeac 100644
--- a/src/tint/lang/wgsl/ast/call_expression.h
+++ b/src/tint/lang/wgsl/ast/call_expression.h
@@ -27,7 +27,7 @@
 
 /// A call expression - represents either a:
 /// * sem::Function
-/// * sem::Builtin
+/// * sem::BuiltinFn
 /// * sem::ValueConstructor
 /// * sem::ValueConversion
 class CallExpression final : public Castable<CallExpression, Expression> {
diff --git a/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc b/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc
index d9e1c60c..49cc35c 100644
--- a/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc
+++ b/src/tint/lang/wgsl/ast/transform/array_length_from_uniform.cc
@@ -41,7 +41,7 @@
     for (auto* fn : program->AST().Functions()) {
         if (auto* sem_fn = program->Sem().Get(fn)) {
             for (auto* builtin : sem_fn->DirectlyCalledBuiltins()) {
-                if (builtin->Type() == core::Function::kArrayLength) {
+                if (builtin->Fn() == core::BuiltinFn::kArrayLength) {
                     return true;
                 }
             }
@@ -206,8 +206,8 @@
             }
 
             auto* call = sem.Get(call_expr)->UnwrapMaterialize()->As<sem::Call>();
-            auto* builtin = call->Target()->As<sem::Builtin>();
-            if (!builtin || builtin->Type() != core::Function::kArrayLength) {
+            auto* builtin = call->Target()->As<sem::BuiltinFn>();
+            if (!builtin || builtin->Fn() != core::BuiltinFn::kArrayLength) {
                 continue;
             }
 
diff --git a/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc b/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc
index dc4ba14..c49d83b 100644
--- a/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc
+++ b/src/tint/lang/wgsl/ast/transform/builtin_polyfill.cc
@@ -24,7 +24,7 @@
 #include "src/tint/lang/wgsl/program/clone_context.h"
 #include "src/tint/lang/wgsl/program/program_builder.h"
 #include "src/tint/lang/wgsl/resolver/resolve.h"
-#include "src/tint/lang/wgsl/sem/builtin.h"
+#include "src/tint/lang/wgsl/sem/builtin_fn.h"
 #include "src/tint/lang/wgsl/sem/call.h"
 #include "src/tint/lang/wgsl/sem/type_expression.h"
 #include "src/tint/lang/wgsl/sem/value_conversion.h"
@@ -155,7 +155,7 @@
     /// Polyfill functions for binary operators.
     Hashmap<BinaryOpSignature, Symbol, 8> binary_op_polyfills;
     /// Polyfill builtins.
-    Hashmap<const sem::Builtin*, Symbol, 8> builtin_polyfills;
+    Hashmap<const sem::BuiltinFn*, Symbol, 8> builtin_polyfills;
     /// Polyfill f32 conversion to i32 or u32 (or vectors of)
     Hashmap<const core::type::Type*, Symbol, 2> f32_conv_polyfills;
     // Tracks whether the chromium_experimental_full_ptr_parameters extension has been enabled.
@@ -858,13 +858,13 @@
         const uint32_t width = WidthOf(target);
 
         // select(target(v), low_limit, v < low_condition)
-        auto* select_low = b.Call(core::Function::kSelect,                  //
+        auto* select_low = b.Call(core::BuiltinFn::kSelect,                 //
                                   b.Call(T(target), "v"),                   //
                                   ScalarOrVector(width, limits.low_limit),  //
                                   b.LessThan("v", ScalarOrVector(width, limits.low_condition)));
 
         // select(high_limit, select_low, v < high_condition)
-        auto* select_high = b.Call(core::Function::kSelect,                   //
+        auto* select_high = b.Call(core::BuiltinFn::kSelect,                  //
                                    ScalarOrVector(width, limits.high_limit),  //
                                    select_low,                                //
                                    b.LessThan("v", ScalarOrVector(width, limits.high_condition)));
@@ -1078,30 +1078,30 @@
         }
         Symbol fn = Switch(
             call->Target(),  //
-            [&](const sem::Builtin* builtin) {
-                switch (builtin->Type()) {
-                    case core::Function::kAcosh:
+            [&](const sem::BuiltinFn* builtin) {
+                switch (builtin->Fn()) {
+                    case core::BuiltinFn::kAcosh:
                         if (cfg.builtins.acosh != Level::kNone) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return acosh(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::Function::kAsinh:
+                    case core::BuiltinFn::kAsinh:
                         if (cfg.builtins.asinh) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return asinh(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::Function::kAtanh:
+                    case core::BuiltinFn::kAtanh:
                         if (cfg.builtins.atanh != Level::kNone) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return atanh(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::Function::kClamp:
+                    case core::BuiltinFn::kClamp:
                         if (cfg.builtins.clamp_int) {
                             auto& sig = builtin->Signature();
                             if (sig.parameters[0]->Type()->is_integer_scalar_or_vector()) {
@@ -1111,49 +1111,49 @@
                         }
                         return Symbol{};
 
-                    case core::Function::kCountLeadingZeros:
+                    case core::BuiltinFn::kCountLeadingZeros:
                         if (cfg.builtins.count_leading_zeros) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return countLeadingZeros(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::Function::kCountTrailingZeros:
+                    case core::BuiltinFn::kCountTrailingZeros:
                         if (cfg.builtins.count_trailing_zeros) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return countTrailingZeros(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::Function::kExtractBits:
+                    case core::BuiltinFn::kExtractBits:
                         if (cfg.builtins.extract_bits != Level::kNone) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return extractBits(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::Function::kFirstLeadingBit:
+                    case core::BuiltinFn::kFirstLeadingBit:
                         if (cfg.builtins.first_leading_bit) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return firstLeadingBit(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::Function::kFirstTrailingBit:
+                    case core::BuiltinFn::kFirstTrailingBit:
                         if (cfg.builtins.first_trailing_bit) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return firstTrailingBit(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::Function::kInsertBits:
+                    case core::BuiltinFn::kInsertBits:
                         if (cfg.builtins.insert_bits != Level::kNone) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return insertBits(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::Function::kReflect:
+                    case core::BuiltinFn::kReflect:
                         // Only polyfill for vec2<f32>. See https://crbug.com/tint/1798 for
                         // more details.
                         if (cfg.builtins.reflect_vec2_f32) {
@@ -1166,14 +1166,14 @@
                         }
                         return Symbol{};
 
-                    case core::Function::kSaturate:
+                    case core::BuiltinFn::kSaturate:
                         if (cfg.builtins.saturate) {
                             return builtin_polyfills.GetOrCreate(
                                 builtin, [&] { return saturate(builtin->ReturnType()); });
                         }
                         return Symbol{};
 
-                    case core::Function::kSign:
+                    case core::BuiltinFn::kSign:
                         if (cfg.builtins.sign_int) {
                             auto* ty = builtin->ReturnType();
                             if (ty->is_signed_integer_scalar_or_vector()) {
@@ -1183,7 +1183,7 @@
                         }
                         return Symbol{};
 
-                    case core::Function::kTextureLoad:
+                    case core::BuiltinFn::kTextureLoad:
                         if (cfg.builtins.bgra8unorm) {
                             auto& sig = builtin->Signature();
                             auto* tex = sig.Parameter(core::ParameterUsage::kTexture);
@@ -1199,7 +1199,7 @@
                         }
                         return Symbol{};
 
-                    case core::Function::kTextureSampleBaseClampToEdge:
+                    case core::BuiltinFn::kTextureSampleBaseClampToEdge:
                         if (cfg.builtins.texture_sample_base_clamp_to_edge_2d_f32) {
                             auto& sig = builtin->Signature();
                             auto* tex = sig.Parameter(core::ParameterUsage::kTexture);
@@ -1213,7 +1213,7 @@
                         }
                         return Symbol{};
 
-                    case core::Function::kTextureStore:
+                    case core::BuiltinFn::kTextureStore:
                         if (cfg.builtins.bgra8unorm) {
                             auto& sig = builtin->Signature();
                             auto* tex = sig.Parameter(core::ParameterUsage::kTexture);
@@ -1231,7 +1231,7 @@
                                             args.Push(arg);
                                         }
                                         return ctx.dst->Call(
-                                            tint::ToString(core::Function::kTextureStore),
+                                            tint::ToString(core::BuiltinFn::kTextureStore),
                                             std::move(args));
                                     });
                                     made_changes = true;
@@ -1240,7 +1240,7 @@
                         }
                         return Symbol{};
 
-                    case core::Function::kQuantizeToF16:
+                    case core::BuiltinFn::kQuantizeToF16:
                         if (cfg.builtins.quantize_to_vec_f16) {
                             if (auto* vec = builtin->ReturnType()->As<core::type::Vector>()) {
                                 return builtin_polyfills.GetOrCreate(
@@ -1249,7 +1249,7 @@
                         }
                         return Symbol{};
 
-                    case core::Function::kWorkgroupUniformLoad:
+                    case core::BuiltinFn::kWorkgroupUniformLoad:
                         if (cfg.builtins.workgroup_uniform_load) {
                             return builtin_polyfills.GetOrCreate(builtin, [&] {
                                 return workgroupUniformLoad(builtin->ReturnType());
diff --git a/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc b/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc
index f3f16ff..021ac65 100644
--- a/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc
+++ b/src/tint/lang/wgsl/ast/transform/demote_to_helper.cc
@@ -149,17 +149,17 @@
                 auto* sem_call = sem.Get<sem::Call>(call);
                 auto* stmt = sem_call ? sem_call->Stmt() : nullptr;
                 auto* func = stmt ? stmt->Function() : nullptr;
-                auto* builtin = sem_call ? sem_call->Target()->As<sem::Builtin>() : nullptr;
+                auto* builtin = sem_call ? sem_call->Target()->As<sem::BuiltinFn>() : nullptr;
                 if (functions_to_process.count(func) == 0 || !builtin) {
                     return;
                 }
 
-                if (builtin->Type() == core::Function::kTextureStore) {
+                if (builtin->Fn() == core::BuiltinFn::kTextureStore) {
                     // A call to textureStore() will always be a statement.
                     // Wrap it inside a conditional block.
                     auto* masked_call = b.If(b.Not(flag), b.Block(ctx.Clone(stmt->Declaration())));
                     ctx.Replace(stmt->Declaration(), masked_call);
-                } else if (builtin->IsAtomic() && builtin->Type() != core::Function::kAtomicLoad) {
+                } else if (builtin->IsAtomic() && builtin->Fn() != core::BuiltinFn::kAtomicLoad) {
                     // A call to an atomic builtin can be a statement or an expression.
                     if (auto* call_stmt = stmt->Declaration()->As<CallStatement>();
                         call_stmt && call_stmt->expr == call) {
@@ -180,7 +180,7 @@
                         auto result = b.Sym();
                         Type result_ty;
                         const Statement* masked_call = nullptr;
-                        if (builtin->Type() == core::Function::kAtomicCompareExchangeWeak) {
+                        if (builtin->Fn() == core::BuiltinFn::kAtomicCompareExchangeWeak) {
                             // Special case for atomicCompareExchangeWeak as we cannot name its
                             // result type. We have to declare an equivalent struct and copy the
                             // original member values over to it.
diff --git a/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc b/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
index 1d68454..757ad37 100644
--- a/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
+++ b/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.cc
@@ -190,11 +190,11 @@
         // functions.
         ctx.ReplaceAll([&](const CallExpression* expr) -> const CallExpression* {
             auto* call = sem.Get(expr)->UnwrapMaterialize()->As<sem::Call>();
-            auto* builtin = call->Target()->As<sem::Builtin>();
+            auto* builtin = call->Target()->As<sem::BuiltinFn>();
 
             if (builtin && !builtin->Parameters().IsEmpty() &&
                 builtin->Parameters()[0]->Type()->Is<core::type::ExternalTexture>() &&
-                builtin->Type() != core::Function::kTextureDimensions) {
+                builtin->Fn() != core::BuiltinFn::kTextureDimensions) {
                 if (auto* var_user =
                         sem.GetVal(expr->args[0])->UnwrapLoad()->As<sem::VariableUser>()) {
                     auto it = new_binding_symbols.find(var_user->Variable());
@@ -207,10 +207,10 @@
                     }
                     auto& syms = it->second;
 
-                    switch (builtin->Type()) {
-                        case core::Function::kTextureLoad:
+                    switch (builtin->Fn()) {
+                        case core::BuiltinFn::kTextureLoad:
                             return createTextureLoad(call, syms);
-                        case core::Function::kTextureSampleBaseClampToEdge:
+                        case core::BuiltinFn::kTextureSampleBaseClampToEdge:
                             return createTextureSampleBaseClampToEdge(expr, syms);
                         default:
                             break;
@@ -309,13 +309,13 @@
     /// builtin function.
     /// @param call_type determines which function body to generate
     /// @returns a statement list that makes of the body of the chosen function
-    auto buildTextureBuiltinBody(core::Function call_type) {
+    auto buildTextureBuiltinBody(core::BuiltinFn call_type) {
         tint::Vector<const Statement*, 16> stmts;
         const CallExpression* single_plane_call = nullptr;
         const CallExpression* plane_0_call = nullptr;
         const CallExpression* plane_1_call = nullptr;
         switch (call_type) {
-            case core::Function::kTextureSampleBaseClampToEdge:
+            case core::BuiltinFn::kTextureSampleBaseClampToEdge:
                 stmts.Push(b.Decl(b.Let(
                     "modifiedCoords", b.Mul(b.MemberAccessor("params", "coordTransformationMatrix"),
                                             b.Call<vec3<f32>>("coord", 1_a)))));
@@ -345,7 +345,7 @@
                 // textureSampleLevel(plane1, smp, plane1_clamped, 0.0);
                 plane_1_call = b.Call("textureSampleLevel", "plane1", "smp", "plane1_clamped", 0_a);
                 break;
-            case core::Function::kTextureLoad:
+            case core::BuiltinFn::kTextureLoad:
                 // textureLoad(plane0, coord, 0);
                 single_plane_call = b.Call("textureLoad", "plane0", "coord", 0_a);
                 // textureLoad(plane0, coord, 0);
@@ -439,7 +439,7 @@
                        b.Param("params", b.ty(params_struct_sym)),
                    },
                    b.ty.vec4(b.ty.f32()),
-                   buildTextureBuiltinBody(core::Function::kTextureSampleBaseClampToEdge));
+                   buildTextureBuiltinBody(core::BuiltinFn::kTextureSampleBaseClampToEdge));
         }
 
         return b.Call(texture_sample_external_sym, tint::Vector{
@@ -486,7 +486,7 @@
                        b.Param("params", b.ty(params_struct_sym)),
                    },
                    b.ty.vec4(b.ty.f32()),  //
-                   buildTextureBuiltinBody(core::Function::kTextureLoad));
+                   buildTextureBuiltinBody(core::BuiltinFn::kTextureLoad));
 
             return name;
         });
diff --git a/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.h b/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.h
index 189c06d..1c429ce 100644
--- a/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.h
+++ b/src/tint/lang/wgsl/ast/transform/multiplanar_external_texture.h
@@ -20,7 +20,7 @@
 
 #include "src/tint/api/common/binding_point.h"
 #include "src/tint/api/options/external_texture.h"
-#include "src/tint/lang/core/function.h"
+#include "src/tint/lang/core/builtin_fn.h"
 #include "src/tint/lang/wgsl/ast/struct_member.h"
 #include "src/tint/lang/wgsl/ast/transform/transform.h"
 
diff --git a/src/tint/lang/wgsl/ast/transform/remove_phonies.cc b/src/tint/lang/wgsl/ast/transform/remove_phonies.cc
index 4a6a392..7f7f7c6 100644
--- a/src/tint/lang/wgsl/ast/transform/remove_phonies.cc
+++ b/src/tint/lang/wgsl/ast/transform/remove_phonies.cc
@@ -71,7 +71,7 @@
                                 // have side effects. Just skip.
                                 return TraverseAction::Skip;
                             }
-                            if (call->Target()->IsAnyOf<sem::Function, sem::Builtin>() &&
+                            if (call->Target()->IsAnyOf<sem::Function, sem::BuiltinFn>() &&
                                 call->HasSideEffects()) {
                                 side_effects.push_back(expr);
                                 return TraverseAction::Skip;
diff --git a/src/tint/lang/wgsl/ast/transform/renamer.cc b/src/tint/lang/wgsl/ast/transform/renamer.cc
index af66929..ea456df 100644
--- a/src/tint/lang/wgsl/ast/transform/renamer.cc
+++ b/src/tint/lang/wgsl/ast/transform/renamer.cc
@@ -1315,7 +1315,7 @@
             [&](const CallExpression* call) {
                 Switch(
                     src->Sem().Get(call)->UnwrapMaterialize()->As<sem::Call>()->Target(),
-                    [&](const sem::Builtin*) {
+                    [&](const sem::BuiltinFn*) {
                         preserved_identifiers.Add(call->target->identifier);
                     },
                     [&](const sem::ValueConversion*) {
diff --git a/src/tint/lang/wgsl/ast/transform/robustness.cc b/src/tint/lang/wgsl/ast/transform/robustness.cc
index 8a60ff8..89b442a 100644
--- a/src/tint/lang/wgsl/ast/transform/robustness.cc
+++ b/src/tint/lang/wgsl/ast/transform/robustness.cc
@@ -24,7 +24,7 @@
 #include "src/tint/lang/wgsl/program/program_builder.h"
 #include "src/tint/lang/wgsl/resolver/resolve.h"
 #include "src/tint/lang/wgsl/sem/block_statement.h"
-#include "src/tint/lang/wgsl/sem/builtin.h"
+#include "src/tint/lang/wgsl/sem/builtin_fn.h"
 #include "src/tint/lang/wgsl/sem/call.h"
 #include "src/tint/lang/wgsl/sem/function.h"
 #include "src/tint/lang/wgsl/sem/index_accessor_expression.h"
@@ -139,7 +139,7 @@
                     if (auto* call = sem.Get<sem::Call>(e)) {
                         Switch(
                             call->Target(),  //
-                            [&](const sem::Builtin* builtin) {
+                            [&](const sem::BuiltinFn* builtin) {
                                 // Calls to builtins may require robustness transformation.
                                 // Inspect.
                                 if (builtin->IsTexture()) {
@@ -246,7 +246,7 @@
                     // Must clamp, even if the index is constant.
 
                     auto* arr_ptr = b.AddressOf(ctx.Clone(expr->Object()->Declaration()));
-                    return b.Sub(b.Call(core::Function::kArrayLength, arr_ptr), 1_u);
+                    return b.Sub(b.Call(core::BuiltinFn::kArrayLength, arr_ptr), 1_u);
                 }
                 if (auto count = arr->ConstantCount()) {
                     if (expr->Index()->ConstantValue()) {
@@ -352,12 +352,12 @@
 
         auto* expr_sem = expr->Unwrap()->As<sem::IndexAccessorExpression>();
         auto idx = CastToU32(expr_sem->Index());
-        auto* clamped_idx = b.Call(core::Function::kMin, idx, max);
+        auto* clamped_idx = b.Call(core::BuiltinFn::kMin, idx, max);
         ctx.Replace(expr->Declaration()->index, clamped_idx);
     }
 
     /// Applies predication to the non-texture builtin call, if required.
-    void MaybePredicateNonTextureBuiltin(const sem::Call* call, const sem::Builtin* builtin) {
+    void MaybePredicateNonTextureBuiltin(const sem::Call* call, const sem::BuiltinFn* builtin) {
         // Gather the predications for the builtin arguments
         const Expression* predicate = nullptr;
         for (auto* arg : call->Declaration()->args) {
@@ -367,14 +367,14 @@
         }
 
         if (predicate) {
-            if (builtin->Type() == core::Function::kWorkgroupUniformLoad) {
+            if (builtin->Fn() == core::BuiltinFn::kWorkgroupUniformLoad) {
                 // https://www.w3.org/TR/WGSL/#workgroupUniformLoad-builtin:
                 //  "Executes a control barrier synchronization function that affects memory and
                 //   atomic operations in the workgroup address space."
                 // Because the call acts like a control barrier, we need to make sure that we still
                 // trigger a workgroup barrier if the predicate fails.
                 PredicateCall(call, predicate,
-                              b.Block(b.CallStmt(b.Call(core::Function::kWorkgroupBarrier))));
+                              b.Block(b.CallStmt(b.Call(core::BuiltinFn::kWorkgroupBarrier))));
             } else {
                 PredicateCall(call, predicate);
             }
@@ -383,8 +383,8 @@
 
     /// Applies predication to texture builtins, based on whether the coordinates, array index and
     /// level arguments are all in bounds.
-    void PredicateTextureBuiltin(const sem::Call* call, const sem::Builtin* builtin) {
-        if (!TextureBuiltinNeedsRobustness(builtin->Type())) {
+    void PredicateTextureBuiltin(const sem::Call* call, const sem::BuiltinFn* builtin) {
+        if (!TextureBuiltinNeedsRobustness(builtin->Fn())) {
             return;
         }
 
@@ -417,7 +417,7 @@
                 // let num_levels = textureNumLevels(texture-arg);
                 num_levels = b.Symbols().New("num_levels");
                 hoist.InsertBefore(
-                    stmt, b.Decl(b.Let(num_levels, b.Call(core::Function::kTextureNumLevels,
+                    stmt, b.Decl(b.Let(num_levels, b.Call(core::BuiltinFn::kTextureNumLevels,
                                                           ctx.Clone(texture_arg)))));
 
                 // predicate: level_idx < num_levels
@@ -442,12 +442,12 @@
                 // predicate: all(coords < textureDimensions(texture))
                 auto* dimensions =
                     level_idx.IsValid()
-                        ? b.Call(core::Function::kTextureDimensions, ctx.Clone(texture_arg),
-                                 b.Call(core::Function::kMin, b.Expr(level_idx),
+                        ? b.Call(core::BuiltinFn::kTextureDimensions, ctx.Clone(texture_arg),
+                                 b.Call(core::BuiltinFn::kMin, b.Expr(level_idx),
                                         b.Sub(num_levels, 1_a)))
-                        : b.Call(core::Function::kTextureDimensions, ctx.Clone(texture_arg));
+                        : b.Call(core::BuiltinFn::kTextureDimensions, ctx.Clone(texture_arg));
                 predicate =
-                    And(predicate, b.Call(core::Function::kAll, b.LessThan(coords, dimensions)));
+                    And(predicate, b.Call(core::BuiltinFn::kAll, b.LessThan(coords, dimensions)));
 
                 // Replace the level argument with `coord`
                 ctx.Replace(arg, b.Expr(coords));
@@ -457,7 +457,7 @@
         if (array_arg_idx >= 0) {
             // let array_idx = u32(array-arg)
             auto* arg = expr->args[static_cast<size_t>(array_arg_idx)];
-            auto* num_layers = b.Call(core::Function::kTextureNumLayers, ctx.Clone(texture_arg));
+            auto* num_layers = b.Call(core::BuiltinFn::kTextureNumLayers, ctx.Clone(texture_arg));
             auto array_idx = b.Symbols().New("array_idx");
             hoist.InsertBefore(stmt, b.Decl(b.Let(array_idx, CastToUnsigned(ctx.Clone(arg), 1u))));
 
@@ -475,8 +475,8 @@
 
     /// Applies bounds clamping to the coordinates, array index and level arguments of the texture
     /// builtin.
-    void ClampTextureBuiltin(const sem::Call* call, const sem::Builtin* builtin) {
-        if (!TextureBuiltinNeedsRobustness(builtin->Type())) {
+    void ClampTextureBuiltin(const sem::Call* call, const sem::BuiltinFn* builtin) {
+        if (!TextureBuiltinNeedsRobustness(builtin->Fn())) {
             return;
         }
 
@@ -502,10 +502,10 @@
                 const auto* arg = expr->args[static_cast<size_t>(level_arg_idx)];
                 level_idx = b.Symbols().New("level_idx");
                 const auto* num_levels =
-                    b.Call(core::Function::kTextureNumLevels, ctx.Clone(texture_arg));
+                    b.Call(core::BuiltinFn::kTextureNumLevels, ctx.Clone(texture_arg));
                 const auto* max = b.Sub(num_levels, 1_a);
                 hoist.InsertBefore(
-                    stmt, b.Decl(b.Let(level_idx, b.Call(core::Function::kMin,
+                    stmt, b.Decl(b.Let(level_idx, b.Call(core::BuiltinFn::kMin,
                                                          b.Call<u32>(ctx.Clone(arg)), max))));
                 ctx.Replace(arg, b.Expr(level_idx));
             }
@@ -519,9 +519,9 @@
                 const auto width = WidthOf(param->Type());
                 const auto* dimensions =
                     level_idx.IsValid()
-                        ? b.Call(core::Function::kTextureDimensions, ctx.Clone(texture_arg),
+                        ? b.Call(core::BuiltinFn::kTextureDimensions, ctx.Clone(texture_arg),
                                  level_idx)
-                        : b.Call(core::Function::kTextureDimensions, ctx.Clone(texture_arg));
+                        : b.Call(core::BuiltinFn::kTextureDimensions, ctx.Clone(texture_arg));
 
                 // dimensions is u32 or vecN<u32>
                 const auto* unsigned_max = b.Sub(dimensions, ScalarOrVec(b.Expr(1_a), width));
@@ -529,9 +529,9 @@
                     const auto* zero = ScalarOrVec(b.Expr(0_a), width);
                     const auto* signed_max = CastToSigned(unsigned_max, width);
                     ctx.Replace(arg,
-                                b.Call(core::Function::kClamp, ctx.Clone(arg), zero, signed_max));
+                                b.Call(core::BuiltinFn::kClamp, ctx.Clone(arg), zero, signed_max));
                 } else {
-                    ctx.Replace(arg, b.Call(core::Function::kMin, ctx.Clone(arg), unsigned_max));
+                    ctx.Replace(arg, b.Call(core::BuiltinFn::kMin, ctx.Clone(arg), unsigned_max));
                 }
             }
         }
@@ -540,14 +540,14 @@
         if (array_arg_idx >= 0) {
             auto* param = builtin->Parameters()[static_cast<size_t>(array_arg_idx)];
             auto* arg = expr->args[static_cast<size_t>(array_arg_idx)];
-            auto* num_layers = b.Call(core::Function::kTextureNumLayers, ctx.Clone(texture_arg));
+            auto* num_layers = b.Call(core::BuiltinFn::kTextureNumLayers, ctx.Clone(texture_arg));
 
             const auto* unsigned_max = b.Sub(num_layers, 1_a);
             if (param->Type()->is_signed_integer_scalar()) {
                 const auto* signed_max = CastToSigned(unsigned_max, 1u);
-                ctx.Replace(arg, b.Call(core::Function::kClamp, ctx.Clone(arg), 0_a, signed_max));
+                ctx.Replace(arg, b.Call(core::BuiltinFn::kClamp, ctx.Clone(arg), 0_a, signed_max));
             } else {
-                ctx.Replace(arg, b.Call(core::Function::kMin, ctx.Clone(arg), unsigned_max));
+                ctx.Replace(arg, b.Call(core::BuiltinFn::kMin, ctx.Clone(arg), unsigned_max));
             }
         }
     }
@@ -555,9 +555,9 @@
     /// @param type builtin type
     /// @returns true if the given builtin is a texture function that requires predication or
     /// clamping of arguments.
-    bool TextureBuiltinNeedsRobustness(core::Function type) {
-        return type == core::Function::kTextureLoad || type == core::Function::kTextureStore ||
-               type == core::Function::kTextureDimensions;
+    bool TextureBuiltinNeedsRobustness(core::BuiltinFn type) {
+        return type == core::BuiltinFn::kTextureLoad || type == core::BuiltinFn::kTextureStore ||
+               type == core::BuiltinFn::kTextureDimensions;
     }
 
     /// @returns a bitwise and of the two expressions, or the other expression if one is null.
diff --git a/src/tint/lang/wgsl/ast/transform/substitute_override.cc b/src/tint/lang/wgsl/ast/transform/substitute_override.cc
index ffd3960..0ffcafb 100644
--- a/src/tint/lang/wgsl/ast/transform/substitute_override.cc
+++ b/src/tint/lang/wgsl/ast/transform/substitute_override.cc
@@ -17,12 +17,12 @@
 #include <functional>
 #include <utility>
 
+#include "src/tint/lang/core/builtin_fn.h"
 #include "src/tint/lang/core/fluent_types.h"
-#include "src/tint/lang/core/function.h"
 #include "src/tint/lang/wgsl/program/clone_context.h"
 #include "src/tint/lang/wgsl/program/program_builder.h"
 #include "src/tint/lang/wgsl/resolver/resolve.h"
-#include "src/tint/lang/wgsl/sem/builtin.h"
+#include "src/tint/lang/wgsl/sem/builtin_fn.h"
 #include "src/tint/lang/wgsl/sem/index_accessor_expression.h"
 #include "src/tint/lang/wgsl/sem/variable.h"
 #include "src/tint/utils/rtti/switch.h"
@@ -111,7 +111,7 @@
             if (auto* access = sem->UnwrapMaterialize()->As<sem::IndexAccessorExpression>()) {
                 if (access->Object()->UnwrapMaterialize()->Type()->HoldsAbstract() &&
                     access->Index()->Stage() == core::EvaluationStage::kOverride) {
-                    auto* obj = b.Call(core::str(core::Function::kTintMaterialize),
+                    auto* obj = b.Call(core::str(core::BuiltinFn::kTintMaterialize),
                                        ctx.Clone(expr->object));
                     return b.IndexAccessor(obj, ctx.Clone(expr->index));
                 }
diff --git a/src/tint/lang/wgsl/inspector/inspector.cc b/src/tint/lang/wgsl/inspector/inspector.cc
index 48cc3b7..ee3dd29 100644
--- a/src/tint/lang/wgsl/inspector/inspector.cc
+++ b/src/tint/lang/wgsl/inspector/inspector.cc
@@ -774,7 +774,7 @@
             continue;
         }
 
-        auto* i = call->Target()->As<sem::Builtin>();
+        auto* i = call->Target()->As<sem::BuiltinFn>();
         if (!i) {
             continue;
         }
diff --git a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
index 4850db3..49babb3 100644
--- a/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
+++ b/src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.cc
@@ -85,7 +85,7 @@
 #include "src/tint/lang/wgsl/ast/variable_decl_statement.h"
 #include "src/tint/lang/wgsl/ast/while_statement.h"
 #include "src/tint/lang/wgsl/program/program.h"
-#include "src/tint/lang/wgsl/sem/builtin.h"
+#include "src/tint/lang/wgsl/sem/builtin_fn.h"
 #include "src/tint/lang/wgsl/sem/call.h"
 #include "src/tint/lang/wgsl/sem/function.h"
 #include "src/tint/lang/wgsl/sem/index_accessor_expression.h"
@@ -1097,8 +1097,8 @@
                 auto* ty = sem->Target()->ReturnType()->Clone(impl.clone_ctx_.type_ctx);
                 core::ir::Instruction* inst = nullptr;
                 // If this is a builtin function, emit the specific builtin value
-                if (auto* b = sem->Target()->As<sem::Builtin>()) {
-                    inst = impl.builder_.Call(ty, b->Type(), args);
+                if (auto* b = sem->Target()->As<sem::BuiltinFn>()) {
+                    inst = impl.builder_.Call(ty, b->Fn(), args);
                 } else if (sem->Target()->As<sem::ValueConstructor>()) {
                     inst = impl.builder_.Construct(ty, std::move(args));
                 } else if (sem->Target()->Is<sem::ValueConversion>()) {
diff --git a/src/tint/lang/wgsl/resolver/builtin_test.cc b/src/tint/lang/wgsl/resolver/builtin_test.cc
index 1ec3b5f..f4175a8 100644
--- a/src/tint/lang/wgsl/resolver/builtin_test.cc
+++ b/src/tint/lang/wgsl/resolver/builtin_test.cc
@@ -55,7 +55,7 @@
 
 struct BuiltinData {
     const char* name;
-    core::Function builtin;
+    core::BuiltinFn builtin;
 };
 
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
@@ -78,9 +78,9 @@
     // let a = select(1_i, 2_i, true);
     // let b = select(3_i, 4_i, false);
     // let c = select(5_u, 6_u, true);
-    auto* select_a = Call(core::Function::kSelect, 1_i, 2_i, true);
-    auto* select_b = Call(core::Function::kSelect, 3_i, 4_i, false);
-    auto* select_c = Call(core::Function::kSelect, 5_u, 6_u, true);
+    auto* select_a = Call(core::BuiltinFn::kSelect, 1_i, 2_i, true);
+    auto* select_b = Call(core::BuiltinFn::kSelect, 3_i, 4_i, false);
+    auto* select_c = Call(core::BuiltinFn::kSelect, 5_u, 6_u, true);
     WrapInFunction(Decl(Let("i", Expr(42_i))),  //
                    Decl(Let("a", select_a)),    //
                    Decl(Let("b", select_b)),    //
@@ -273,7 +273,7 @@
 struct BuiltinDataWithParamNum {
     uint32_t args_number;
     const char* name;
-    core::Function builtin;
+    core::BuiltinFn builtin;
 };
 
 inline std::ostream& operator<<(std::ostream& out, BuiltinDataWithParamNum data) {
@@ -700,55 +700,55 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverTest,
     ResolverBuiltinTest_FloatBuiltin_IdenticalType,
-    testing::Values(BuiltinDataWithParamNum{1, "abs", core::Function::kAbs},
-                    BuiltinDataWithParamNum{1, "acos", core::Function::kAcos},
-                    BuiltinDataWithParamNum{1, "acosh", core::Function::kAcos},
-                    BuiltinDataWithParamNum{1, "asin", core::Function::kAsin},
-                    BuiltinDataWithParamNum{1, "asinh", core::Function::kAsin},
-                    BuiltinDataWithParamNum{1, "atan", core::Function::kAtan},
-                    BuiltinDataWithParamNum{1, "atanh", core::Function::kAtan},
-                    BuiltinDataWithParamNum{2, "atan2", core::Function::kAtan2},
-                    BuiltinDataWithParamNum{1, "ceil", core::Function::kCeil},
-                    BuiltinDataWithParamNum{3, "clamp", core::Function::kClamp},
-                    BuiltinDataWithParamNum{1, "cos", core::Function::kCos},
-                    BuiltinDataWithParamNum{1, "cosh", core::Function::kCosh},
+    testing::Values(BuiltinDataWithParamNum{1, "abs", core::BuiltinFn::kAbs},
+                    BuiltinDataWithParamNum{1, "acos", core::BuiltinFn::kAcos},
+                    BuiltinDataWithParamNum{1, "acosh", core::BuiltinFn::kAcos},
+                    BuiltinDataWithParamNum{1, "asin", core::BuiltinFn::kAsin},
+                    BuiltinDataWithParamNum{1, "asinh", core::BuiltinFn::kAsin},
+                    BuiltinDataWithParamNum{1, "atan", core::BuiltinFn::kAtan},
+                    BuiltinDataWithParamNum{1, "atanh", core::BuiltinFn::kAtan},
+                    BuiltinDataWithParamNum{2, "atan2", core::BuiltinFn::kAtan2},
+                    BuiltinDataWithParamNum{1, "ceil", core::BuiltinFn::kCeil},
+                    BuiltinDataWithParamNum{3, "clamp", core::BuiltinFn::kClamp},
+                    BuiltinDataWithParamNum{1, "cos", core::BuiltinFn::kCos},
+                    BuiltinDataWithParamNum{1, "cosh", core::BuiltinFn::kCosh},
                     // cross: (vec3<T>, vec3<T>) -> vec3<T>
-                    BuiltinDataWithParamNum{1, "degrees", core::Function::kDegrees},
+                    BuiltinDataWithParamNum{1, "degrees", core::BuiltinFn::kDegrees},
                     // distance: (T, T) -> T, (vecN<T>, vecN<T>) -> T
-                    BuiltinDataWithParamNum{1, "exp", core::Function::kExp},
-                    BuiltinDataWithParamNum{1, "exp2", core::Function::kExp2},
+                    BuiltinDataWithParamNum{1, "exp", core::BuiltinFn::kExp},
+                    BuiltinDataWithParamNum{1, "exp2", core::BuiltinFn::kExp2},
                     // faceForward: (vecN<T>, vecN<T>, vecN<T>) -> vecN<T>
-                    BuiltinDataWithParamNum{1, "floor", core::Function::kFloor},
-                    BuiltinDataWithParamNum{3, "fma", core::Function::kFma},
-                    BuiltinDataWithParamNum{1, "fract", core::Function::kFract},
+                    BuiltinDataWithParamNum{1, "floor", core::BuiltinFn::kFloor},
+                    BuiltinDataWithParamNum{3, "fma", core::BuiltinFn::kFma},
+                    BuiltinDataWithParamNum{1, "fract", core::BuiltinFn::kFract},
                     // frexp
-                    BuiltinDataWithParamNum{1, "inverseSqrt", core::Function::kInverseSqrt},
+                    BuiltinDataWithParamNum{1, "inverseSqrt", core::BuiltinFn::kInverseSqrt},
                     // ldexp: (T, i32) -> T, (vecN<T>, vecN<i32>) -> vecN<T>
                     // length: (vecN<T>) -> T
-                    BuiltinDataWithParamNum{1, "log", core::Function::kLog},
-                    BuiltinDataWithParamNum{1, "log2", core::Function::kLog2},
-                    BuiltinDataWithParamNum{2, "max", core::Function::kMax},
-                    BuiltinDataWithParamNum{2, "min", core::Function::kMin},
+                    BuiltinDataWithParamNum{1, "log", core::BuiltinFn::kLog},
+                    BuiltinDataWithParamNum{1, "log2", core::BuiltinFn::kLog2},
+                    BuiltinDataWithParamNum{2, "max", core::BuiltinFn::kMax},
+                    BuiltinDataWithParamNum{2, "min", core::BuiltinFn::kMin},
                     // Note that `mix(vecN<f32>, vecN<f32>, f32) -> vecN<f32>` is not tested here.
-                    BuiltinDataWithParamNum{3, "mix", core::Function::kMix},
+                    BuiltinDataWithParamNum{3, "mix", core::BuiltinFn::kMix},
                     // modf
                     // normalize: (vecN<T>) -> vecN<T>
-                    BuiltinDataWithParamNum{2, "pow", core::Function::kPow},
+                    BuiltinDataWithParamNum{2, "pow", core::BuiltinFn::kPow},
                     // quantizeToF16 is not implemented yet.
-                    BuiltinDataWithParamNum{1, "radians", core::Function::kRadians},
+                    BuiltinDataWithParamNum{1, "radians", core::BuiltinFn::kRadians},
                     // reflect: (vecN<T>, vecN<T>) -> vecN<T>
                     // refract: (vecN<T>, vecN<T>, T) -> vecN<T>
-                    BuiltinDataWithParamNum{1, "round", core::Function::kRound},
+                    BuiltinDataWithParamNum{1, "round", core::BuiltinFn::kRound},
                     // saturate not implemented yet.
-                    BuiltinDataWithParamNum{1, "sign", core::Function::kSign},
-                    BuiltinDataWithParamNum{1, "sin", core::Function::kSin},
-                    BuiltinDataWithParamNum{1, "sinh", core::Function::kSinh},
-                    BuiltinDataWithParamNum{3, "smoothstep", core::Function::kSmoothstep},
-                    BuiltinDataWithParamNum{1, "sqrt", core::Function::kSqrt},
-                    BuiltinDataWithParamNum{2, "step", core::Function::kStep},
-                    BuiltinDataWithParamNum{1, "tan", core::Function::kTan},
-                    BuiltinDataWithParamNum{1, "tanh", core::Function::kTanh},
-                    BuiltinDataWithParamNum{1, "trunc", core::Function::kTrunc}));
+                    BuiltinDataWithParamNum{1, "sign", core::BuiltinFn::kSign},
+                    BuiltinDataWithParamNum{1, "sin", core::BuiltinFn::kSin},
+                    BuiltinDataWithParamNum{1, "sinh", core::BuiltinFn::kSinh},
+                    BuiltinDataWithParamNum{3, "smoothstep", core::BuiltinFn::kSmoothstep},
+                    BuiltinDataWithParamNum{1, "sqrt", core::BuiltinFn::kSqrt},
+                    BuiltinDataWithParamNum{2, "step", core::BuiltinFn::kStep},
+                    BuiltinDataWithParamNum{1, "tan", core::BuiltinFn::kTan},
+                    BuiltinDataWithParamNum{1, "tanh", core::BuiltinFn::kTanh},
+                    BuiltinDataWithParamNum{1, "trunc", core::BuiltinFn::kTrunc}));
 
 using ResolverBuiltinFloatTest = ResolverTest;
 
@@ -1430,7 +1430,7 @@
 struct BuiltinDataWithParamNum {
     uint32_t args_number;
     const char* name;
-    core::Function builtin;
+    core::BuiltinFn builtin;
 };
 
 inline std::ostream& operator<<(std::ostream& out, BuiltinDataWithParamNum data) {
@@ -1826,18 +1826,18 @@
     ResolverTest,
     ResolverBuiltinTest_IntegerBuiltin_IdenticalType,
     testing::Values(
-        BuiltinDataWithParamNum{1, "abs", core::Function::kAbs},
-        BuiltinDataWithParamNum{3, "clamp", core::Function::kClamp},
-        BuiltinDataWithParamNum{1, "countLeadingZeros", core::Function::kCountLeadingZeros},
-        BuiltinDataWithParamNum{1, "countOneBits", core::Function::kCountOneBits},
-        BuiltinDataWithParamNum{1, "countTrailingZeros", core::Function::kCountTrailingZeros},
+        BuiltinDataWithParamNum{1, "abs", core::BuiltinFn::kAbs},
+        BuiltinDataWithParamNum{3, "clamp", core::BuiltinFn::kClamp},
+        BuiltinDataWithParamNum{1, "countLeadingZeros", core::BuiltinFn::kCountLeadingZeros},
+        BuiltinDataWithParamNum{1, "countOneBits", core::BuiltinFn::kCountOneBits},
+        BuiltinDataWithParamNum{1, "countTrailingZeros", core::BuiltinFn::kCountTrailingZeros},
         // extractBits: (T, u32, u32) -> T
-        BuiltinDataWithParamNum{1, "firstLeadingBit", core::Function::kFirstLeadingBit},
-        BuiltinDataWithParamNum{1, "firstTrailingBit", core::Function::kFirstTrailingBit},
+        BuiltinDataWithParamNum{1, "firstLeadingBit", core::BuiltinFn::kFirstLeadingBit},
+        BuiltinDataWithParamNum{1, "firstTrailingBit", core::BuiltinFn::kFirstTrailingBit},
         // insertBits: (T, T, u32, u32) -> T
-        BuiltinDataWithParamNum{2, "max", core::Function::kMax},
-        BuiltinDataWithParamNum{2, "min", core::Function::kMin},
-        BuiltinDataWithParamNum{1, "reverseBits", core::Function::kReverseBits}));
+        BuiltinDataWithParamNum{2, "max", core::BuiltinFn::kMax},
+        BuiltinDataWithParamNum{2, "min", core::BuiltinFn::kMin},
+        BuiltinDataWithParamNum{1, "reverseBits", core::BuiltinFn::kReverseBits}));
 
 }  // namespace integer_builtin_tests
 
@@ -2576,8 +2576,8 @@
 TEST_P(ResolverBuiltinTest_DataPacking, InferType) {
     auto param = GetParam();
 
-    bool pack4 = param.builtin == core::Function::kPack4X8Snorm ||
-                 param.builtin == core::Function::kPack4X8Unorm;
+    bool pack4 = param.builtin == core::BuiltinFn::kPack4X8Snorm ||
+                 param.builtin == core::BuiltinFn::kPack4X8Unorm;
 
     auto* call = pack4 ? Call(param.name, Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f))
                        : Call(param.name, Call<vec2<f32>>(1_f, 2_f));
@@ -2591,8 +2591,8 @@
 TEST_P(ResolverBuiltinTest_DataPacking, Error_IncorrectParamType) {
     auto param = GetParam();
 
-    bool pack4 = param.builtin == core::Function::kPack4X8Snorm ||
-                 param.builtin == core::Function::kPack4X8Unorm;
+    bool pack4 = param.builtin == core::BuiltinFn::kPack4X8Snorm ||
+                 param.builtin == core::BuiltinFn::kPack4X8Unorm;
 
     auto* call = pack4 ? Call(param.name, Call<vec4<i32>>(1_i, 2_i, 3_i, 4_i))
                        : Call(param.name, Call<vec2<i32>>(1_i, 2_i));
@@ -2617,8 +2617,8 @@
 TEST_P(ResolverBuiltinTest_DataPacking, Error_TooManyParams) {
     auto param = GetParam();
 
-    bool pack4 = param.builtin == core::Function::kPack4X8Snorm ||
-                 param.builtin == core::Function::kPack4X8Unorm;
+    bool pack4 = param.builtin == core::BuiltinFn::kPack4X8Snorm ||
+                 param.builtin == core::BuiltinFn::kPack4X8Unorm;
 
     auto* call = pack4 ? Call(param.name, Call<vec4<f32>>(1_f, 2_f, 3_f, 4_f), 1_f)
                        : Call(param.name, Call<vec2<f32>>(1_f, 2_f), 1_f);
@@ -2632,11 +2632,11 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverTest,
     ResolverBuiltinTest_DataPacking,
-    testing::Values(BuiltinData{"pack4x8snorm", core::Function::kPack4X8Snorm},
-                    BuiltinData{"pack4x8unorm", core::Function::kPack4X8Unorm},
-                    BuiltinData{"pack2x16snorm", core::Function::kPack2X16Snorm},
-                    BuiltinData{"pack2x16unorm", core::Function::kPack2X16Unorm},
-                    BuiltinData{"pack2x16float", core::Function::kPack2X16Float}));
+    testing::Values(BuiltinData{"pack4x8snorm", core::BuiltinFn::kPack4X8Snorm},
+                    BuiltinData{"pack4x8unorm", core::BuiltinFn::kPack4X8Unorm},
+                    BuiltinData{"pack2x16snorm", core::BuiltinFn::kPack2X16Snorm},
+                    BuiltinData{"pack2x16unorm", core::BuiltinFn::kPack2X16Unorm},
+                    BuiltinData{"pack2x16float", core::BuiltinFn::kPack2X16Float}));
 
 }  // namespace data_packing_builtin_tests
 
@@ -2647,8 +2647,8 @@
 TEST_P(ResolverBuiltinTest_DataUnpacking, InferType) {
     auto param = GetParam();
 
-    bool pack4 = param.builtin == core::Function::kUnpack4X8Snorm ||
-                 param.builtin == core::Function::kUnpack4X8Unorm;
+    bool pack4 = param.builtin == core::BuiltinFn::kUnpack4X8Snorm ||
+                 param.builtin == core::BuiltinFn::kUnpack4X8Unorm;
 
     auto* call = Call(param.name, 1_u);
     WrapInFunction(call);
@@ -2666,11 +2666,11 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverTest,
     ResolverBuiltinTest_DataUnpacking,
-    testing::Values(BuiltinData{"unpack4x8snorm", core::Function::kUnpack4X8Snorm},
-                    BuiltinData{"unpack4x8unorm", core::Function::kUnpack4X8Unorm},
-                    BuiltinData{"unpack2x16snorm", core::Function::kUnpack2X16Snorm},
-                    BuiltinData{"unpack2x16unorm", core::Function::kUnpack2X16Unorm},
-                    BuiltinData{"unpack2x16float", core::Function::kUnpack2X16Float}));
+    testing::Values(BuiltinData{"unpack4x8snorm", core::BuiltinFn::kUnpack4X8Snorm},
+                    BuiltinData{"unpack4x8unorm", core::BuiltinFn::kUnpack4X8Unorm},
+                    BuiltinData{"unpack2x16snorm", core::BuiltinFn::kUnpack2X16Snorm},
+                    BuiltinData{"unpack2x16unorm", core::BuiltinFn::kUnpack2X16Unorm},
+                    BuiltinData{"unpack2x16float", core::BuiltinFn::kUnpack2X16Float}));
 
 }  // namespace data_unpacking_builtin_tests
 
@@ -2703,8 +2703,8 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverTest,
     ResolverBuiltinTest_Barrier,
-    testing::Values(BuiltinData{"storageBarrier", core::Function::kStorageBarrier},
-                    BuiltinData{"workgroupBarrier", core::Function::kWorkgroupBarrier}));
+    testing::Values(BuiltinData{"storageBarrier", core::BuiltinFn::kStorageBarrier},
+                    BuiltinData{"workgroupBarrier", core::BuiltinFn::kWorkgroupBarrier}));
 
 }  // namespace synchronization_builtin_tests
 
diff --git a/src/tint/lang/wgsl/resolver/dependency_graph.cc b/src/tint/lang/wgsl/resolver/dependency_graph.cc
index db74547..32486a4 100644
--- a/src/tint/lang/wgsl/resolver/dependency_graph.cc
+++ b/src/tint/lang/wgsl/resolver/dependency_graph.cc
@@ -60,7 +60,7 @@
 #include "src/tint/lang/wgsl/ast/variable_decl_statement.h"
 #include "src/tint/lang/wgsl/ast/while_statement.h"
 #include "src/tint/lang/wgsl/ast/workgroup_attribute.h"
-#include "src/tint/lang/wgsl/sem/builtin.h"
+#include "src/tint/lang/wgsl/sem/builtin_fn.h"
 #include "src/tint/utils/containers/map.h"
 #include "src/tint/utils/containers/scope_stack.h"
 #include "src/tint/utils/containers/unique_vector.h"
@@ -474,7 +474,7 @@
 
         BuiltinType type = BuiltinType::kNone;
         std::variant<std::monostate,
-                     core::Function,
+                     core::BuiltinFn,
                      core::Builtin,
                      core::BuiltinValue,
                      core::AddressSpace,
@@ -490,8 +490,8 @@
     /// @returns the builtin info
     DependencyScanner::BuiltinInfo GetBuiltinInfo(Symbol symbol) {
         return builtin_info_map.GetOrCreate(symbol, [&] {
-            if (auto builtin_fn = core::ParseFunction(symbol.NameView());
-                builtin_fn != core::Function::kNone) {
+            if (auto builtin_fn = core::ParseBuiltinFn(symbol.NameView());
+                builtin_fn != core::BuiltinFn::kNone) {
                 return BuiltinInfo{BuiltinType::kFunction, builtin_fn};
             }
             if (auto builtin_ty = core::ParseBuiltin(symbol.NameView());
@@ -537,7 +537,7 @@
                     break;
                 case BuiltinType::kFunction:
                     graph_.resolved_identifiers.Add(
-                        from, ResolvedIdentifier(builtin_info.Value<core::Function>()));
+                        from, ResolvedIdentifier(builtin_info.Value<core::BuiltinFn>()));
                     break;
                 case BuiltinType::kBuiltin:
                     graph_.resolved_identifiers.Add(
@@ -921,7 +921,7 @@
                 return "<unknown>";
             });
     }
-    if (auto builtin_fn = BuiltinFunction(); builtin_fn != core::Function::kNone) {
+    if (auto builtin_fn = BuiltinFn(); builtin_fn != core::BuiltinFn::kNone) {
         return "builtin function '" + tint::ToString(builtin_fn) + "'";
     }
     if (auto builtin_ty = BuiltinType(); builtin_ty != core::Builtin::kUndefined) {
diff --git a/src/tint/lang/wgsl/resolver/dependency_graph.h b/src/tint/lang/wgsl/resolver/dependency_graph.h
index 7d145ba..a08ff7c 100644
--- a/src/tint/lang/wgsl/resolver/dependency_graph.h
+++ b/src/tint/lang/wgsl/resolver/dependency_graph.h
@@ -20,8 +20,8 @@
 
 #include "src/tint/lang/core/access.h"
 #include "src/tint/lang/core/builtin.h"
+#include "src/tint/lang/core/builtin_fn.h"
 #include "src/tint/lang/core/builtin_value.h"
-#include "src/tint/lang/core/function.h"
 #include "src/tint/lang/core/interpolation_sampling.h"
 #include "src/tint/lang/core/interpolation_type.h"
 #include "src/tint/lang/core/texel_format.h"
@@ -43,7 +43,7 @@
 /// - const ast::TypeDecl*  (as const ast::Node*)
 /// - const ast::Variable*  (as const ast::Node*)
 /// - const ast::Function*  (as const ast::Node*)
-/// - core::Function
+/// - core::BuiltinFn
 /// - core::Access
 /// - core::AddressSpace
 /// - core::Builtin
@@ -74,13 +74,13 @@
         return nullptr;
     }
 
-    /// @return the builtin function if the ResolvedIdentifier holds core::Function, otherwise
-    /// core::Function::kNone
-    core::Function BuiltinFunction() const {
-        if (auto n = std::get_if<core::Function>(&value_)) {
+    /// @return the builtin function if the ResolvedIdentifier holds core::BuiltinFn, otherwise
+    /// core::BuiltinFn::kNone
+    core::BuiltinFn BuiltinFn() const {
+        if (auto n = std::get_if<core::BuiltinFn>(&value_)) {
             return *n;
         }
-        return core::Function::kNone;
+        return core::BuiltinFn::kNone;
     }
 
     /// @return the access if the ResolvedIdentifier holds core::Access, otherwise
@@ -169,7 +169,7 @@
   private:
     std::variant<UnresolvedIdentifier,
                  const ast::Node*,
-                 core::Function,
+                 core::BuiltinFn,
                  core::Access,
                  core::AddressSpace,
                  core::Builtin,
diff --git a/src/tint/lang/wgsl/resolver/dependency_graph_test.cc b/src/tint/lang/wgsl/resolver/dependency_graph_test.cc
index a22669f..2eaa607 100644
--- a/src/tint/lang/wgsl/resolver/dependency_graph_test.cc
+++ b/src/tint/lang/wgsl/resolver/dependency_graph_test.cc
@@ -1177,10 +1177,10 @@
 ////////////////////////////////////////////////////////////////////////////////
 namespace resolve_to_builtin_func {
 
-using ResolverDependencyGraphResolveToBuiltinFunc =
-    ResolverDependencyGraphTestWithParam<std::tuple<SymbolUseKind, core::Function>>;
+using ResolverDependencyGraphResolveToBuiltinFn =
+    ResolverDependencyGraphTestWithParam<std::tuple<SymbolUseKind, core::BuiltinFn>>;
 
-TEST_P(ResolverDependencyGraphResolveToBuiltinFunc, Resolve) {
+TEST_P(ResolverDependencyGraphResolveToBuiltinFn, Resolve) {
     const auto use = std::get<0>(GetParam());
     const auto builtin = std::get<1>(GetParam());
     const auto symbol = Symbols().New(tint::ToString(builtin));
@@ -1191,23 +1191,23 @@
 
     auto resolved = Build().resolved_identifiers.Get(ident);
     ASSERT_TRUE(resolved);
-    EXPECT_EQ(resolved->BuiltinFunction(), builtin) << resolved->String();
+    EXPECT_EQ(resolved->BuiltinFn(), builtin) << resolved->String();
 }
 
 INSTANTIATE_TEST_SUITE_P(Types,
-                         ResolverDependencyGraphResolveToBuiltinFunc,
+                         ResolverDependencyGraphResolveToBuiltinFn,
                          testing::Combine(testing::ValuesIn(kTypeUseKinds),
-                                          testing::ValuesIn(core::kFunctions)));
+                                          testing::ValuesIn(core::kBuiltinFns)));
 
 INSTANTIATE_TEST_SUITE_P(Values,
-                         ResolverDependencyGraphResolveToBuiltinFunc,
+                         ResolverDependencyGraphResolveToBuiltinFn,
                          testing::Combine(testing::ValuesIn(kValueUseKinds),
-                                          testing::ValuesIn(core::kFunctions)));
+                                          testing::ValuesIn(core::kBuiltinFns)));
 
 INSTANTIATE_TEST_SUITE_P(Functions,
-                         ResolverDependencyGraphResolveToBuiltinFunc,
+                         ResolverDependencyGraphResolveToBuiltinFn,
                          testing::Combine(testing::ValuesIn(kFuncUseKinds),
-                                          testing::ValuesIn(core::kFunctions)));
+                                          testing::ValuesIn(core::kBuiltinFns)));
 
 }  // namespace resolve_to_builtin_func
 
@@ -1597,7 +1597,7 @@
                          testing::Combine(testing::ValuesIn(kAllUseKinds),
                                           testing::ValuesIn(core::kBuiltinStrings)));
 
-INSTANTIATE_TEST_SUITE_P(BuiltinFunction,
+INSTANTIATE_TEST_SUITE_P(BuiltinFn,
                          ResolverDependencyGraphShadowKindTest,
                          testing::Combine(testing::ValuesIn(kAllUseKinds),
                                           testing::ValuesIn(core::kBuiltinStrings)));
diff --git a/src/tint/lang/wgsl/resolver/materialize_test.cc b/src/tint/lang/wgsl/resolver/materialize_test.cc
index a8fed54..6116ada 100644
--- a/src/tint/lang/wgsl/resolver/materialize_test.cc
+++ b/src/tint/lang/wgsl/resolver/materialize_test.cc
@@ -953,7 +953,7 @@
             break;
         }
         case Method::kTintMaterializeBuiltin: {
-            auto* call = Call(core::str(core::Function::kTintMaterialize), abstract_expr());
+            auto* call = Call(core::str(core::BuiltinFn::kTintMaterialize), abstract_expr());
             WrapInFunction(Decl(Const("c", call)));
             break;
         }
diff --git a/src/tint/lang/wgsl/resolver/resolver.cc b/src/tint/lang/wgsl/resolver/resolver.cc
index 3552a7c..9435162 100644
--- a/src/tint/lang/wgsl/resolver/resolver.cc
+++ b/src/tint/lang/wgsl/resolver/resolver.cc
@@ -2325,7 +2325,7 @@
                 });
         }
 
-        if (auto f = resolved->BuiltinFunction(); f != core::Function::kNone) {
+        if (auto f = resolved->BuiltinFn(); f != core::BuiltinFn::kNone) {
             if (!TINT_LIKELY(CheckNotTemplated("builtin", ident))) {
                 return nullptr;
             }
@@ -2400,7 +2400,7 @@
 
 template <size_t N>
 sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
-                                 core::Function fn,
+                                 core::BuiltinFn fn,
                                  Vector<const sem::ValueExpression*, N>& args) {
     auto arg_stage = core::EvaluationStage::kConstant;
     for (auto* arg : args) {
@@ -2434,12 +2434,12 @@
         }
         auto eval_stage = overload->const_eval_fn ? core::EvaluationStage::kConstant
                                                   : core::EvaluationStage::kRuntime;
-        return builder_->create<sem::Builtin>(
+        return builder_->create<sem::BuiltinFn>(
             fn, overload->return_type, std::move(params), eval_stage, supported_stages,
             flags.Contains(OverloadFlag::kIsDeprecated), flags.Contains(OverloadFlag::kMustUse));
     });
 
-    if (fn == core::Function::kTintMaterialize) {
+    if (fn == core::BuiltinFn::kTintMaterialize) {
         args[0] = Materialize(args[0]);
         if (!args[0]) {
             return nullptr;
@@ -2487,24 +2487,24 @@
         current_function_->AddDirectCall(call);
     }
 
-    if (!validator_.RequiredExtensionForBuiltinFunction(call)) {
+    if (!validator_.RequiredExtensionForBuiltinFn(call)) {
         return nullptr;
     }
 
-    if (IsTextureBuiltin(fn)) {
-        if (!validator_.TextureBuiltinFunction(call)) {
+    if (IsTexture(fn)) {
+        if (!validator_.TextureBuiltinFn(call)) {
             return nullptr;
         }
         CollectTextureSamplerPairs(target, call->Arguments());
     }
 
-    if (fn == core::Function::kWorkgroupUniformLoad) {
+    if (fn == core::BuiltinFn::kWorkgroupUniformLoad) {
         if (!validator_.WorkgroupUniformLoad(call)) {
             return nullptr;
         }
     }
 
-    if (fn == core::Function::kSubgroupBroadcast) {
+    if (fn == core::BuiltinFn::kSubgroupBroadcast) {
         if (!validator_.SubgroupBroadcast(call)) {
             return nullptr;
         }
@@ -3027,7 +3027,7 @@
         });
 }
 
-void Resolver::CollectTextureSamplerPairs(const sem::Builtin* builtin,
+void Resolver::CollectTextureSamplerPairs(const sem::BuiltinFn* builtin,
                                           VectorRef<const sem::ValueExpression*> args) const {
     // Collect a texture/sampler pair for this builtin.
     const auto& signature = builtin->Signature();
@@ -3332,7 +3332,7 @@
         return builder_->create<sem::TypeExpression>(expr, current_statement_, ty);
     }
 
-    if (resolved->BuiltinFunction() != core::Function::kNone) {
+    if (resolved->BuiltinFn() != core::BuiltinFn::kNone) {
         AddError("missing '(' for builtin function call", expr->source.End());
         return nullptr;
     }
diff --git a/src/tint/lang/wgsl/resolver/resolver.h b/src/tint/lang/wgsl/resolver/resolver.h
index 77b5d9e..32bdde6 100644
--- a/src/tint/lang/wgsl/resolver/resolver.h
+++ b/src/tint/lang/wgsl/resolver/resolver.h
@@ -59,7 +59,7 @@
 namespace tint::sem {
 class Array;
 class BlockStatement;
-class Builtin;
+class BuiltinFn;
 class CaseStatement;
 class ForLoopStatement;
 class IfStatement;
@@ -212,7 +212,7 @@
     sem::Expression* Identifier(const ast::IdentifierExpression*);
     template <size_t N>
     sem::Call* BuiltinCall(const ast::CallExpression*,
-                           core::Function,
+                           core::BuiltinFn,
                            Vector<const sem::ValueExpression*, N>& args);
     sem::ValueExpression* Literal(const ast::LiteralExpression*);
     sem::ValueExpression* MemberAccessor(const ast::MemberAccessorExpression*);
@@ -312,7 +312,7 @@
     // / builtin, and records these on the current function by calling AddTextureSamplerPair().
     void CollectTextureSamplerPairs(sem::Function* func,
                                     VectorRef<const sem::ValueExpression*> args) const;
-    void CollectTextureSamplerPairs(const sem::Builtin* builtin,
+    void CollectTextureSamplerPairs(const sem::BuiltinFn* builtin,
                                     VectorRef<const sem::ValueExpression*> args) const;
 
     /// Resolves the WorkgroupSize for the given function, assigning it to
@@ -635,7 +635,7 @@
     Hashset<const ast::Expression*, 8> skip_const_eval_;
     IdentifierResolveHint identifier_resolve_hint_;
     Hashmap<const core::type::Type*, size_t, 8> nest_depth_;
-    Hashmap<std::pair<core::intrinsic::Overload, core::Function>, sem::Builtin*, 64> builtins_;
+    Hashmap<std::pair<core::intrinsic::Overload, core::BuiltinFn>, sem::BuiltinFn*, 64> builtins_;
     Hashmap<core::intrinsic::Overload, sem::ValueConstructor*, 16> constructors_;
     Hashmap<core::intrinsic::Overload, sem::ValueConversion*, 16> converters_;
 };
diff --git a/src/tint/lang/wgsl/resolver/uniformity.cc b/src/tint/lang/wgsl/resolver/uniformity.cc
index 9b8385b..0ce82d0 100644
--- a/src/tint/lang/wgsl/resolver/uniformity.cc
+++ b/src/tint/lang/wgsl/resolver/uniformity.cc
@@ -23,7 +23,7 @@
 #include "src/tint/lang/wgsl/program/program_builder.h"
 #include "src/tint/lang/wgsl/resolver/dependency_graph.h"
 #include "src/tint/lang/wgsl/sem/block_statement.h"
-#include "src/tint/lang/wgsl/sem/builtin.h"
+#include "src/tint/lang/wgsl/sem/builtin_fn.h"
 #include "src/tint/lang/wgsl/sem/for_loop_statement.h"
 #include "src/tint/lang/wgsl/sem/function.h"
 #include "src/tint/lang/wgsl/sem/if_statement.h"
@@ -1547,17 +1547,17 @@
         const FunctionInfo* func_info = nullptr;
         Switch(
             sem->Target(),
-            [&](const sem::Builtin* builtin) {
+            [&](const sem::BuiltinFn* builtin) {
                 // Most builtins have no restrictions. The exceptions are barriers, derivatives,
                 // some texture sampling builtins, and atomics.
                 if (builtin->IsBarrier()) {
                     callsite_tag = {CallSiteTag::CallSiteRequiredToBeUniform, default_severity};
-                } else if (builtin->Type() == core::Function::kWorkgroupUniformLoad) {
+                } else if (builtin->Fn() == core::BuiltinFn::kWorkgroupUniformLoad) {
                     callsite_tag = {CallSiteTag::CallSiteRequiredToBeUniform, default_severity};
                 } else if (builtin->IsDerivative() ||
-                           builtin->Type() == core::Function::kTextureSample ||
-                           builtin->Type() == core::Function::kTextureSampleBias ||
-                           builtin->Type() == core::Function::kTextureSampleCompare) {
+                           builtin->Fn() == core::BuiltinFn::kTextureSample ||
+                           builtin->Fn() == core::BuiltinFn::kTextureSampleBias ||
+                           builtin->Fn() == core::BuiltinFn::kTextureSampleCompare) {
                     // Get the severity of derivative uniformity violations in this context.
                     auto severity = sem_.DiagnosticSeverity(
                         call, wgsl::CoreDiagnosticRule::kDerivativeUniformity);
@@ -1568,7 +1568,7 @@
                 } else if (builtin->IsAtomic()) {
                     callsite_tag = {CallSiteTag::CallSiteNoRestriction};
                     function_tag = ReturnValueMayBeNonUniform;
-                } else if (builtin->Type() == core::Function::kTextureLoad) {
+                } else if (builtin->Fn() == core::BuiltinFn::kTextureLoad) {
                     // Loading from a read-write storage texture may produce a non-uniform value.
                     auto* storage =
                         builtin->Parameters()[0]->Type()->As<core::type::StorageTexture>();
@@ -1669,8 +1669,8 @@
                     current_function_->variables.Set(root_ident, ptr_result);
                 }
             } else {
-                auto* builtin = sem->Target()->As<sem::Builtin>();
-                if (builtin && builtin->Type() == core::Function::kWorkgroupUniformLoad) {
+                auto* builtin = sem->Target()->As<sem::BuiltinFn>();
+                if (builtin && builtin->Fn() == core::BuiltinFn::kWorkgroupUniformLoad) {
                     // The workgroupUniformLoad builtin requires its parameter to be uniform.
                     current_function_->RequiredToBeUniform(default_severity)->AddEdge(args[i]);
                 } else {
@@ -1736,7 +1736,7 @@
         const ast::CallExpression* call,
         wgsl::DiagnosticSeverity severity) {
         auto* target = SemCall(call)->Target();
-        if (target->Is<sem::Builtin>()) {
+        if (target->Is<sem::BuiltinFn>()) {
             // This is a call to a builtin, so we must be done.
             return call;
         } else if (auto* user = target->As<sem::Function>()) {
diff --git a/src/tint/lang/wgsl/resolver/validator.cc b/src/tint/lang/wgsl/resolver/validator.cc
index c21c6d1..67aed69 100644
--- a/src/tint/lang/wgsl/resolver/validator.cc
+++ b/src/tint/lang/wgsl/resolver/validator.cc
@@ -1519,8 +1519,8 @@
                          call->Declaration()->source);
                 sem_.NoteDeclarationSource(fn->Declaration());
             },
-            [&](const sem::Builtin* b) {
-                AddError("ignoring return value of builtin '" + tint::ToString(b->Type()) + "'",
+            [&](const sem::BuiltinFn* b) {
+                AddError("ignoring return value of builtin '" + tint::ToString(b->Fn()) + "'",
                          call->Declaration()->source);
             },
             [&](const sem::ValueConversion*) {
@@ -1633,8 +1633,8 @@
             // https://gpuweb.github.io/gpuweb/wgsl/#function-call-expr
             // If the called function does not return a value, a function call statement should be
             // used instead.
-            auto* builtin = call->Target()->As<sem::Builtin>();
-            auto name = tint::ToString(builtin->Type());
+            auto* builtin = call->Target()->As<sem::BuiltinFn>();
+            auto name = tint::ToString(builtin->Fn());
             AddError("builtin '" + name + "' does not return a value", call->Declaration()->source);
             return false;
         }
@@ -1643,8 +1643,8 @@
     return true;
 }
 
-bool Validator::TextureBuiltinFunction(const sem::Call* call) const {
-    auto* builtin = call->Target()->As<sem::Builtin>();
+bool Validator::TextureBuiltinFn(const sem::Call* call) const {
+    auto* builtin = call->Target()->As<sem::BuiltinFn>();
     if (!builtin) {
         return false;
     }
@@ -1695,7 +1695,7 @@
 }
 
 bool Validator::WorkgroupUniformLoad(const sem::Call* call) const {
-    auto* builtin = call->Target()->As<sem::Builtin>();
+    auto* builtin = call->Target()->As<sem::BuiltinFn>();
     if (!builtin) {
         return false;
     }
@@ -1717,7 +1717,7 @@
 }
 
 bool Validator::SubgroupBroadcast(const sem::Call* call) const {
-    auto* builtin = call->Target()->As<sem::Builtin>();
+    auto* builtin = call->Target()->As<sem::BuiltinFn>();
     if (!builtin) {
         return false;
     }
@@ -1733,8 +1733,8 @@
     return true;
 }
 
-bool Validator::RequiredExtensionForBuiltinFunction(const sem::Call* call) const {
-    const auto* builtin = call->Target()->As<sem::Builtin>();
+bool Validator::RequiredExtensionForBuiltinFn(const sem::Call* call) const {
+    const auto* builtin = call->Target()->As<sem::BuiltinFn>();
     if (!builtin) {
         return true;
     }
diff --git a/src/tint/lang/wgsl/resolver/validator.h b/src/tint/lang/wgsl/resolver/validator.h
index 38bb8f1..ecce5ba 100644
--- a/src/tint/lang/wgsl/resolver/validator.h
+++ b/src/tint/lang/wgsl/resolver/validator.h
@@ -52,7 +52,7 @@
 class Array;
 class BlockStatement;
 class BreakIfStatement;
-class Builtin;
+class BuiltinFn;
 class Call;
 class CaseStatement;
 class ForLoopStatement;
@@ -457,7 +457,7 @@
     /// Validates a texture builtin function
     /// @param call the builtin call to validate
     /// @returns true on success, false otherwise
-    bool TextureBuiltinFunction(const sem::Call* call) const;
+    bool TextureBuiltinFn(const sem::Call* call) const;
 
     /// Validates a workgroupUniformLoad builtin function
     /// @param call the builtin call to validate
@@ -472,7 +472,7 @@
     /// Validates an optional builtin function and its required extension.
     /// @param call the builtin call to validate
     /// @returns true on success, false otherwise
-    bool RequiredExtensionForBuiltinFunction(const sem::Call* call) const;
+    bool RequiredExtensionForBuiltinFn(const sem::Call* call) const;
 
     /// Validates that 'f16' extension is enabled for f16 usage at @p source
     /// @param source the source of the f16 usage
diff --git a/src/tint/lang/wgsl/sem/BUILD.bazel b/src/tint/lang/wgsl/sem/BUILD.bazel
index 75b0dae..a014edf 100644
--- a/src/tint/lang/wgsl/sem/BUILD.bazel
+++ b/src/tint/lang/wgsl/sem/BUILD.bazel
@@ -31,8 +31,8 @@
     "behavior.cc",
     "block_statement.cc",
     "break_if_statement.cc",
-    "builtin.cc",
     "builtin_enum_expression.cc",
+    "builtin_fn.cc",
     "call.cc",
     "call_target.cc",
     "expression.cc",
@@ -64,8 +64,8 @@
     "behavior.h",
     "block_statement.h",
     "break_if_statement.h",
-    "builtin.h",
     "builtin_enum_expression.h",
+    "builtin_fn.h",
     "call.h",
     "call_target.h",
     "expression.h",
@@ -122,7 +122,7 @@
   name = "test",
   alwayslink = True,
   srcs = [
-    "builtin_test.cc",
+    "builtin_fn_test.cc",
     "diagnostic_severity_test.cc",
     "helper_test.h",
     "struct_test.cc",
diff --git a/src/tint/lang/wgsl/sem/BUILD.cmake b/src/tint/lang/wgsl/sem/BUILD.cmake
index 306ba36..6e545fa 100644
--- a/src/tint/lang/wgsl/sem/BUILD.cmake
+++ b/src/tint/lang/wgsl/sem/BUILD.cmake
@@ -36,10 +36,10 @@
   lang/wgsl/sem/block_statement.h
   lang/wgsl/sem/break_if_statement.cc
   lang/wgsl/sem/break_if_statement.h
-  lang/wgsl/sem/builtin.cc
-  lang/wgsl/sem/builtin.h
   lang/wgsl/sem/builtin_enum_expression.cc
   lang/wgsl/sem/builtin_enum_expression.h
+  lang/wgsl/sem/builtin_fn.cc
+  lang/wgsl/sem/builtin_fn.h
   lang/wgsl/sem/call.cc
   lang/wgsl/sem/call.h
   lang/wgsl/sem/call_target.cc
@@ -120,7 +120,7 @@
 # Kind:      test
 ################################################################################
 tint_add_target(tint_lang_wgsl_sem_test test
-  lang/wgsl/sem/builtin_test.cc
+  lang/wgsl/sem/builtin_fn_test.cc
   lang/wgsl/sem/diagnostic_severity_test.cc
   lang/wgsl/sem/helper_test.h
   lang/wgsl/sem/struct_test.cc
diff --git a/src/tint/lang/wgsl/sem/BUILD.gn b/src/tint/lang/wgsl/sem/BUILD.gn
index 87f0a99..2e87dae 100644
--- a/src/tint/lang/wgsl/sem/BUILD.gn
+++ b/src/tint/lang/wgsl/sem/BUILD.gn
@@ -41,10 +41,10 @@
     "block_statement.h",
     "break_if_statement.cc",
     "break_if_statement.h",
-    "builtin.cc",
-    "builtin.h",
     "builtin_enum_expression.cc",
     "builtin_enum_expression.h",
+    "builtin_fn.cc",
+    "builtin_fn.h",
     "call.cc",
     "call.h",
     "call_target.cc",
@@ -123,7 +123,7 @@
   tint_unittests_source_set("unittests") {
     testonly = true
     sources = [
-      "builtin_test.cc",
+      "builtin_fn_test.cc",
       "diagnostic_severity_test.cc",
       "helper_test.h",
       "struct_test.cc",
diff --git a/src/tint/lang/wgsl/sem/builtin.cc b/src/tint/lang/wgsl/sem/builtin.cc
deleted file mode 100644
index a3e5fa5..0000000
--- a/src/tint/lang/wgsl/sem/builtin.cc
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright 2020 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.
-
-// Doxygen seems to trip over this file for some unknown reason. Disable.
-//! @cond Doxygen_Suppress
-
-#include "src/tint/lang/wgsl/sem/builtin.h"
-
-#include <utility>
-#include <vector>
-
-#include "src/tint/utils/containers/transform.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::sem::Builtin);
-
-namespace tint::sem {
-
-const char* Builtin::str() const {
-    return core::str(type_);
-}
-
-Builtin::Builtin(core::Function type,
-                 const core::type::Type* return_type,
-                 VectorRef<Parameter*> parameters,
-                 core::EvaluationStage eval_stage,
-                 PipelineStageSet supported_stages,
-                 bool is_deprecated,
-                 bool must_use)
-    : Base(return_type, std::move(parameters), eval_stage, must_use),
-      type_(type),
-      supported_stages_(supported_stages),
-      is_deprecated_(is_deprecated) {}
-
-Builtin::~Builtin() = default;
-
-bool Builtin::IsCoarseDerivative() const {
-    return IsCoarseDerivativeBuiltin(type_);
-}
-
-bool Builtin::IsFineDerivative() const {
-    return IsFineDerivativeBuiltin(type_);
-}
-
-bool Builtin::IsDerivative() const {
-    return IsDerivativeBuiltin(type_);
-}
-
-bool Builtin::IsTexture() const {
-    return IsTextureBuiltin(type_);
-}
-
-bool Builtin::IsImageQuery() const {
-    return IsImageQueryBuiltin(type_);
-}
-
-bool Builtin::IsDataPacking() const {
-    return IsDataPackingBuiltin(type_);
-}
-
-bool Builtin::IsDataUnpacking() const {
-    return IsDataUnpackingBuiltin(type_);
-}
-
-bool Builtin::IsBarrier() const {
-    return IsBarrierBuiltin(type_);
-}
-
-bool Builtin::IsAtomic() const {
-    return IsAtomicBuiltin(type_);
-}
-
-bool Builtin::IsDP4a() const {
-    return IsDP4aBuiltin(type_);
-}
-
-bool Builtin::IsSubgroup() const {
-    return IsSubgroupBuiltin(type_);
-}
-
-bool Builtin::HasSideEffects() const {
-    return core::HasSideEffects(type_);
-}
-
-wgsl::Extension Builtin::RequiredExtension() const {
-    if (IsDP4a()) {
-        return wgsl::Extension::kChromiumExperimentalDp4A;
-    }
-    if (IsSubgroup()) {
-        return wgsl::Extension::kChromiumExperimentalSubgroups;
-    }
-    if (type_ == core::Function::kTextureBarrier) {
-        return wgsl::Extension::kChromiumExperimentalReadWriteStorageTexture;
-    }
-    return wgsl::Extension::kUndefined;
-}
-
-}  // namespace tint::sem
-
-//! @endcond
diff --git a/src/tint/lang/wgsl/sem/builtin_fn.cc b/src/tint/lang/wgsl/sem/builtin_fn.cc
new file mode 100644
index 0000000..b7c9909
--- /dev/null
+++ b/src/tint/lang/wgsl/sem/builtin_fn.cc
@@ -0,0 +1,110 @@
+// Copyright 2020 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.
+
+// Doxygen seems to trip over this file for some unknown reason. Disable.
+//! @cond Doxygen_Suppress
+
+#include "src/tint/lang/wgsl/sem/builtin_fn.h"
+
+#include <utility>
+#include <vector>
+
+#include "src/tint/utils/containers/transform.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::sem::BuiltinFn);
+
+namespace tint::sem {
+
+const char* BuiltinFn::str() const {
+    return core::str(fn_);
+}
+
+BuiltinFn::BuiltinFn(core::BuiltinFn type,
+                     const core::type::Type* return_type,
+                     VectorRef<Parameter*> parameters,
+                     core::EvaluationStage eval_stage,
+                     PipelineStageSet supported_stages,
+                     bool is_deprecated,
+                     bool must_use)
+    : Base(return_type, std::move(parameters), eval_stage, must_use),
+      fn_(type),
+      supported_stages_(supported_stages),
+      is_deprecated_(is_deprecated) {}
+
+BuiltinFn::~BuiltinFn() = default;
+
+bool BuiltinFn::IsCoarseDerivative() const {
+    return core::IsCoarseDerivative(fn_);
+}
+
+bool BuiltinFn::IsFineDerivative() const {
+    return core::IsFineDerivative(fn_);
+}
+
+bool BuiltinFn::IsDerivative() const {
+    return core::IsDerivative(fn_);
+}
+
+bool BuiltinFn::IsTexture() const {
+    return core::IsTexture(fn_);
+}
+
+bool BuiltinFn::IsImageQuery() const {
+    return core::IsImageQuery(fn_);
+}
+
+bool BuiltinFn::IsDataPacking() const {
+    return core::IsDataPacking(fn_);
+}
+
+bool BuiltinFn::IsDataUnpacking() const {
+    return core::IsDataUnpacking(fn_);
+}
+
+bool BuiltinFn::IsBarrier() const {
+    return core::IsBarrier(fn_);
+}
+
+bool BuiltinFn::IsAtomic() const {
+    return core::IsAtomic(fn_);
+}
+
+bool BuiltinFn::IsDP4a() const {
+    return core::IsDP4a(fn_);
+}
+
+bool BuiltinFn::IsSubgroup() const {
+    return core::IsSubgroup(fn_);
+}
+
+bool BuiltinFn::HasSideEffects() const {
+    return core::HasSideEffects(fn_);
+}
+
+wgsl::Extension BuiltinFn::RequiredExtension() const {
+    if (IsDP4a()) {
+        return wgsl::Extension::kChromiumExperimentalDp4A;
+    }
+    if (IsSubgroup()) {
+        return wgsl::Extension::kChromiumExperimentalSubgroups;
+    }
+    if (fn_ == core::BuiltinFn::kTextureBarrier) {
+        return wgsl::Extension::kChromiumExperimentalReadWriteStorageTexture;
+    }
+    return wgsl::Extension::kUndefined;
+}
+
+}  // namespace tint::sem
+
+//! @endcond
diff --git a/src/tint/lang/wgsl/sem/builtin.h b/src/tint/lang/wgsl/sem/builtin_fn.h
similarity index 82%
rename from src/tint/lang/wgsl/sem/builtin.h
rename to src/tint/lang/wgsl/sem/builtin_fn.h
index 838288a..525403c 100644
--- a/src/tint/lang/wgsl/sem/builtin.h
+++ b/src/tint/lang/wgsl/sem/builtin_fn.h
@@ -12,13 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_LANG_WGSL_SEM_BUILTIN_H_
-#define SRC_TINT_LANG_WGSL_SEM_BUILTIN_H_
+#ifndef SRC_TINT_LANG_WGSL_SEM_BUILTIN_FN_H_
+#define SRC_TINT_LANG_WGSL_SEM_BUILTIN_FN_H_
 
 #include <string>
 #include <vector>
 
-#include "src/tint/lang/core/function.h"
+#include "src/tint/lang/core/builtin_fn.h"
 #include "src/tint/lang/wgsl/extension.h"
 #include "src/tint/lang/wgsl/sem/call_target.h"
 #include "src/tint/lang/wgsl/sem/pipeline_stage_set.h"
@@ -26,8 +26,8 @@
 
 namespace tint::sem {
 
-/// Builtin holds the semantic information for a builtin function.
-class Builtin final : public Castable<Builtin, CallTarget> {
+/// BuiltinFn holds the semantic information for a builtin function.
+class BuiltinFn final : public Castable<BuiltinFn, CallTarget> {
   public:
     /// Constructor
     /// @param type the builtin type
@@ -37,19 +37,19 @@
     /// @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(core::Function type,
-            const core::type::Type* return_type,
-            VectorRef<Parameter*> parameters,
-            core::EvaluationStage eval_stage,
-            PipelineStageSet supported_stages,
-            bool is_deprecated,
-            bool must_use);
+    BuiltinFn(core::BuiltinFn type,
+              const core::type::Type* return_type,
+              VectorRef<Parameter*> parameters,
+              core::EvaluationStage eval_stage,
+              PipelineStageSet supported_stages,
+              bool is_deprecated,
+              bool must_use);
 
     /// Destructor
-    ~Builtin() override;
+    ~BuiltinFn() override;
 
     /// @return the type of the builtin
-    core::Function Type() const { return type_; }
+    core::BuiltinFn Fn() const { return fn_; }
 
     /// @return the pipeline stages that this builtin can be used in
     PipelineStageSet SupportedStages() const { return supported_stages_; }
@@ -106,11 +106,11 @@
 
     /// @return the hash code for this object
     std::size_t HashCode() const {
-        return Hash(Type(), SupportedStages(), ReturnType(), Parameters(), IsDeprecated());
+        return Hash(Fn(), SupportedStages(), ReturnType(), Parameters(), IsDeprecated());
     }
 
   private:
-    const core::Function type_;
+    const core::BuiltinFn fn_;
     const PipelineStageSet supported_stages_;
     const bool is_deprecated_;
 };
@@ -123,4 +123,4 @@
 
 }  // namespace tint::sem
 
-#endif  // SRC_TINT_LANG_WGSL_SEM_BUILTIN_H_
+#endif  // SRC_TINT_LANG_WGSL_SEM_BUILTIN_FN_H_
diff --git a/src/tint/lang/wgsl/sem/builtin_fn_test.cc b/src/tint/lang/wgsl/sem/builtin_fn_test.cc
new file mode 100644
index 0000000..f10a9f9
--- /dev/null
+++ b/src/tint/lang/wgsl/sem/builtin_fn_test.cc
@@ -0,0 +1,127 @@
+// 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.
+
+#include "src/tint/lang/wgsl/sem/builtin_fn.h"
+
+#include "gtest/gtest.h"
+
+namespace tint::sem {
+namespace {
+
+struct BuiltinData {
+    const char* name;
+    core::BuiltinFn builtin;
+};
+
+inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
+    out << data.name;
+    return out;
+}
+
+using BuiltinFunctionTest = testing::TestWithParam<BuiltinData>;
+
+TEST_P(BuiltinFunctionTest, Parse) {
+    auto param = GetParam();
+    EXPECT_EQ(core::ParseBuiltinFn(param.name), param.builtin);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    BuiltinFunctionTest,
+    BuiltinFunctionTest,
+    testing::Values(BuiltinData{"abs", core::BuiltinFn::kAbs},
+                    BuiltinData{"acos", core::BuiltinFn::kAcos},
+                    BuiltinData{"all", core::BuiltinFn::kAll},
+                    BuiltinData{"any", core::BuiltinFn::kAny},
+                    BuiltinData{"arrayLength", core::BuiltinFn::kArrayLength},
+                    BuiltinData{"asin", core::BuiltinFn::kAsin},
+                    BuiltinData{"atan", core::BuiltinFn::kAtan},
+                    BuiltinData{"atan2", core::BuiltinFn::kAtan2},
+                    BuiltinData{"ceil", core::BuiltinFn::kCeil},
+                    BuiltinData{"clamp", core::BuiltinFn::kClamp},
+                    BuiltinData{"cos", core::BuiltinFn::kCos},
+                    BuiltinData{"cosh", core::BuiltinFn::kCosh},
+                    BuiltinData{"countOneBits", core::BuiltinFn::kCountOneBits},
+                    BuiltinData{"cross", core::BuiltinFn::kCross},
+                    BuiltinData{"determinant", core::BuiltinFn::kDeterminant},
+                    BuiltinData{"distance", core::BuiltinFn::kDistance},
+                    BuiltinData{"dot", core::BuiltinFn::kDot},
+                    BuiltinData{"dot4I8Packed", core::BuiltinFn::kDot4I8Packed},
+                    BuiltinData{"dot4U8Packed", core::BuiltinFn::kDot4U8Packed},
+                    BuiltinData{"dpdx", core::BuiltinFn::kDpdx},
+                    BuiltinData{"dpdxCoarse", core::BuiltinFn::kDpdxCoarse},
+                    BuiltinData{"dpdxFine", core::BuiltinFn::kDpdxFine},
+                    BuiltinData{"dpdy", core::BuiltinFn::kDpdy},
+                    BuiltinData{"dpdyCoarse", core::BuiltinFn::kDpdyCoarse},
+                    BuiltinData{"dpdyFine", core::BuiltinFn::kDpdyFine},
+                    BuiltinData{"exp", core::BuiltinFn::kExp},
+                    BuiltinData{"exp2", core::BuiltinFn::kExp2},
+                    BuiltinData{"faceForward", core::BuiltinFn::kFaceForward},
+                    BuiltinData{"floor", core::BuiltinFn::kFloor},
+                    BuiltinData{"fma", core::BuiltinFn::kFma},
+                    BuiltinData{"fract", core::BuiltinFn::kFract},
+                    BuiltinData{"frexp", core::BuiltinFn::kFrexp},
+                    BuiltinData{"fwidth", core::BuiltinFn::kFwidth},
+                    BuiltinData{"fwidthCoarse", core::BuiltinFn::kFwidthCoarse},
+                    BuiltinData{"fwidthFine", core::BuiltinFn::kFwidthFine},
+                    BuiltinData{"inverseSqrt", core::BuiltinFn::kInverseSqrt},
+                    BuiltinData{"ldexp", core::BuiltinFn::kLdexp},
+                    BuiltinData{"length", core::BuiltinFn::kLength},
+                    BuiltinData{"log", core::BuiltinFn::kLog},
+                    BuiltinData{"log2", core::BuiltinFn::kLog2},
+                    BuiltinData{"max", core::BuiltinFn::kMax},
+                    BuiltinData{"min", core::BuiltinFn::kMin},
+                    BuiltinData{"mix", core::BuiltinFn::kMix},
+                    BuiltinData{"modf", core::BuiltinFn::kModf},
+                    BuiltinData{"normalize", core::BuiltinFn::kNormalize},
+                    BuiltinData{"pow", core::BuiltinFn::kPow},
+                    BuiltinData{"reflect", core::BuiltinFn::kReflect},
+                    BuiltinData{"reverseBits", core::BuiltinFn::kReverseBits},
+                    BuiltinData{"round", core::BuiltinFn::kRound},
+                    BuiltinData{"select", core::BuiltinFn::kSelect},
+                    BuiltinData{"sign", core::BuiltinFn::kSign},
+                    BuiltinData{"sin", core::BuiltinFn::kSin},
+                    BuiltinData{"sinh", core::BuiltinFn::kSinh},
+                    BuiltinData{"smoothstep", core::BuiltinFn::kSmoothstep},
+                    BuiltinData{"sqrt", core::BuiltinFn::kSqrt},
+                    BuiltinData{"step", core::BuiltinFn::kStep},
+                    BuiltinData{"storageBarrier", core::BuiltinFn::kStorageBarrier},
+                    BuiltinData{"tan", core::BuiltinFn::kTan},
+                    BuiltinData{"tanh", core::BuiltinFn::kTanh},
+                    BuiltinData{"textureDimensions", core::BuiltinFn::kTextureDimensions},
+                    BuiltinData{"textureLoad", core::BuiltinFn::kTextureLoad},
+                    BuiltinData{"textureNumLayers", core::BuiltinFn::kTextureNumLayers},
+                    BuiltinData{"textureNumLevels", core::BuiltinFn::kTextureNumLevels},
+                    BuiltinData{"textureNumSamples", core::BuiltinFn::kTextureNumSamples},
+                    BuiltinData{"textureSample", core::BuiltinFn::kTextureSample},
+                    BuiltinData{"textureSampleBias", core::BuiltinFn::kTextureSampleBias},
+                    BuiltinData{"textureSampleCompare", core::BuiltinFn::kTextureSampleCompare},
+                    BuiltinData{"textureSampleCompareLevel",
+                                core::BuiltinFn::kTextureSampleCompareLevel},
+                    BuiltinData{"textureSampleGrad", core::BuiltinFn::kTextureSampleGrad},
+                    BuiltinData{"textureSampleLevel", core::BuiltinFn::kTextureSampleLevel},
+                    BuiltinData{"trunc", core::BuiltinFn::kTrunc},
+                    BuiltinData{"unpack2x16float", core::BuiltinFn::kUnpack2X16Float},
+                    BuiltinData{"unpack2x16snorm", core::BuiltinFn::kUnpack2X16Snorm},
+                    BuiltinData{"unpack2x16unorm", core::BuiltinFn::kUnpack2X16Unorm},
+                    BuiltinData{"unpack4x8snorm", core::BuiltinFn::kUnpack4X8Snorm},
+                    BuiltinData{"unpack4x8unorm", core::BuiltinFn::kUnpack4X8Unorm},
+                    BuiltinData{"workgroupBarrier", core::BuiltinFn::kWorkgroupBarrier},
+                    BuiltinData{"workgroupUniformLoad", core::BuiltinFn::kWorkgroupUniformLoad}));
+
+TEST_F(BuiltinFunctionTest, ParseNoMatch) {
+    EXPECT_EQ(core::ParseBuiltinFn("not_builtin"), core::BuiltinFn::kNone);
+}
+
+}  // namespace
+}  // namespace tint::sem
diff --git a/src/tint/lang/wgsl/sem/builtin_test.cc b/src/tint/lang/wgsl/sem/builtin_test.cc
deleted file mode 100644
index ae77105..0000000
--- a/src/tint/lang/wgsl/sem/builtin_test.cc
+++ /dev/null
@@ -1,127 +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.
-
-#include "src/tint/lang/wgsl/sem/builtin.h"
-
-#include "gtest/gtest.h"
-
-namespace tint::sem {
-namespace {
-
-struct BuiltinData {
-    const char* name;
-    core::Function builtin;
-};
-
-inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
-    out << data.name;
-    return out;
-}
-
-using BuiltinFunctionTest = testing::TestWithParam<BuiltinData>;
-
-TEST_P(BuiltinFunctionTest, Parse) {
-    auto param = GetParam();
-    EXPECT_EQ(core::ParseFunction(param.name), param.builtin);
-}
-
-INSTANTIATE_TEST_SUITE_P(
-    BuiltinFunctionTest,
-    BuiltinFunctionTest,
-    testing::Values(BuiltinData{"abs", core::Function::kAbs},
-                    BuiltinData{"acos", core::Function::kAcos},
-                    BuiltinData{"all", core::Function::kAll},
-                    BuiltinData{"any", core::Function::kAny},
-                    BuiltinData{"arrayLength", core::Function::kArrayLength},
-                    BuiltinData{"asin", core::Function::kAsin},
-                    BuiltinData{"atan", core::Function::kAtan},
-                    BuiltinData{"atan2", core::Function::kAtan2},
-                    BuiltinData{"ceil", core::Function::kCeil},
-                    BuiltinData{"clamp", core::Function::kClamp},
-                    BuiltinData{"cos", core::Function::kCos},
-                    BuiltinData{"cosh", core::Function::kCosh},
-                    BuiltinData{"countOneBits", core::Function::kCountOneBits},
-                    BuiltinData{"cross", core::Function::kCross},
-                    BuiltinData{"determinant", core::Function::kDeterminant},
-                    BuiltinData{"distance", core::Function::kDistance},
-                    BuiltinData{"dot", core::Function::kDot},
-                    BuiltinData{"dot4I8Packed", core::Function::kDot4I8Packed},
-                    BuiltinData{"dot4U8Packed", core::Function::kDot4U8Packed},
-                    BuiltinData{"dpdx", core::Function::kDpdx},
-                    BuiltinData{"dpdxCoarse", core::Function::kDpdxCoarse},
-                    BuiltinData{"dpdxFine", core::Function::kDpdxFine},
-                    BuiltinData{"dpdy", core::Function::kDpdy},
-                    BuiltinData{"dpdyCoarse", core::Function::kDpdyCoarse},
-                    BuiltinData{"dpdyFine", core::Function::kDpdyFine},
-                    BuiltinData{"exp", core::Function::kExp},
-                    BuiltinData{"exp2", core::Function::kExp2},
-                    BuiltinData{"faceForward", core::Function::kFaceForward},
-                    BuiltinData{"floor", core::Function::kFloor},
-                    BuiltinData{"fma", core::Function::kFma},
-                    BuiltinData{"fract", core::Function::kFract},
-                    BuiltinData{"frexp", core::Function::kFrexp},
-                    BuiltinData{"fwidth", core::Function::kFwidth},
-                    BuiltinData{"fwidthCoarse", core::Function::kFwidthCoarse},
-                    BuiltinData{"fwidthFine", core::Function::kFwidthFine},
-                    BuiltinData{"inverseSqrt", core::Function::kInverseSqrt},
-                    BuiltinData{"ldexp", core::Function::kLdexp},
-                    BuiltinData{"length", core::Function::kLength},
-                    BuiltinData{"log", core::Function::kLog},
-                    BuiltinData{"log2", core::Function::kLog2},
-                    BuiltinData{"max", core::Function::kMax},
-                    BuiltinData{"min", core::Function::kMin},
-                    BuiltinData{"mix", core::Function::kMix},
-                    BuiltinData{"modf", core::Function::kModf},
-                    BuiltinData{"normalize", core::Function::kNormalize},
-                    BuiltinData{"pow", core::Function::kPow},
-                    BuiltinData{"reflect", core::Function::kReflect},
-                    BuiltinData{"reverseBits", core::Function::kReverseBits},
-                    BuiltinData{"round", core::Function::kRound},
-                    BuiltinData{"select", core::Function::kSelect},
-                    BuiltinData{"sign", core::Function::kSign},
-                    BuiltinData{"sin", core::Function::kSin},
-                    BuiltinData{"sinh", core::Function::kSinh},
-                    BuiltinData{"smoothstep", core::Function::kSmoothstep},
-                    BuiltinData{"sqrt", core::Function::kSqrt},
-                    BuiltinData{"step", core::Function::kStep},
-                    BuiltinData{"storageBarrier", core::Function::kStorageBarrier},
-                    BuiltinData{"tan", core::Function::kTan},
-                    BuiltinData{"tanh", core::Function::kTanh},
-                    BuiltinData{"textureDimensions", core::Function::kTextureDimensions},
-                    BuiltinData{"textureLoad", core::Function::kTextureLoad},
-                    BuiltinData{"textureNumLayers", core::Function::kTextureNumLayers},
-                    BuiltinData{"textureNumLevels", core::Function::kTextureNumLevels},
-                    BuiltinData{"textureNumSamples", core::Function::kTextureNumSamples},
-                    BuiltinData{"textureSample", core::Function::kTextureSample},
-                    BuiltinData{"textureSampleBias", core::Function::kTextureSampleBias},
-                    BuiltinData{"textureSampleCompare", core::Function::kTextureSampleCompare},
-                    BuiltinData{"textureSampleCompareLevel",
-                                core::Function::kTextureSampleCompareLevel},
-                    BuiltinData{"textureSampleGrad", core::Function::kTextureSampleGrad},
-                    BuiltinData{"textureSampleLevel", core::Function::kTextureSampleLevel},
-                    BuiltinData{"trunc", core::Function::kTrunc},
-                    BuiltinData{"unpack2x16float", core::Function::kUnpack2X16Float},
-                    BuiltinData{"unpack2x16snorm", core::Function::kUnpack2X16Snorm},
-                    BuiltinData{"unpack2x16unorm", core::Function::kUnpack2X16Unorm},
-                    BuiltinData{"unpack4x8snorm", core::Function::kUnpack4X8Snorm},
-                    BuiltinData{"unpack4x8unorm", core::Function::kUnpack4X8Unorm},
-                    BuiltinData{"workgroupBarrier", core::Function::kWorkgroupBarrier},
-                    BuiltinData{"workgroupUniformLoad", core::Function::kWorkgroupUniformLoad}));
-
-TEST_F(BuiltinFunctionTest, ParseNoMatch) {
-    EXPECT_EQ(core::ParseFunction("not_builtin"), core::Function::kNone);
-}
-
-}  // namespace
-}  // namespace tint::sem
diff --git a/src/tint/lang/wgsl/sem/call.h b/src/tint/lang/wgsl/sem/call.h
index 419a5ae..3956589 100644
--- a/src/tint/lang/wgsl/sem/call.h
+++ b/src/tint/lang/wgsl/sem/call.h
@@ -18,7 +18,7 @@
 #include <vector>
 
 #include "src/tint/lang/wgsl/ast/call_expression.h"
-#include "src/tint/lang/wgsl/sem/builtin.h"
+#include "src/tint/lang/wgsl/sem/builtin_fn.h"
 #include "src/tint/lang/wgsl/sem/value_expression.h"
 #include "src/tint/utils/containers/vector.h"
 
diff --git a/src/tint/lang/wgsl/sem/function.h b/src/tint/lang/wgsl/sem/function.h
index c21a76e..585ede0 100644
--- a/src/tint/lang/wgsl/sem/function.h
+++ b/src/tint/lang/wgsl/sem/function.h
@@ -35,7 +35,7 @@
 class ReturnStatement;
 }  // namespace tint::ast
 namespace tint::sem {
-class Builtin;
+class BuiltinFn;
 class Variable;
 }  // namespace tint::sem
 
@@ -117,13 +117,13 @@
     }
 
     /// @returns the list of builtins that this function directly calls.
-    const UniqueVector<const Builtin*, 4>& DirectlyCalledBuiltins() const {
+    const UniqueVector<const BuiltinFn*, 4>& DirectlyCalledBuiltins() const {
         return directly_called_builtins_;
     }
 
     /// Records that this function transitively calls `builtin`.
     /// @param builtin the builtin this function directly calls
-    void AddDirectlyCalledBuiltin(const Builtin* builtin) {
+    void AddDirectlyCalledBuiltin(const BuiltinFn* builtin) {
         directly_called_builtins_.Add(builtin);
     }
 
@@ -288,7 +288,7 @@
     UniqueVector<const GlobalVariable*, 4> directly_referenced_globals_;
     UniqueVector<const GlobalVariable*, 8> transitively_referenced_globals_;
     UniqueVector<const Function*, 8> transitively_called_functions_;
-    UniqueVector<const Builtin*, 4> directly_called_builtins_;
+    UniqueVector<const BuiltinFn*, 4> directly_called_builtins_;
     UniqueVector<VariablePair, 8> texture_sampler_pairs_;
     std::vector<const Call*> direct_calls_;
     std::vector<const Call*> callsites_;
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
index 726eb6d..1fb499f 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.cc
@@ -1141,20 +1141,20 @@
         return b.IndexAccessor(expr, Expr(index));
     }
 
-    bool RequiresDerivativeUniformity(core::Function fn) {
+    bool RequiresDerivativeUniformity(core::BuiltinFn fn) {
         switch (fn) {
-            case core::Function::kDpdxCoarse:
-            case core::Function::kDpdyCoarse:
-            case core::Function::kFwidthCoarse:
-            case core::Function::kDpdxFine:
-            case core::Function::kDpdyFine:
-            case core::Function::kFwidthFine:
-            case core::Function::kDpdx:
-            case core::Function::kDpdy:
-            case core::Function::kFwidth:
-            case core::Function::kTextureSample:
-            case core::Function::kTextureSampleBias:
-            case core::Function::kTextureSampleCompare:
+            case core::BuiltinFn::kDpdxCoarse:
+            case core::BuiltinFn::kDpdyCoarse:
+            case core::BuiltinFn::kFwidthCoarse:
+            case core::BuiltinFn::kDpdxFine:
+            case core::BuiltinFn::kDpdyFine:
+            case core::BuiltinFn::kFwidthFine:
+            case core::BuiltinFn::kDpdx:
+            case core::BuiltinFn::kDpdy:
+            case core::BuiltinFn::kFwidth:
+            case core::BuiltinFn::kTextureSample:
+            case core::BuiltinFn::kTextureSampleBias:
+            case core::BuiltinFn::kTextureSampleCompare:
                 return true;
             default:
                 return false;
diff --git a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts_test.cc b/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts_test.cc
index fcabf9a..e5866f4 100644
--- a/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts_test.cc
+++ b/src/tint/lang/wgsl/writer/ir_to_program/rename_conflicts_test.cc
@@ -1019,7 +1019,7 @@
 
     auto* fn = b.Function("f", ty.i32());
     b.Append(fn->Block(), [&] {  //
-        auto* res = b.Call(ty.i32(), core::Function::kMax, 1_i, 2_i)->Result();
+        auto* res = b.Call(ty.i32(), core::BuiltinFn::kMax, 1_i, 2_i)->Result();
         b.Return(fn, res);
     });
 
@@ -1052,7 +1052,7 @@
 
     auto* fn = b.Function("f", ty.i32());
     b.Append(fn->Block(), [&] {  //
-        auto* res = b.Call(ty.i32(), core::Function::kMax, 1_i, 2_i)->Result();
+        auto* res = b.Call(ty.i32(), core::BuiltinFn::kMax, 1_i, 2_i)->Result();
         b.Return(fn, res);
     });