Move InterpolationSampling and InterpolationType to builtin.

This CL moves the ast::InterpolateSampling and ast::InterpolationType to
builtin::

Change-Id: Iad9365ff629cbb7b3b03de6a4cd9355a21ce287e
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/120442
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index e37ad6c..9870ccd 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -708,6 +708,10 @@
     "builtin/diagnostic_severity.h",
     "builtin/extension.cc",
     "builtin/extension.h",
+    "builtin/interpolation_sampling.cc",
+    "builtin/interpolation_sampling.h",
+    "builtin/interpolation_type.cc",
+    "builtin/interpolation_type.h",
     "builtin/texel_format.cc",
     "builtin/texel_format.h",
   ]
@@ -1306,6 +1310,8 @@
       "builtin/diagnostic_rule_test.cc",
       "builtin/diagnostic_severity_test.cc",
       "builtin/extension_test.cc",
+      "builtin/interpolation_sampling_test.cc",
+      "builtin/interpolation_type_test.cc",
       "builtin/texel_format_test.cc",
     ]
     deps = [ ":libtint_builtins_src" ]
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index eb4203d..2fe2161 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -158,6 +158,8 @@
   ast/int_literal_expression.h
   ast/internal_attribute.cc
   ast/internal_attribute.h
+  ast/interpolate_attribute.cc
+  ast/interpolate_attribute.h
   ast/invariant_attribute.cc
   ast/invariant_attribute.h
   ast/let.cc
@@ -555,9 +557,10 @@
 tint_generated(builtin/diagnostic_rule BENCH TEST)
 tint_generated(builtin/diagnostic_severity BENCH TEST)
 tint_generated(builtin/extension BENCH TEST)
+tint_generated(builtin/interpolation_sampling BENCH TEST)
+tint_generated(builtin/interpolation_type BENCH TEST)
 tint_generated(builtin/texel_format BENCH TEST)
-tint_generated(ast/diagnostic_control TEST)
-tint_generated(ast/interpolate_attribute BENCH TEST)
+
 tint_generated(resolver/init_conv_intrinsic)
 tint_generated(sem/builtin_type)
 tint_generated(sem/parameter_usage)
@@ -826,6 +829,7 @@
     ast/increment_decrement_statement_test.cc
     ast/index_accessor_expression_test.cc
     ast/int_literal_expression_test.cc
+    ast/interpolate_attribute_test.cc
     ast/invariant_attribute_test.cc
     ast/location_attribute_test.cc
     ast/loop_statement_test.cc
diff --git a/src/tint/ast/interpolate_attribute.cc b/src/tint/ast/interpolate_attribute.cc
index 2e9ef2a..339880d 100644
--- a/src/tint/ast/interpolate_attribute.cc
+++ b/src/tint/ast/interpolate_attribute.cc
@@ -12,14 +12,6 @@
 // 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/ast/interpolate_attribute.cc.tmpl
-//
-// Do not modify this file directly
-////////////////////////////////////////////////////////////////////////////////
-
 #include "src/tint/ast/interpolate_attribute.h"
 
 #include <string>
@@ -33,8 +25,8 @@
 InterpolateAttribute::InterpolateAttribute(ProgramID pid,
                                            NodeID nid,
                                            const Source& src,
-                                           InterpolationType ty,
-                                           InterpolationSampling smpl)
+                                           builtin::InterpolationType ty,
+                                           builtin::InterpolationSampling smpl)
     : Base(pid, nid, src), type(ty), sampling(smpl) {}
 
 InterpolateAttribute::~InterpolateAttribute() = default;
@@ -49,65 +41,4 @@
     return ctx->dst->create<InterpolateAttribute>(src, type, sampling);
 }
 
-/// ParseInterpolationType parses a InterpolationType from a string.
-/// @param str the string to parse
-/// @returns the parsed enum, or InterpolationType::kUndefined if the string could not be parsed.
-InterpolationType ParseInterpolationType(std::string_view str) {
-    if (str == "flat") {
-        return InterpolationType::kFlat;
-    }
-    if (str == "linear") {
-        return InterpolationType::kLinear;
-    }
-    if (str == "perspective") {
-        return InterpolationType::kPerspective;
-    }
-    return InterpolationType::kUndefined;
-}
-
-std::ostream& operator<<(std::ostream& out, InterpolationType value) {
-    switch (value) {
-        case InterpolationType::kUndefined:
-            return out << "undefined";
-        case InterpolationType::kFlat:
-            return out << "flat";
-        case InterpolationType::kLinear:
-            return out << "linear";
-        case InterpolationType::kPerspective:
-            return out << "perspective";
-    }
-    return out << "<unknown>";
-}
-
-/// ParseInterpolationSampling parses a InterpolationSampling from a string.
-/// @param str the string to parse
-/// @returns the parsed enum, or InterpolationSampling::kUndefined if the string could not be
-/// parsed.
-InterpolationSampling ParseInterpolationSampling(std::string_view str) {
-    if (str == "center") {
-        return InterpolationSampling::kCenter;
-    }
-    if (str == "centroid") {
-        return InterpolationSampling::kCentroid;
-    }
-    if (str == "sample") {
-        return InterpolationSampling::kSample;
-    }
-    return InterpolationSampling::kUndefined;
-}
-
-std::ostream& operator<<(std::ostream& out, InterpolationSampling value) {
-    switch (value) {
-        case InterpolationSampling::kUndefined:
-            return out << "undefined";
-        case InterpolationSampling::kCenter:
-            return out << "center";
-        case InterpolationSampling::kCentroid:
-            return out << "centroid";
-        case InterpolationSampling::kSample:
-            return out << "sample";
-    }
-    return out << "<unknown>";
-}
-
 }  // namespace tint::ast
diff --git a/src/tint/ast/interpolate_attribute.cc.tmpl b/src/tint/ast/interpolate_attribute.cc.tmpl
deleted file mode 100644
index b6f0b35..0000000
--- a/src/tint/ast/interpolate_attribute.cc.tmpl
+++ /dev/null
@@ -1,50 +0,0 @@
-{{- /*
---------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate builtin_value.cc
-
-See:
-* tools/src/cmd/gen for structures used by this template
-* https://golang.org/pkg/text/template/ for documentation on the template syntax
---------------------------------------------------------------------------------
-*/ -}}
-
-{{- Import "src/tint/templates/enums.tmpl.inc" -}}
-
-#include "src/tint/ast/interpolate_attribute.h"
-
-#include <string>
-
-#include "src/tint/program_builder.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::ast::InterpolateAttribute);
-
-namespace tint::ast {
-
-InterpolateAttribute::InterpolateAttribute(ProgramID pid,
-                                           NodeID nid,
-                                           const Source& src,
-                                           InterpolationType ty,
-                                           InterpolationSampling smpl)
-    : Base(pid, nid, src), type(ty), sampling(smpl) {}
-
-InterpolateAttribute::~InterpolateAttribute() = default;
-
-std::string InterpolateAttribute::Name() const {
-    return "interpolate";
-}
-
-const InterpolateAttribute* InterpolateAttribute::Clone(CloneContext* ctx) const {
-    // Clone arguments outside of create() call to have deterministic ordering
-    auto src = ctx->Clone(source);
-    return ctx->dst->create<InterpolateAttribute>(src, type, sampling);
-}
-
-{{ Eval "ParseEnum" (Sem.Enum "interpolation_type")}}
-
-{{ Eval "EnumOStream" (Sem.Enum "interpolation_type")}}
-
-{{ Eval "ParseEnum" (Sem.Enum "interpolation_sampling")}}
-
-{{ Eval "EnumOStream" (Sem.Enum "interpolation_sampling")}}
-
-}  // namespace tint::ast
diff --git a/src/tint/ast/interpolate_attribute.h b/src/tint/ast/interpolate_attribute.h
index dd60156..2d3ce6f 100644
--- a/src/tint/ast/interpolate_attribute.h
+++ b/src/tint/ast/interpolate_attribute.h
@@ -12,14 +12,6 @@
 // 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/ast/interpolate_attribute.h.tmpl
-//
-// Do not modify this file directly
-////////////////////////////////////////////////////////////////////////////////
-
 #ifndef SRC_TINT_AST_INTERPOLATE_ATTRIBUTE_H_
 #define SRC_TINT_AST_INTERPOLATE_ATTRIBUTE_H_
 
@@ -27,58 +19,11 @@
 #include <string>
 
 #include "src/tint/ast/attribute.h"
+#include "src/tint/builtin/interpolation_sampling.h"
+#include "src/tint/builtin/interpolation_type.h"
 
 namespace tint::ast {
 
-/// The interpolation type.
-enum class InterpolationType {
-    kUndefined,
-    kFlat,
-    kLinear,
-    kPerspective,
-};
-
-/// @param out the std::ostream to write to
-/// @param value the InterpolationType
-/// @returns `out` so calls can be chained
-std::ostream& operator<<(std::ostream& out, InterpolationType value);
-
-/// ParseInterpolationType parses a InterpolationType from a string.
-/// @param str the string to parse
-/// @returns the parsed enum, or InterpolationType::kUndefined if the string could not be parsed.
-InterpolationType ParseInterpolationType(std::string_view str);
-
-constexpr const char* kInterpolationTypeStrings[] = {
-    "flat",
-    "linear",
-    "perspective",
-};
-
-/// The interpolation sampling.
-enum class InterpolationSampling {
-    kUndefined,
-    kCenter,
-    kCentroid,
-    kSample,
-};
-
-/// @param out the std::ostream to write to
-/// @param value the InterpolationSampling
-/// @returns `out` so calls can be chained
-std::ostream& operator<<(std::ostream& out, InterpolationSampling value);
-
-/// ParseInterpolationSampling parses a InterpolationSampling from a string.
-/// @param str the string to parse
-/// @returns the parsed enum, or InterpolationSampling::kUndefined if the string could not be
-/// parsed.
-InterpolationSampling ParseInterpolationSampling(std::string_view str);
-
-constexpr const char* kInterpolationSamplingStrings[] = {
-    "center",
-    "centroid",
-    "sample",
-};
-
 /// An interpolate attribute
 class InterpolateAttribute final : public Castable<InterpolateAttribute, Attribute> {
   public:
@@ -91,8 +36,8 @@
     InterpolateAttribute(ProgramID pid,
                          NodeID nid,
                          const Source& src,
-                         InterpolationType type,
-                         InterpolationSampling sampling);
+                         builtin::InterpolationType type,
+                         builtin::InterpolationSampling sampling);
     ~InterpolateAttribute() override;
 
     /// @returns the WGSL name for the attribute
@@ -105,10 +50,10 @@
     const InterpolateAttribute* Clone(CloneContext* ctx) const override;
 
     /// The interpolation type
-    const InterpolationType type;
+    const builtin::InterpolationType type;
 
     /// The interpolation sampling
-    const InterpolationSampling sampling;
+    const builtin::InterpolationSampling sampling;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/interpolate_attribute.h.tmpl b/src/tint/ast/interpolate_attribute.h.tmpl
deleted file mode 100644
index c225cb6..0000000
--- a/src/tint/ast/interpolate_attribute.h.tmpl
+++ /dev/null
@@ -1,63 +0,0 @@
-{{- /*
---------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate interpolate_attribute.h
-
-See:
-* tools/src/cmd/gen for structures used by this template
-* https://golang.org/pkg/text/template/ for documentation on the template syntax
---------------------------------------------------------------------------------
-*/ -}}
-
-{{- Import "src/tint/templates/enums.tmpl.inc" -}}
-
-#ifndef SRC_TINT_AST_INTERPOLATE_ATTRIBUTE_H_
-#define SRC_TINT_AST_INTERPOLATE_ATTRIBUTE_H_
-
-#include <ostream>
-#include <string>
-
-#include "src/tint/ast/attribute.h"
-
-namespace tint::ast {
-
-/// The interpolation type.
-{{ Eval "DeclareEnum" (Sem.Enum "interpolation_type") }}
-
-/// The interpolation sampling.
-{{ Eval "DeclareEnum" (Sem.Enum "interpolation_sampling") }}
-
-/// An interpolate attribute
-class InterpolateAttribute final : public Castable<InterpolateAttribute, Attribute> {
-  public:
-    /// Create an interpolate attribute.
-    /// @param pid the identifier of the program that owns this node
-    /// @param nid the unique node identifier
-    /// @param src the source of this node
-    /// @param type the interpolation type
-    /// @param sampling the interpolation sampling
-    InterpolateAttribute(ProgramID pid,
-                         NodeID nid,
-                         const Source& src,
-                         InterpolationType type,
-                         InterpolationSampling sampling);
-    ~InterpolateAttribute() override;
-
-    /// @returns the WGSL name for the attribute
-    std::string Name() const override;
-
-    /// Clones this node and all transitive child nodes using the `CloneContext`
-    /// `ctx`.
-    /// @param ctx the clone context
-    /// @return the newly cloned node
-    const InterpolateAttribute* Clone(CloneContext* ctx) const override;
-
-    /// The interpolation type
-    const InterpolationType type;
-
-    /// The interpolation sampling
-    const InterpolationSampling sampling;
-};
-
-}  // namespace tint::ast
-
-#endif  // SRC_TINT_AST_INTERPOLATE_ATTRIBUTE_H_
diff --git a/src/tint/ast/interpolate_attribute_test.cc b/src/tint/ast/interpolate_attribute_test.cc
index 6c1204f..472994d 100644
--- a/src/tint/ast/interpolate_attribute_test.cc
+++ b/src/tint/ast/interpolate_attribute_test.cc
@@ -12,14 +12,6 @@
 // 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/ast/interpolate_attribute_test.cc.tmpl
-//
-// Do not modify this file directly
-////////////////////////////////////////////////////////////////////////////////
-
 #include "src/tint/ast/interpolate_attribute.h"
 
 #include <string>
@@ -33,123 +25,11 @@
 using InterpolateAttributeTest = TestHelper;
 
 TEST_F(InterpolateAttributeTest, Creation) {
-    auto* d =
-        create<InterpolateAttribute>(InterpolationType::kLinear, InterpolationSampling::kCenter);
-    EXPECT_EQ(InterpolationType::kLinear, d->type);
-    EXPECT_EQ(InterpolationSampling::kCenter, d->sampling);
+    auto* d = create<InterpolateAttribute>(builtin::InterpolationType::kLinear,
+                                           builtin::InterpolationSampling::kCenter);
+    EXPECT_EQ(builtin::InterpolationType::kLinear, d->type);
+    EXPECT_EQ(builtin::InterpolationSampling::kCenter, d->sampling);
 }
 
-namespace interpolation_type_tests {
-
-namespace parse_print_tests {
-
-struct Case {
-    const char* string;
-    InterpolationType value;
-};
-
-inline std::ostream& operator<<(std::ostream& out, Case c) {
-    return out << "'" << std::string(c.string) << "'";
-}
-
-static constexpr Case kValidCases[] = {
-    {"flat", InterpolationType::kFlat},
-    {"linear", InterpolationType::kLinear},
-    {"perspective", InterpolationType::kPerspective},
-};
-
-static constexpr Case kInvalidCases[] = {
-    {"ccat", InterpolationType::kUndefined},          {"3", InterpolationType::kUndefined},
-    {"fVat", InterpolationType::kUndefined},          {"1inear", InterpolationType::kUndefined},
-    {"lnqqar", InterpolationType::kUndefined},        {"linell77", InterpolationType::kUndefined},
-    {"perppHqective", InterpolationType::kUndefined}, {"cespctve", InterpolationType::kUndefined},
-    {"ebGpective", InterpolationType::kUndefined},
-};
-
-using InterpolationTypeParseTest = testing::TestWithParam<Case>;
-
-TEST_P(InterpolationTypeParseTest, Parse) {
-    const char* string = GetParam().string;
-    InterpolationType expect = GetParam().value;
-    EXPECT_EQ(expect, ParseInterpolationType(string));
-}
-
-INSTANTIATE_TEST_SUITE_P(ValidCases, InterpolationTypeParseTest, testing::ValuesIn(kValidCases));
-INSTANTIATE_TEST_SUITE_P(InvalidCases,
-                         InterpolationTypeParseTest,
-                         testing::ValuesIn(kInvalidCases));
-
-using InterpolationTypePrintTest = testing::TestWithParam<Case>;
-
-TEST_P(InterpolationTypePrintTest, Print) {
-    InterpolationType value = GetParam().value;
-    const char* expect = GetParam().string;
-    EXPECT_EQ(expect, utils::ToString(value));
-}
-
-INSTANTIATE_TEST_SUITE_P(ValidCases, InterpolationTypePrintTest, testing::ValuesIn(kValidCases));
-
-}  // namespace parse_print_tests
-
-}  // namespace interpolation_type_tests
-
-namespace interpolation_sampling_tests {
-
-namespace parse_print_tests {
-
-struct Case {
-    const char* string;
-    InterpolationSampling value;
-};
-
-inline std::ostream& operator<<(std::ostream& out, Case c) {
-    return out << "'" << std::string(c.string) << "'";
-}
-
-static constexpr Case kValidCases[] = {
-    {"center", InterpolationSampling::kCenter},
-    {"centroid", InterpolationSampling::kCentroid},
-    {"sample", InterpolationSampling::kSample},
-};
-
-static constexpr Case kInvalidCases[] = {
-    {"cevteii", InterpolationSampling::kUndefined}, {"ceWWt8r", InterpolationSampling::kUndefined},
-    {"xxentr", InterpolationSampling::kUndefined},  {"ceXggrid", InterpolationSampling::kUndefined},
-    {"ceXriu", InterpolationSampling::kUndefined},  {"centr3id", InterpolationSampling::kUndefined},
-    {"sEmple", InterpolationSampling::kUndefined},  {"amTTlPP", InterpolationSampling::kUndefined},
-    {"ddamxxl", InterpolationSampling::kUndefined},
-};
-
-using InterpolationSamplingParseTest = testing::TestWithParam<Case>;
-
-TEST_P(InterpolationSamplingParseTest, Parse) {
-    const char* string = GetParam().string;
-    InterpolationSampling expect = GetParam().value;
-    EXPECT_EQ(expect, ParseInterpolationSampling(string));
-}
-
-INSTANTIATE_TEST_SUITE_P(ValidCases,
-                         InterpolationSamplingParseTest,
-                         testing::ValuesIn(kValidCases));
-INSTANTIATE_TEST_SUITE_P(InvalidCases,
-                         InterpolationSamplingParseTest,
-                         testing::ValuesIn(kInvalidCases));
-
-using InterpolationSamplingPrintTest = testing::TestWithParam<Case>;
-
-TEST_P(InterpolationSamplingPrintTest, Print) {
-    InterpolationSampling value = GetParam().value;
-    const char* expect = GetParam().string;
-    EXPECT_EQ(expect, utils::ToString(value));
-}
-
-INSTANTIATE_TEST_SUITE_P(ValidCases,
-                         InterpolationSamplingPrintTest,
-                         testing::ValuesIn(kValidCases));
-
-}  // namespace parse_print_tests
-
-}  // namespace interpolation_sampling_tests
-
 }  // namespace
 }  // namespace tint::ast
diff --git a/src/tint/ast/interpolate_attribute_test.cc.tmpl b/src/tint/ast/interpolate_attribute_test.cc.tmpl
deleted file mode 100644
index 1adc9ab..0000000
--- a/src/tint/ast/interpolate_attribute_test.cc.tmpl
+++ /dev/null
@@ -1,45 +0,0 @@
-{{- /*
---------------------------------------------------------------------------------
-Template file for use with tools/src/cmd/gen to generate interpolate_attribute_test.cc
-
-See:
-* tools/src/cmd/gen for structures used by this template
-* https://golang.org/pkg/text/template/ for documentation on the template syntax
---------------------------------------------------------------------------------
-*/ -}}
-
-{{- Import "src/tint/templates/enums.tmpl.inc" -}}
-
-#include "src/tint/ast/interpolate_attribute.h"
-
-#include <string>
-
-#include "src/tint/ast/test_helper.h"
-#include "src/tint/utils/string.h"
-
-namespace tint::ast {
-namespace {
-
-using InterpolateAttributeTest = TestHelper;
-
-TEST_F(InterpolateAttributeTest, Creation) {
-    auto* d =
-        create<InterpolateAttribute>(InterpolationType::kLinear, InterpolationSampling::kCenter);
-    EXPECT_EQ(InterpolationType::kLinear, d->type);
-    EXPECT_EQ(InterpolationSampling::kCenter, d->sampling);
-}
-
-namespace interpolation_type_tests {
-
-{{ Eval "TestParsePrintEnum" (Sem.Enum "interpolation_type")}}
-
-}  // namespace interpolation_type_tests
-
-namespace interpolation_sampling_tests {
-
-{{ Eval "TestParsePrintEnum" (Sem.Enum "interpolation_sampling")}}
-
-}  // namespace interpolation_sampling_tests
-
-}  // namespace
-}  // namespace tint::ast
diff --git a/src/tint/builtin/interpolation_sampling.cc b/src/tint/builtin/interpolation_sampling.cc
new file mode 100644
index 0000000..8b39930
--- /dev/null
+++ b/src/tint/builtin/interpolation_sampling.cc
@@ -0,0 +1,60 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/interpolation_sampling.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/interpolation_sampling.h"
+
+#include <string>
+
+namespace tint::builtin {
+
+/// ParseInterpolationSampling parses a InterpolationSampling from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or InterpolationSampling::kUndefined if the string could not be
+/// parsed.
+InterpolationSampling ParseInterpolationSampling(std::string_view str) {
+    if (str == "center") {
+        return InterpolationSampling::kCenter;
+    }
+    if (str == "centroid") {
+        return InterpolationSampling::kCentroid;
+    }
+    if (str == "sample") {
+        return InterpolationSampling::kSample;
+    }
+    return InterpolationSampling::kUndefined;
+}
+
+std::ostream& operator<<(std::ostream& out, InterpolationSampling value) {
+    switch (value) {
+        case InterpolationSampling::kUndefined:
+            return out << "undefined";
+        case InterpolationSampling::kCenter:
+            return out << "center";
+        case InterpolationSampling::kCentroid:
+            return out << "centroid";
+        case InterpolationSampling::kSample:
+            return out << "sample";
+    }
+    return out << "<unknown>";
+}
+
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_sampling.cc.tmpl b/src/tint/builtin/interpolation_sampling.cc.tmpl
new file mode 100644
index 0000000..1063ded
--- /dev/null
+++ b/src/tint/builtin/interpolation_sampling.cc.tmpl
@@ -0,0 +1,23 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate builtin_value.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#include "src/tint/builtin/interpolation_sampling.h"
+
+#include <string>
+
+namespace tint::builtin {
+
+{{ Eval "ParseEnum" (Sem.Enum "interpolation_sampling")}}
+
+{{ Eval "EnumOStream" (Sem.Enum "interpolation_sampling")}}
+
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_sampling.h b/src/tint/builtin/interpolation_sampling.h
new file mode 100644
index 0000000..a3fc357
--- /dev/null
+++ b/src/tint/builtin/interpolation_sampling.h
@@ -0,0 +1,58 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/interpolation_sampling.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_TINT_BUILTIN_INTERPOLATION_SAMPLING_H_
+#define SRC_TINT_BUILTIN_INTERPOLATION_SAMPLING_H_
+
+#include <ostream>
+#include <string>
+
+namespace tint::builtin {
+
+/// The interpolation sampling.
+enum class InterpolationSampling {
+    kUndefined,
+    kCenter,
+    kCentroid,
+    kSample,
+};
+
+/// @param out the std::ostream to write to
+/// @param value the InterpolationSampling
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, InterpolationSampling value);
+
+/// ParseInterpolationSampling parses a InterpolationSampling from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or InterpolationSampling::kUndefined if the string could not be
+/// parsed.
+InterpolationSampling ParseInterpolationSampling(std::string_view str);
+
+constexpr const char* kInterpolationSamplingStrings[] = {
+    "center",
+    "centroid",
+    "sample",
+};
+
+}  // namespace tint::builtin
+
+#endif  // SRC_TINT_BUILTIN_INTERPOLATION_SAMPLING_H_
diff --git a/src/tint/builtin/interpolation_sampling.h.tmpl b/src/tint/builtin/interpolation_sampling.h.tmpl
new file mode 100644
index 0000000..24b3b02
--- /dev/null
+++ b/src/tint/builtin/interpolation_sampling.h.tmpl
@@ -0,0 +1,26 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate interpolate_attribute.h
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#ifndef SRC_TINT_BUILTIN_INTERPOLATION_SAMPLING_H_
+#define SRC_TINT_BUILTIN_INTERPOLATION_SAMPLING_H_
+
+#include <ostream>
+#include <string>
+
+namespace tint::builtin {
+
+/// The interpolation sampling.
+{{ Eval "DeclareEnum" (Sem.Enum "interpolation_sampling") }}
+
+}  // namespace tint::builtin
+
+#endif  // SRC_TINT_BUILTIN_INTERPOLATION_SAMPLING_H_
diff --git a/src/tint/builtin/interpolation_sampling_bench.cc b/src/tint/builtin/interpolation_sampling_bench.cc
new file mode 100644
index 0000000..4fb7e09
--- /dev/null
+++ b/src/tint/builtin/interpolation_sampling_bench.cc
@@ -0,0 +1,48 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/interpolation_sampling_bench.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include <array>
+
+#include "benchmark/benchmark.h"
+#include "src/tint/builtin/interpolation_sampling.h"
+
+namespace tint::builtin {
+namespace {
+
+void InterpolationSamplingParser(::benchmark::State& state) {
+    const char* kStrings[] = {
+        "ccnter",     "c3r",   "centeV",  "center",   "1enter",    "cnqqer",    "centll77",
+        "qqenrppHid", "cntov", "cenGoid", "centroid", "ceviiroid", "ceWWtro8d", "cxxtMoid",
+        "saXggl",     "Xmle",  "sam3le",  "sample",   "sEmple",    "amTTlPP",   "ddamxxl",
+    };
+    for (auto _ : state) {
+        for (auto* str : kStrings) {
+            auto result = ParseInterpolationSampling(str);
+            benchmark::DoNotOptimize(result);
+        }
+    }
+}
+
+BENCHMARK(InterpolationSamplingParser);
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/ast/interpolate_attribute_bench.cc.tmpl b/src/tint/builtin/interpolation_sampling_bench.cc.tmpl
similarity index 78%
copy from src/tint/ast/interpolate_attribute_bench.cc.tmpl
copy to src/tint/builtin/interpolation_sampling_bench.cc.tmpl
index b75fe44..b2b29f4 100644
--- a/src/tint/ast/interpolate_attribute_bench.cc.tmpl
+++ b/src/tint/builtin/interpolation_sampling_bench.cc.tmpl
@@ -10,18 +10,15 @@
 
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 
-#include "src/tint/ast/interpolate_attribute.h"
-
 #include <array>
 
 #include "benchmark/benchmark.h"
+#include "src/tint/builtin/interpolation_sampling.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
-{{ Eval "BenchmarkParseEnum" (Sem.Enum "interpolation_type")}}
-
 {{ Eval "BenchmarkParseEnum" (Sem.Enum "interpolation_sampling")}}
 
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_sampling_test.cc b/src/tint/builtin/interpolation_sampling_test.cc
new file mode 100644
index 0000000..db497a8
--- /dev/null
+++ b/src/tint/builtin/interpolation_sampling_test.cc
@@ -0,0 +1,96 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/interpolation_sampling_test.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/interpolation_sampling.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+#include "src/tint/utils/string.h"
+
+namespace tint::builtin {
+namespace {
+
+namespace interpolation_sampling_tests {
+
+namespace parse_print_tests {
+
+struct Case {
+    const char* string;
+    InterpolationSampling value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+    return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+    {"center", InterpolationSampling::kCenter},
+    {"centroid", InterpolationSampling::kCentroid},
+    {"sample", InterpolationSampling::kSample},
+};
+
+static constexpr Case kInvalidCases[] = {
+    {"ccnter", InterpolationSampling::kUndefined},
+    {"c3r", InterpolationSampling::kUndefined},
+    {"centeV", InterpolationSampling::kUndefined},
+    {"1entroid", InterpolationSampling::kUndefined},
+    {"enJrqqid", InterpolationSampling::kUndefined},
+    {"llen77roid", InterpolationSampling::kUndefined},
+    {"sapppHHe", InterpolationSampling::kUndefined},
+    {"cam", InterpolationSampling::kUndefined},
+    {"sbGpl", InterpolationSampling::kUndefined},
+};
+
+using InterpolationSamplingParseTest = testing::TestWithParam<Case>;
+
+TEST_P(InterpolationSamplingParseTest, Parse) {
+    const char* string = GetParam().string;
+    InterpolationSampling expect = GetParam().value;
+    EXPECT_EQ(expect, ParseInterpolationSampling(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases,
+                         InterpolationSamplingParseTest,
+                         testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases,
+                         InterpolationSamplingParseTest,
+                         testing::ValuesIn(kInvalidCases));
+
+using InterpolationSamplingPrintTest = testing::TestWithParam<Case>;
+
+TEST_P(InterpolationSamplingPrintTest, Print) {
+    InterpolationSampling value = GetParam().value;
+    const char* expect = GetParam().string;
+    EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases,
+                         InterpolationSamplingPrintTest,
+                         testing::ValuesIn(kValidCases));
+
+}  // namespace parse_print_tests
+
+}  // namespace interpolation_sampling_tests
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_sampling_test.cc.tmpl b/src/tint/builtin/interpolation_sampling_test.cc.tmpl
new file mode 100644
index 0000000..ed77d63
--- /dev/null
+++ b/src/tint/builtin/interpolation_sampling_test.cc.tmpl
@@ -0,0 +1,30 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate interpolate_attribute_test.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#include "src/tint/builtin/interpolation_sampling.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+#include "src/tint/utils/string.h"
+
+namespace tint::builtin {
+namespace {
+
+namespace interpolation_sampling_tests {
+
+{{ Eval "TestParsePrintEnum" (Sem.Enum "interpolation_sampling")}}
+
+}  // namespace interpolation_sampling_tests
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_type.cc b/src/tint/builtin/interpolation_type.cc
new file mode 100644
index 0000000..ee3f68b
--- /dev/null
+++ b/src/tint/builtin/interpolation_type.cc
@@ -0,0 +1,59 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/interpolation_type.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/interpolation_type.h"
+
+#include <string>
+
+namespace tint::builtin {
+
+/// ParseInterpolationType parses a InterpolationType from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or InterpolationType::kUndefined if the string could not be parsed.
+InterpolationType ParseInterpolationType(std::string_view str) {
+    if (str == "flat") {
+        return InterpolationType::kFlat;
+    }
+    if (str == "linear") {
+        return InterpolationType::kLinear;
+    }
+    if (str == "perspective") {
+        return InterpolationType::kPerspective;
+    }
+    return InterpolationType::kUndefined;
+}
+
+std::ostream& operator<<(std::ostream& out, InterpolationType value) {
+    switch (value) {
+        case InterpolationType::kUndefined:
+            return out << "undefined";
+        case InterpolationType::kFlat:
+            return out << "flat";
+        case InterpolationType::kLinear:
+            return out << "linear";
+        case InterpolationType::kPerspective:
+            return out << "perspective";
+    }
+    return out << "<unknown>";
+}
+
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_type.cc.tmpl b/src/tint/builtin/interpolation_type.cc.tmpl
new file mode 100644
index 0000000..4158a29
--- /dev/null
+++ b/src/tint/builtin/interpolation_type.cc.tmpl
@@ -0,0 +1,23 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate builtin_value.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#include "src/tint/builtin/interpolation_type.h"
+
+#include <string>
+
+namespace tint::builtin {
+
+{{ Eval "ParseEnum" (Sem.Enum "interpolation_type")}}
+
+{{ Eval "EnumOStream" (Sem.Enum "interpolation_type")}}
+
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_type.h b/src/tint/builtin/interpolation_type.h
new file mode 100644
index 0000000..ee54964
--- /dev/null
+++ b/src/tint/builtin/interpolation_type.h
@@ -0,0 +1,57 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/interpolation_type.h.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef SRC_TINT_BUILTIN_INTERPOLATION_TYPE_H_
+#define SRC_TINT_BUILTIN_INTERPOLATION_TYPE_H_
+
+#include <ostream>
+#include <string>
+
+namespace tint::builtin {
+
+/// The interpolation type.
+enum class InterpolationType {
+    kUndefined,
+    kFlat,
+    kLinear,
+    kPerspective,
+};
+
+/// @param out the std::ostream to write to
+/// @param value the InterpolationType
+/// @returns `out` so calls can be chained
+std::ostream& operator<<(std::ostream& out, InterpolationType value);
+
+/// ParseInterpolationType parses a InterpolationType from a string.
+/// @param str the string to parse
+/// @returns the parsed enum, or InterpolationType::kUndefined if the string could not be parsed.
+InterpolationType ParseInterpolationType(std::string_view str);
+
+constexpr const char* kInterpolationTypeStrings[] = {
+    "flat",
+    "linear",
+    "perspective",
+};
+
+}  // namespace tint::builtin
+
+#endif  // SRC_TINT_BUILTIN_INTERPOLATION_TYPE_H_
diff --git a/src/tint/builtin/interpolation_type.h.tmpl b/src/tint/builtin/interpolation_type.h.tmpl
new file mode 100644
index 0000000..c869a96
--- /dev/null
+++ b/src/tint/builtin/interpolation_type.h.tmpl
@@ -0,0 +1,26 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate interpolate_attribute.h
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#ifndef SRC_TINT_BUILTIN_INTERPOLATION_TYPE_H_
+#define SRC_TINT_BUILTIN_INTERPOLATION_TYPE_H_
+
+#include <ostream>
+#include <string>
+
+namespace tint::builtin {
+
+/// The interpolation type.
+{{ Eval "DeclareEnum" (Sem.Enum "interpolation_type") }}
+
+}  // namespace tint::builtin
+
+#endif  // SRC_TINT_BUILTIN_INTERPOLATION_TYPE_H_
diff --git a/src/tint/ast/interpolate_attribute_bench.cc b/src/tint/builtin/interpolation_type_bench.cc
similarity index 66%
rename from src/tint/ast/interpolate_attribute_bench.cc
rename to src/tint/builtin/interpolation_type_bench.cc
index 722cb06..5098f26 100644
--- a/src/tint/ast/interpolate_attribute_bench.cc
+++ b/src/tint/builtin/interpolation_type_bench.cc
@@ -1,4 +1,4 @@
-// Copyright 2022 The Tint Authors.
+// 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.
@@ -15,18 +15,18 @@
 ////////////////////////////////////////////////////////////////////////////////
 // File generated by tools/src/cmd/gen
 // using the template:
-//   src/tint/ast/interpolate_attribute_bench.cc.tmpl
+//   src/tint/builtin/interpolation_type_bench.cc.tmpl
 //
 // Do not modify this file directly
 ////////////////////////////////////////////////////////////////////////////////
 
-#include "src/tint/ast/interpolate_attribute.h"
+#include "src/tint/builtin/interpolation_type.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
 void InterpolationTypeParser(::benchmark::State& state) {
@@ -47,21 +47,5 @@
 
 BENCHMARK(InterpolationTypeParser);
 
-void InterpolationSamplingParser(::benchmark::State& state) {
-    const char* kStrings[] = {
-        "44enter", "cSSVVter",     "centRr",     "center",   "ent9r",  "cente",   "VentORr",
-        "cenyroi", "77errtrllnid", "04entroid",  "centroid", "enooid", "centzzd", "ceiippr1i",
-        "saXXple", "55IImpnn99",   "aHHrrmplSS", "sample",   "kkle",   "jagRR",   "smbe",
-    };
-    for (auto _ : state) {
-        for (auto* str : kStrings) {
-            auto result = ParseInterpolationSampling(str);
-            benchmark::DoNotOptimize(result);
-        }
-    }
-}
-
-BENCHMARK(InterpolationSamplingParser);
-
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/ast/interpolate_attribute_bench.cc.tmpl b/src/tint/builtin/interpolation_type_bench.cc.tmpl
similarity index 78%
rename from src/tint/ast/interpolate_attribute_bench.cc.tmpl
rename to src/tint/builtin/interpolation_type_bench.cc.tmpl
index b75fe44..1b5df2e 100644
--- a/src/tint/ast/interpolate_attribute_bench.cc.tmpl
+++ b/src/tint/builtin/interpolation_type_bench.cc.tmpl
@@ -10,18 +10,16 @@
 
 {{- Import "src/tint/templates/enums.tmpl.inc" -}}
 
-#include "src/tint/ast/interpolate_attribute.h"
+#include "src/tint/builtin/interpolation_type.h"
 
 #include <array>
 
 #include "benchmark/benchmark.h"
 
-namespace tint::ast {
+namespace tint::builtin {
 namespace {
 
 {{ Eval "BenchmarkParseEnum" (Sem.Enum "interpolation_type")}}
 
-{{ Eval "BenchmarkParseEnum" (Sem.Enum "interpolation_sampling")}}
-
 }  // namespace
-}  // namespace tint::ast
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_type_test.cc b/src/tint/builtin/interpolation_type_test.cc
new file mode 100644
index 0000000..96e7094
--- /dev/null
+++ b/src/tint/builtin/interpolation_type_test.cc
@@ -0,0 +1,88 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+////////////////////////////////////////////////////////////////////////////////
+// File generated by tools/src/cmd/gen
+// using the template:
+//   src/tint/builtin/interpolation_type_test.cc.tmpl
+//
+// Do not modify this file directly
+////////////////////////////////////////////////////////////////////////////////
+
+#include "src/tint/builtin/interpolation_type.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+#include "src/tint/utils/string.h"
+
+namespace tint::builtin {
+namespace {
+
+namespace interpolation_type_tests {
+
+namespace parse_print_tests {
+
+struct Case {
+    const char* string;
+    InterpolationType value;
+};
+
+inline std::ostream& operator<<(std::ostream& out, Case c) {
+    return out << "'" << std::string(c.string) << "'";
+}
+
+static constexpr Case kValidCases[] = {
+    {"flat", InterpolationType::kFlat},
+    {"linear", InterpolationType::kLinear},
+    {"perspective", InterpolationType::kPerspective},
+};
+
+static constexpr Case kInvalidCases[] = {
+    {"ccat", InterpolationType::kUndefined},          {"3", InterpolationType::kUndefined},
+    {"fVat", InterpolationType::kUndefined},          {"1inear", InterpolationType::kUndefined},
+    {"lnqqar", InterpolationType::kUndefined},        {"linell77", InterpolationType::kUndefined},
+    {"perppHqective", InterpolationType::kUndefined}, {"cespctve", InterpolationType::kUndefined},
+    {"ebGpective", InterpolationType::kUndefined},
+};
+
+using InterpolationTypeParseTest = testing::TestWithParam<Case>;
+
+TEST_P(InterpolationTypeParseTest, Parse) {
+    const char* string = GetParam().string;
+    InterpolationType expect = GetParam().value;
+    EXPECT_EQ(expect, ParseInterpolationType(string));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, InterpolationTypeParseTest, testing::ValuesIn(kValidCases));
+INSTANTIATE_TEST_SUITE_P(InvalidCases,
+                         InterpolationTypeParseTest,
+                         testing::ValuesIn(kInvalidCases));
+
+using InterpolationTypePrintTest = testing::TestWithParam<Case>;
+
+TEST_P(InterpolationTypePrintTest, Print) {
+    InterpolationType value = GetParam().value;
+    const char* expect = GetParam().string;
+    EXPECT_EQ(expect, utils::ToString(value));
+}
+
+INSTANTIATE_TEST_SUITE_P(ValidCases, InterpolationTypePrintTest, testing::ValuesIn(kValidCases));
+
+}  // namespace parse_print_tests
+
+}  // namespace interpolation_type_tests
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/builtin/interpolation_type_test.cc.tmpl b/src/tint/builtin/interpolation_type_test.cc.tmpl
new file mode 100644
index 0000000..a1a48b9
--- /dev/null
+++ b/src/tint/builtin/interpolation_type_test.cc.tmpl
@@ -0,0 +1,30 @@
+{{- /*
+--------------------------------------------------------------------------------
+Template file for use with tools/src/cmd/gen to generate interpolate_attribute_test.cc
+
+See:
+* tools/src/cmd/gen for structures used by this template
+* https://golang.org/pkg/text/template/ for documentation on the template syntax
+--------------------------------------------------------------------------------
+*/ -}}
+
+{{- Import "src/tint/templates/enums.tmpl.inc" -}}
+
+#include "src/tint/builtin/interpolation_type.h"
+
+#include <gtest/gtest.h>
+#include <string>
+
+#include "src/tint/utils/string.h"
+
+namespace tint::builtin {
+namespace {
+
+namespace interpolation_type_tests {
+
+{{ Eval "TestParsePrintEnum" (Sem.Enum "interpolation_type")}}
+
+}  // namespace interpolation_type_tests
+
+}  // namespace
+}  // namespace tint::builtin
diff --git a/src/tint/inspector/inspector.cc b/src/tint/inspector/inspector.cc
index 0863db3..e3706cf 100644
--- a/src/tint/inspector/inspector.cc
+++ b/src/tint/inspector/inspector.cc
@@ -129,38 +129,38 @@
 
     auto ast_interpolation_type = interpolation_attribute->type;
     auto ast_sampling_type = interpolation_attribute->sampling;
-    if (ast_interpolation_type != ast::InterpolationType::kFlat &&
-        ast_sampling_type == ast::InterpolationSampling::kUndefined) {
-        ast_sampling_type = ast::InterpolationSampling::kCenter;
+    if (ast_interpolation_type != builtin::InterpolationType::kFlat &&
+        ast_sampling_type == builtin::InterpolationSampling::kUndefined) {
+        ast_sampling_type = builtin::InterpolationSampling::kCenter;
     }
 
     auto interpolation_type = InterpolationType::kUnknown;
     switch (ast_interpolation_type) {
-        case ast::InterpolationType::kPerspective:
+        case builtin::InterpolationType::kPerspective:
             interpolation_type = InterpolationType::kPerspective;
             break;
-        case ast::InterpolationType::kLinear:
+        case builtin::InterpolationType::kLinear:
             interpolation_type = InterpolationType::kLinear;
             break;
-        case ast::InterpolationType::kFlat:
+        case builtin::InterpolationType::kFlat:
             interpolation_type = InterpolationType::kFlat;
             break;
-        case ast::InterpolationType::kUndefined:
+        case builtin::InterpolationType::kUndefined:
             break;
     }
 
     auto sampling_type = InterpolationSampling::kUnknown;
     switch (ast_sampling_type) {
-        case ast::InterpolationSampling::kUndefined:
+        case builtin::InterpolationSampling::kUndefined:
             sampling_type = InterpolationSampling::kNone;
             break;
-        case ast::InterpolationSampling::kCenter:
+        case builtin::InterpolationSampling::kCenter:
             sampling_type = InterpolationSampling::kCenter;
             break;
-        case ast::InterpolationSampling::kCentroid:
+        case builtin::InterpolationSampling::kCentroid:
             sampling_type = InterpolationSampling::kCentroid;
             break;
-        case ast::InterpolationSampling::kSample:
+        case builtin::InterpolationSampling::kSample:
             sampling_type = InterpolationSampling::kSample;
             break;
     }
diff --git a/src/tint/inspector/inspector_test.cc b/src/tint/inspector/inspector_test.cc
index 13197bd..361b8db 100644
--- a/src/tint/inspector/inspector_test.cc
+++ b/src/tint/inspector/inspector_test.cc
@@ -51,8 +51,8 @@
     : public InspectorBuilder,
       public testing::TestWithParam<InspectorGetEntryPointComponentAndCompositionTestParams> {};
 struct InspectorGetEntryPointInterpolateTestParams {
-    ast::InterpolationType in_type;
-    ast::InterpolationSampling in_sampling;
+    builtin::InterpolationType in_type;
+    builtin::InterpolationSampling in_sampling;
     inspector::InterpolationType out_type;
     inspector::InterpolationSampling out_sampling;
 };
@@ -1436,31 +1436,31 @@
     InspectorGetEntryPointInterpolateTest,
     testing::Values(
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kPerspective, ast::InterpolationSampling::kCenter,
+            builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kCenter,
             InterpolationType::kPerspective, InterpolationSampling::kCenter},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kPerspective, ast::InterpolationSampling::kCentroid,
+            builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kCentroid,
             InterpolationType::kPerspective, InterpolationSampling::kCentroid},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kPerspective, ast::InterpolationSampling::kSample,
+            builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kSample,
             InterpolationType::kPerspective, InterpolationSampling::kSample},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kPerspective, ast::InterpolationSampling::kUndefined,
+            builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kUndefined,
             InterpolationType::kPerspective, InterpolationSampling::kCenter},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kLinear, ast::InterpolationSampling::kCenter,
+            builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kCenter,
             InterpolationType::kLinear, InterpolationSampling::kCenter},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kLinear, ast::InterpolationSampling::kCentroid,
+            builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kCentroid,
             InterpolationType::kLinear, InterpolationSampling::kCentroid},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kLinear, ast::InterpolationSampling::kSample,
+            builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kSample,
             InterpolationType::kLinear, InterpolationSampling::kSample},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kLinear, ast::InterpolationSampling::kUndefined,
+            builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kUndefined,
             InterpolationType::kLinear, InterpolationSampling::kCenter},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kFlat, ast::InterpolationSampling::kUndefined,
+            builtin::InterpolationType::kFlat, builtin::InterpolationSampling::kUndefined,
             InterpolationType::kFlat, InterpolationSampling::kNone}));
 
 TEST_F(InspectorGetOverrideDefaultValuesTest, Bool) {
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index 0b678dc..f132900 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -3463,8 +3463,8 @@
     /// @returns the interpolate attribute pointer
     const ast::InterpolateAttribute* Interpolate(
         const Source& source,
-        ast::InterpolationType type,
-        ast::InterpolationSampling sampling = ast::InterpolationSampling::kUndefined) {
+        builtin::InterpolationType type,
+        builtin::InterpolationSampling sampling = builtin::InterpolationSampling::kUndefined) {
         return create<ast::InterpolateAttribute>(source, type, sampling);
     }
 
@@ -3473,8 +3473,8 @@
     /// @param sampling the interpolation sampling
     /// @returns the interpolate attribute pointer
     const ast::InterpolateAttribute* Interpolate(
-        ast::InterpolationType type,
-        ast::InterpolationSampling sampling = ast::InterpolationSampling::kUndefined) {
+        builtin::InterpolationType type,
+        builtin::InterpolationSampling sampling = builtin::InterpolationSampling::kUndefined) {
         return create<ast::InterpolateAttribute>(source_, type, sampling);
     }
 
@@ -3482,12 +3482,14 @@
     /// @param source the source information
     /// @returns the interpolate attribute pointer
     const ast::InterpolateAttribute* Flat(const Source& source) {
-        return Interpolate(source, ast::InterpolationType::kFlat);
+        return Interpolate(source, builtin::InterpolationType::kFlat);
     }
 
     /// Creates an ast::InterpolateAttribute using flat interpolation
     /// @returns the interpolate attribute pointer
-    const ast::InterpolateAttribute* Flat() { return Interpolate(ast::InterpolationType::kFlat); }
+    const ast::InterpolateAttribute* Flat() {
+        return Interpolate(builtin::InterpolationType::kFlat);
+    }
 
     /// Creates an ast::InvariantAttribute
     /// @param source the source information
diff --git a/src/tint/reader/spirv/parser_impl.cc b/src/tint/reader/spirv/parser_impl.cc
index b4e23b8..35df789 100644
--- a/src/tint/reader/spirv/parser_impl.cc
+++ b/src/tint/reader/spirv/parser_impl.cc
@@ -1775,8 +1775,8 @@
                                             const DecorationList& decorations,
                                             AttributeList* attributes) {
     // Vulkan defaults to perspective-correct interpolation.
-    ast::InterpolationType type = ast::InterpolationType::kPerspective;
-    ast::InterpolationSampling sampling = ast::InterpolationSampling::kUndefined;
+    builtin::InterpolationType type = builtin::InterpolationType::kPerspective;
+    builtin::InterpolationSampling sampling = builtin::InterpolationSampling::kUndefined;
 
     for (const auto& deco : decorations) {
         TINT_ASSERT(Reader, deco.size() > 0);
@@ -1789,49 +1789,49 @@
                 SetLocation(attributes, builder_.Location(AInt(deco[1])));
                 if (store_type->IsIntegerScalarOrVector()) {
                     // Default to flat interpolation for integral user-defined IO types.
-                    type = ast::InterpolationType::kFlat;
+                    type = builtin::InterpolationType::kFlat;
                 }
                 break;
             case spv::Decoration::Flat:
-                type = ast::InterpolationType::kFlat;
+                type = builtin::InterpolationType::kFlat;
                 break;
             case spv::Decoration::NoPerspective:
                 if (store_type->IsIntegerScalarOrVector()) {
                     // This doesn't capture the array or struct case.
                     return Fail() << "NoPerspective is invalid on integral IO";
                 }
-                type = ast::InterpolationType::kLinear;
+                type = builtin::InterpolationType::kLinear;
                 break;
             case spv::Decoration::Centroid:
                 if (store_type->IsIntegerScalarOrVector()) {
                     // This doesn't capture the array or struct case.
                     return Fail() << "Centroid interpolation sampling is invalid on integral IO";
                 }
-                sampling = ast::InterpolationSampling::kCentroid;
+                sampling = builtin::InterpolationSampling::kCentroid;
                 break;
             case spv::Decoration::Sample:
                 if (store_type->IsIntegerScalarOrVector()) {
                     // This doesn't capture the array or struct case.
                     return Fail() << "Sample interpolation sampling is invalid on integral IO";
                 }
-                sampling = ast::InterpolationSampling::kSample;
+                sampling = builtin::InterpolationSampling::kSample;
                 break;
             default:
                 break;
         }
     }
 
-    if (type == ast::InterpolationType::kFlat &&
+    if (type == builtin::InterpolationType::kFlat &&
         !ast::HasAttribute<ast::LocationAttribute>(*attributes)) {
         // WGSL requires that '@interpolate(flat)' needs to be paired with '@location', however
         // SPIR-V requires all fragment shader integer Inputs are 'flat'. If the decorations do not
         // contain a spv::Decoration::Location, then make this perspective.
-        type = ast::InterpolationType::kPerspective;
+        type = builtin::InterpolationType::kPerspective;
     }
 
     // Apply interpolation.
-    if (type == ast::InterpolationType::kPerspective &&
-        sampling == ast::InterpolationSampling::kUndefined) {
+    if (type == builtin::InterpolationType::kPerspective &&
+        sampling == builtin::InterpolationSampling::kUndefined) {
         // This is the default. Don't add a decoration.
     } else {
         attributes->Push(create<ast::InterpolateAttribute>(type, sampling));
diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc
index ba9f7eb..e333efe 100644
--- a/src/tint/reader/wgsl/parser_impl.cc
+++ b/src/tint/reader/wgsl/parser_impl.cc
@@ -1115,18 +1115,18 @@
 //   : 'center'
 //   | 'centroid'
 //   | 'sample'
-Expect<ast::InterpolationSampling> ParserImpl::expect_interpolation_sample_name() {
-    return expect_enum("interpolation sampling", ast::ParseInterpolationSampling,
-                       ast::kInterpolationSamplingStrings);
+Expect<builtin::InterpolationSampling> ParserImpl::expect_interpolation_sample_name() {
+    return expect_enum("interpolation sampling", builtin::ParseInterpolationSampling,
+                       builtin::kInterpolationSamplingStrings);
 }
 
 // interpolation_type_name
 //   : 'perspective'
 //   | 'linear'
 //   | 'flat'
-Expect<ast::InterpolationType> ParserImpl::expect_interpolation_type_name() {
-    return expect_enum("interpolation type", ast::ParseInterpolationType,
-                       ast::kInterpolationTypeStrings);
+Expect<builtin::InterpolationType> ParserImpl::expect_interpolation_type_name() {
+    return expect_enum("interpolation type", builtin::ParseInterpolationType,
+                       builtin::kInterpolationTypeStrings);
 }
 
 // builtin_value_name
@@ -3091,7 +3091,7 @@
                 return Failure::kErrored;
             }
 
-            ast::InterpolationSampling sampling = ast::InterpolationSampling::kUndefined;
+            builtin::InterpolationSampling sampling = builtin::InterpolationSampling::kUndefined;
             if (match(Token::Type::kComma)) {
                 if (!peek_is(Token::Type::kParenRight)) {
                     auto sample = expect_interpolation_sample_name();
diff --git a/src/tint/reader/wgsl/parser_impl.h b/src/tint/reader/wgsl/parser_impl.h
index e67d745..759e88d 100644
--- a/src/tint/reader/wgsl/parser_impl.h
+++ b/src/tint/reader/wgsl/parser_impl.h
@@ -457,11 +457,11 @@
     /// Parses an interpolation sample name identifier, erroring if the next token does not match a
     /// valid sample name.
     /// @returns the parsed sample name.
-    Expect<ast::InterpolationSampling> expect_interpolation_sample_name();
+    Expect<builtin::InterpolationSampling> expect_interpolation_sample_name();
     /// Parses an interpolation type name identifier, erroring if the next token does not match a
     /// value type name.
     /// @returns the parsed type name
-    Expect<ast::InterpolationType> expect_interpolation_type_name();
+    Expect<builtin::InterpolationType> expect_interpolation_type_name();
     /// Parses a builtin identifier, erroring if the next token does not match a
     /// valid builtin name.
     /// @returns the parsed builtin.
diff --git a/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc b/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc
index bc0c2c9..9468d1c 100644
--- a/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc
@@ -352,8 +352,8 @@
     ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
     auto* interp = var_attr->As<ast::InterpolateAttribute>();
-    EXPECT_EQ(interp->type, ast::InterpolationType::kFlat);
-    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kUndefined);
+    EXPECT_EQ(interp->type, builtin::InterpolationType::kFlat);
+    EXPECT_EQ(interp->sampling, builtin::InterpolationSampling::kUndefined);
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Single_TrailingComma) {
@@ -368,8 +368,8 @@
     ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
     auto* interp = var_attr->As<ast::InterpolateAttribute>();
-    EXPECT_EQ(interp->type, ast::InterpolationType::kFlat);
-    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kUndefined);
+    EXPECT_EQ(interp->type, builtin::InterpolationType::kFlat);
+    EXPECT_EQ(interp->sampling, builtin::InterpolationSampling::kUndefined);
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Single_DoubleTrailingComma) {
@@ -395,8 +395,8 @@
     ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
     auto* interp = var_attr->As<ast::InterpolateAttribute>();
-    EXPECT_EQ(interp->type, ast::InterpolationType::kPerspective);
-    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kCenter);
+    EXPECT_EQ(interp->type, builtin::InterpolationType::kPerspective);
+    EXPECT_EQ(interp->sampling, builtin::InterpolationSampling::kCenter);
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Double_TrailingComma) {
@@ -411,8 +411,8 @@
     ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
     auto* interp = var_attr->As<ast::InterpolateAttribute>();
-    EXPECT_EQ(interp->type, ast::InterpolationType::kPerspective);
-    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kCenter);
+    EXPECT_EQ(interp->type, builtin::InterpolationType::kPerspective);
+    EXPECT_EQ(interp->sampling, builtin::InterpolationSampling::kCenter);
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Perspective_Centroid) {
@@ -427,8 +427,8 @@
     ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
     auto* interp = var_attr->As<ast::InterpolateAttribute>();
-    EXPECT_EQ(interp->type, ast::InterpolationType::kPerspective);
-    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kCentroid);
+    EXPECT_EQ(interp->type, builtin::InterpolationType::kPerspective);
+    EXPECT_EQ(interp->sampling, builtin::InterpolationSampling::kCentroid);
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Linear_Sample) {
@@ -443,8 +443,8 @@
     ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
     auto* interp = var_attr->As<ast::InterpolateAttribute>();
-    EXPECT_EQ(interp->type, ast::InterpolationType::kLinear);
-    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kSample);
+    EXPECT_EQ(interp->type, builtin::InterpolationType::kLinear);
+    EXPECT_EQ(interp->sampling, builtin::InterpolationSampling::kSample);
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_MissingLeftParen) {
diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc
index 982b865..3255c49 100644
--- a/src/tint/resolver/attribute_validation_test.cc
+++ b/src/tint/resolver/attribute_validation_test.cc
@@ -104,8 +104,8 @@
         case AttributeKind::kId:
             return {builder.Id(source, 0_a)};
         case AttributeKind::kInterpolate:
-            return {builder.Interpolate(source, ast::InterpolationType::kLinear,
-                                        ast::InterpolationSampling::kCenter)};
+            return {builder.Interpolate(source, builtin::InterpolationType::kLinear,
+                                        builtin::InterpolationSampling::kCenter)};
         case AttributeKind::kInvariant:
             return {builder.Invariant(source)};
         case AttributeKind::kLocation:
@@ -1488,8 +1488,8 @@
 using InterpolateTest = ResolverTest;
 
 struct Params {
-    ast::InterpolationType type;
-    ast::InterpolationSampling sampling;
+    builtin::InterpolationType type;
+    builtin::InterpolationSampling sampling;
     bool should_pass;
 };
 
@@ -1538,7 +1538,7 @@
              Stage(ast::PipelineStage::kFragment),
          });
 
-    if (params.type != ast::InterpolationType::kFlat) {
+    if (params.type != builtin::InterpolationType::kFlat) {
         EXPECT_FALSE(r()->Resolve());
         EXPECT_EQ(r()->error(),
                   "12:34 error: interpolation type must be 'flat' for integral "
@@ -1569,7 +1569,7 @@
              Stage(ast::PipelineStage::kFragment),
          });
 
-    if (params.type != ast::InterpolationType::kFlat) {
+    if (params.type != builtin::InterpolationType::kFlat) {
         EXPECT_FALSE(r()->Resolve());
         EXPECT_EQ(r()->error(),
                   "12:34 error: interpolation type must be 'flat' for integral "
@@ -1588,19 +1588,25 @@
     ResolverAttributeValidationTest,
     InterpolateParameterTest,
     testing::Values(
-        Params{ast::InterpolationType::kPerspective, ast::InterpolationSampling::kUndefined, true},
-        Params{ast::InterpolationType::kPerspective, ast::InterpolationSampling::kCenter, true},
-        Params{ast::InterpolationType::kPerspective, ast::InterpolationSampling::kCentroid, true},
-        Params{ast::InterpolationType::kPerspective, ast::InterpolationSampling::kSample, true},
-        Params{ast::InterpolationType::kLinear, ast::InterpolationSampling::kUndefined, true},
-        Params{ast::InterpolationType::kLinear, ast::InterpolationSampling::kCenter, true},
-        Params{ast::InterpolationType::kLinear, ast::InterpolationSampling::kCentroid, true},
-        Params{ast::InterpolationType::kLinear, ast::InterpolationSampling::kSample, true},
+        Params{builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kUndefined,
+               true},
+        Params{builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kCenter,
+               true},
+        Params{builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kCentroid,
+               true},
+        Params{builtin::InterpolationType::kPerspective, builtin::InterpolationSampling::kSample,
+               true},
+        Params{builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kUndefined,
+               true},
+        Params{builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kCenter, true},
+        Params{builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kCentroid,
+               true},
+        Params{builtin::InterpolationType::kLinear, builtin::InterpolationSampling::kSample, true},
         // flat interpolation must not have a sampling type
-        Params{ast::InterpolationType::kFlat, ast::InterpolationSampling::kUndefined, true},
-        Params{ast::InterpolationType::kFlat, ast::InterpolationSampling::kCenter, false},
-        Params{ast::InterpolationType::kFlat, ast::InterpolationSampling::kCentroid, false},
-        Params{ast::InterpolationType::kFlat, ast::InterpolationSampling::kSample, false}));
+        Params{builtin::InterpolationType::kFlat, builtin::InterpolationSampling::kUndefined, true},
+        Params{builtin::InterpolationType::kFlat, builtin::InterpolationSampling::kCenter, false},
+        Params{builtin::InterpolationType::kFlat, builtin::InterpolationSampling::kCentroid, false},
+        Params{builtin::InterpolationType::kFlat, builtin::InterpolationSampling::kSample, false}));
 
 TEST_F(InterpolateTest, FragmentInput_Integer_MissingFlatInterpolation) {
     Func("main",
@@ -1644,8 +1650,8 @@
              Param("a", ty.vec4<f32>(),
                    utils::Vector{
                        Builtin(builtin::BuiltinValue::kPosition),
-                       Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
-                                   ast::InterpolationSampling::kUndefined),
+                       Interpolate(Source{{12, 34}}, builtin::InterpolationType::kFlat,
+                                   builtin::InterpolationSampling::kUndefined),
                    }),
          },
          ty.void_(), utils::Empty,
@@ -1668,8 +1674,8 @@
          },
          utils::Vector{
              Builtin(builtin::BuiltinValue::kPosition),
-             Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
-                         ast::InterpolationSampling::kUndefined),
+             Interpolate(Source{{12, 34}}, builtin::InterpolationType::kFlat,
+                         builtin::InterpolationSampling::kUndefined),
          });
 
     EXPECT_FALSE(r()->Resolve());
@@ -1678,12 +1684,13 @@
 }
 
 TEST_F(InterpolateTest, MissingLocationAttribute_Struct) {
-    Structure("S",
-              utils::Vector{
-                  Member("a", ty.f32(),
-                         utils::Vector{Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
-                                                   ast::InterpolationSampling::kUndefined)}),
-              });
+    Structure(
+        "S",
+        utils::Vector{
+            Member("a", ty.f32(),
+                   utils::Vector{Interpolate(Source{{12, 34}}, builtin::InterpolationType::kFlat,
+                                             builtin::InterpolationSampling::kUndefined)}),
+        });
 
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc
index 2ef7d1e..ebb8284 100644
--- a/src/tint/resolver/validator.cc
+++ b/src/tint/resolver/validator.cc
@@ -973,14 +973,14 @@
                                      const type::Type* storage_ty) const {
     auto* type = storage_ty->UnwrapRef();
 
-    if (type->is_integer_scalar_or_vector() && attr->type != ast::InterpolationType::kFlat) {
+    if (type->is_integer_scalar_or_vector() && attr->type != builtin::InterpolationType::kFlat) {
         AddError("interpolation type must be 'flat' for integral user-defined IO types",
                  attr->source);
         return false;
     }
 
-    if (attr->type == ast::InterpolationType::kFlat &&
-        attr->sampling != ast::InterpolationSampling::kUndefined) {
+    if (attr->type == builtin::InterpolationType::kFlat &&
+        attr->sampling != builtin::InterpolationSampling::kUndefined) {
         AddError("flat interpolation attribute must not have a sampling parameter", attr->source);
         return false;
     }
diff --git a/src/tint/transform/canonicalize_entry_point_io.cc b/src/tint/transform/canonicalize_entry_point_io.cc
index 2df7966..80b51dc 100644
--- a/src/tint/transform/canonicalize_entry_point_io.cc
+++ b/src/tint/transform/canonicalize_entry_point_io.cc
@@ -222,8 +222,8 @@
                 !ast::HasAttribute<ast::InterpolateAttribute>(attributes) &&
                 (ast::HasAttribute<ast::LocationAttribute>(attributes) ||
                  cfg.shader_style == ShaderStyle::kSpirv)) {
-                attributes.Push(ctx.dst->Interpolate(ast::InterpolationType::kFlat,
-                                                     ast::InterpolationSampling::kUndefined));
+                attributes.Push(ctx.dst->Interpolate(builtin::InterpolationType::kFlat,
+                                                     builtin::InterpolationSampling::kUndefined));
             }
 
             // Disable validation for use of the `input` address space.
@@ -291,8 +291,8 @@
             type->is_integer_scalar_or_vector() &&
             ast::HasAttribute<ast::LocationAttribute>(attributes) &&
             !ast::HasAttribute<ast::InterpolateAttribute>(attributes)) {
-            attributes.Push(ctx.dst->Interpolate(ast::InterpolationType::kFlat,
-                                                 ast::InterpolationSampling::kUndefined));
+            attributes.Push(ctx.dst->Interpolate(builtin::InterpolationType::kFlat,
+                                                 builtin::InterpolationSampling::kUndefined));
         }
 
         // In GLSL, if it's a builtin, override the name with the
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index 742694c..d89aaaf 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -2191,21 +2191,21 @@
     for (auto* attr : attributes) {
         if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
             switch (interpolate->type) {
-                case ast::InterpolationType::kPerspective:
-                case ast::InterpolationType::kLinear:
-                case ast::InterpolationType::kUndefined:
+                case builtin::InterpolationType::kPerspective:
+                case builtin::InterpolationType::kLinear:
+                case builtin::InterpolationType::kUndefined:
                     break;
-                case ast::InterpolationType::kFlat:
+                case builtin::InterpolationType::kFlat:
                     out << "flat ";
                     break;
             }
             switch (interpolate->sampling) {
-                case ast::InterpolationSampling::kCentroid:
+                case builtin::InterpolationSampling::kCentroid:
                     out << "centroid ";
                     break;
-                case ast::InterpolationSampling::kSample:
-                case ast::InterpolationSampling::kCenter:
-                case ast::InterpolationSampling::kUndefined:
+                case builtin::InterpolationSampling::kSample:
+                case builtin::InterpolationSampling::kCenter:
+                case builtin::InterpolationSampling::kUndefined:
                     break;
             }
         }
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 7b33e4a..2659a52 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -3187,31 +3187,32 @@
     return "";
 }
 
-std::string GeneratorImpl::interpolation_to_modifiers(ast::InterpolationType type,
-                                                      ast::InterpolationSampling sampling) const {
+std::string GeneratorImpl::interpolation_to_modifiers(
+    builtin::InterpolationType type,
+    builtin::InterpolationSampling sampling) const {
     std::string modifiers;
     switch (type) {
-        case ast::InterpolationType::kPerspective:
+        case builtin::InterpolationType::kPerspective:
             modifiers += "linear ";
             break;
-        case ast::InterpolationType::kLinear:
+        case builtin::InterpolationType::kLinear:
             modifiers += "noperspective ";
             break;
-        case ast::InterpolationType::kFlat:
+        case builtin::InterpolationType::kFlat:
             modifiers += "nointerpolation ";
             break;
-        case ast::InterpolationType::kUndefined:
+        case builtin::InterpolationType::kUndefined:
             break;
     }
     switch (sampling) {
-        case ast::InterpolationSampling::kCentroid:
+        case builtin::InterpolationSampling::kCentroid:
             modifiers += "centroid ";
             break;
-        case ast::InterpolationSampling::kSample:
+        case builtin::InterpolationSampling::kSample:
             modifiers += "sample ";
             break;
-        case ast::InterpolationSampling::kCenter:
-        case ast::InterpolationSampling::kUndefined:
+        case builtin::InterpolationSampling::kCenter:
+        case builtin::InterpolationSampling::kUndefined:
             break;
     }
     return modifiers;
diff --git a/src/tint/writer/hlsl/generator_impl.h b/src/tint/writer/hlsl/generator_impl.h
index da846f4..1f272ef 100644
--- a/src/tint/writer/hlsl/generator_impl.h
+++ b/src/tint/writer/hlsl/generator_impl.h
@@ -501,8 +501,8 @@
     /// @param type the interpolation type
     /// @param sampling the interpolation sampling
     /// @returns the string name of the attribute or blank on error
-    std::string interpolation_to_modifiers(ast::InterpolationType type,
-                                           ast::InterpolationSampling sampling) const;
+    std::string interpolation_to_modifiers(builtin::InterpolationType type,
+                                           builtin::InterpolationSampling sampling) const;
 
   private:
     enum class VarType { kIn, kOut };
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index 5c77e47..0f6b390 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -1939,33 +1939,34 @@
     return "";
 }
 
-std::string GeneratorImpl::interpolation_to_attribute(ast::InterpolationType type,
-                                                      ast::InterpolationSampling sampling) const {
+std::string GeneratorImpl::interpolation_to_attribute(
+    builtin::InterpolationType type,
+    builtin::InterpolationSampling sampling) const {
     std::string attr;
     switch (sampling) {
-        case ast::InterpolationSampling::kCenter:
+        case builtin::InterpolationSampling::kCenter:
             attr = "center_";
             break;
-        case ast::InterpolationSampling::kCentroid:
+        case builtin::InterpolationSampling::kCentroid:
             attr = "centroid_";
             break;
-        case ast::InterpolationSampling::kSample:
+        case builtin::InterpolationSampling::kSample:
             attr = "sample_";
             break;
-        case ast::InterpolationSampling::kUndefined:
+        case builtin::InterpolationSampling::kUndefined:
             break;
     }
     switch (type) {
-        case ast::InterpolationType::kPerspective:
+        case builtin::InterpolationType::kPerspective:
             attr += "perspective";
             break;
-        case ast::InterpolationType::kLinear:
+        case builtin::InterpolationType::kLinear:
             attr += "no_perspective";
             break;
-        case ast::InterpolationType::kFlat:
+        case builtin::InterpolationType::kFlat:
             attr += "flat";
             break;
-        case ast::InterpolationType::kUndefined:
+        case builtin::InterpolationType::kUndefined:
             break;
     }
     return attr;
diff --git a/src/tint/writer/msl/generator_impl.h b/src/tint/writer/msl/generator_impl.h
index 0e9b261..3e84546 100644
--- a/src/tint/writer/msl/generator_impl.h
+++ b/src/tint/writer/msl/generator_impl.h
@@ -366,8 +366,8 @@
     /// @param type the interpolation type
     /// @param sampling the interpolation sampling
     /// @returns the string name of the attribute or blank on error
-    std::string interpolation_to_attribute(ast::InterpolationType type,
-                                           ast::InterpolationSampling sampling) const;
+    std::string interpolation_to_attribute(builtin::InterpolationType type,
+                                           builtin::InterpolationSampling sampling) const;
 
   private:
     // A pair of byte size and alignment `uint32_t`s.
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index 0e04d17..0a3c5ba 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -4047,29 +4047,29 @@
 }
 
 void Builder::AddInterpolationDecorations(uint32_t id,
-                                          ast::InterpolationType type,
-                                          ast::InterpolationSampling sampling) {
+                                          builtin::InterpolationType type,
+                                          builtin::InterpolationSampling sampling) {
     switch (type) {
-        case ast::InterpolationType::kLinear:
+        case builtin::InterpolationType::kLinear:
             push_annot(spv::Op::OpDecorate, {Operand(id), U32Operand(SpvDecorationNoPerspective)});
             break;
-        case ast::InterpolationType::kFlat:
+        case builtin::InterpolationType::kFlat:
             push_annot(spv::Op::OpDecorate, {Operand(id), U32Operand(SpvDecorationFlat)});
             break;
-        case ast::InterpolationType::kPerspective:
-        case ast::InterpolationType::kUndefined:
+        case builtin::InterpolationType::kPerspective:
+        case builtin::InterpolationType::kUndefined:
             break;
     }
     switch (sampling) {
-        case ast::InterpolationSampling::kCentroid:
+        case builtin::InterpolationSampling::kCentroid:
             push_annot(spv::Op::OpDecorate, {Operand(id), U32Operand(SpvDecorationCentroid)});
             break;
-        case ast::InterpolationSampling::kSample:
+        case builtin::InterpolationSampling::kSample:
             push_capability(SpvCapabilitySampleRateShading);
             push_annot(spv::Op::OpDecorate, {Operand(id), U32Operand(SpvDecorationSample)});
             break;
-        case ast::InterpolationSampling::kCenter:
-        case ast::InterpolationSampling::kUndefined:
+        case builtin::InterpolationSampling::kCenter:
+        case builtin::InterpolationSampling::kUndefined:
             break;
     }
 }
diff --git a/src/tint/writer/spirv/builder.h b/src/tint/writer/spirv/builder.h
index c939a39..d4aa11b 100644
--- a/src/tint/writer/spirv/builder.h
+++ b/src/tint/writer/spirv/builder.h
@@ -221,8 +221,8 @@
     /// @param type the interpolation type
     /// @param sampling the interpolation sampling
     void AddInterpolationDecorations(uint32_t id,
-                                     ast::InterpolationType type,
-                                     ast::InterpolationSampling sampling);
+                                     builtin::InterpolationType type,
+                                     builtin::InterpolationSampling sampling);
 
     /// Generates the enabling of an extension. Emits an error and returns false if the extension is
     /// not supported.
diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc
index 42db52a..0902d2c 100644
--- a/src/tint/writer/wgsl/generator_impl.cc
+++ b/src/tint/writer/wgsl/generator_impl.cc
@@ -572,7 +572,7 @@
             },
             [&](const ast::InterpolateAttribute* interpolate) {
                 out << "interpolate(" << interpolate->type;
-                if (interpolate->sampling != ast::InterpolationSampling::kUndefined) {
+                if (interpolate->sampling != builtin::InterpolationSampling::kUndefined) {
                     out << ", " << interpolate->sampling;
                 }
                 out << ")";