[tint] Move cached builtin info out of Symbol

Use a hashmap local to the dependency analysis instead. This breaks
the dependency from `symbol` to `builtin`, allowing us to use Symbol
from the builtin namespace.

Change-Id: I4f5d3d59e56c86f0ab833a41d97966dab5fbd655
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/141721
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/docs/tint/layering.md b/docs/tint/layering.md
index 587febc..3e3c8f6 100644
--- a/docs/tint/layering.md
+++ b/docs/tint/layering.md
@@ -50,6 +50,11 @@
 |               Types                     |      |
 +-----------------------------------------+      |
                   |                              |
+                  V                              |
++-----------------------------------------+      |
+|              Builtin                    |      |
++-----------------------------------------+      |
+                  |                              |
                   |------------------------------+
                   V
 +-----------------------------------------+
@@ -57,11 +62,6 @@
 +-----------------------------------------+
                   |
                   V
-+-----------------------------------------+
-|              Builtin                    |
-+-----------------------------------------+
-                  |
-                  V
 +-----------------------------------------+ +-------------+
 |               Utils                     | | Initializer |
 +-----------------------------------------+ +-------------+
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index bc6530d..5c8d48d 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -210,10 +210,7 @@
     "symbol_table.cc",
     "symbol_table.h",
   ]
-  deps = [
-    ":libtint_builtins_src",
-    ":libtint_utils_src",
-  ]
+  deps = [ ":libtint_utils_src" ]
 }
 
 libtint_source_set("libtint_utils_src") {
@@ -292,8 +289,6 @@
     "clone_context.cc",
     "program.cc",
     "program_builder.cc",
-    "resolver/builtin_structs.cc",
-    "resolver/builtin_structs.h",
     "resolver/const_eval.cc",
     "resolver/const_eval.h",
     "resolver/ctor_conv_intrinsic.cc",
@@ -853,6 +848,8 @@
 
 libtint_source_set("libtint_type_src") {
   sources = [
+    "resolver/builtin_structs.cc",
+    "resolver/builtin_structs.h",
     "type/abstract_float.cc",
     "type/abstract_float.h",
     "type/abstract_int.cc",
@@ -1257,6 +1254,7 @@
     ]
     deps = [
       ":libtint_ast_src",
+      ":libtint_builtins_src",
       ":libtint_constant_src",
       ":libtint_ir_src",
       ":libtint_program_src",
diff --git a/src/tint/ir/to_program.cc b/src/tint/ir/to_program.cc
index 2e535e2..92dfd5c 100644
--- a/src/tint/ir/to_program.cc
+++ b/src/tint/ir/to_program.cc
@@ -18,6 +18,7 @@
 #include <tuple>
 #include <utility>
 
+#include "src/tint/builtin/builtin.h"
 #include "src/tint/constant/splat.h"
 #include "src/tint/ir/access.h"
 #include "src/tint/ir/binary.h"
diff --git a/src/tint/resolver/builtin_structs.cc b/src/tint/resolver/builtin_structs.cc
index 55daa8f..0e7c659 100644
--- a/src/tint/resolver/builtin_structs.cc
+++ b/src/tint/resolver/builtin_structs.cc
@@ -18,6 +18,7 @@
 #include <string>
 #include <utility>
 
+#include "src/tint/builtin/builtin.h"
 #include "src/tint/switch.h"
 #include "src/tint/symbol_table.h"
 #include "src/tint/type/abstract_float.h"
diff --git a/src/tint/resolver/dependency_graph.cc b/src/tint/resolver/dependency_graph.cc
index 84932ed..2a4669d 100644
--- a/src/tint/resolver/dependency_graph.cc
+++ b/src/tint/resolver/dependency_graph.cc
@@ -16,6 +16,7 @@
 
 #include <string>
 #include <utility>
+#include <variant>
 #include <vector>
 
 #include "src/tint/ast/alias.h"
@@ -438,46 +439,131 @@
         UnhandledNode(diagnostics_, attr);
     }
 
+    /// The type of builtin that a symbol could represent.
+    enum class BuiltinType {
+        /// No builtin matched
+        kNone = 0,
+        /// Builtin function
+        kFunction,
+        /// Builtin
+        kBuiltin,
+        /// Builtin value
+        kBuiltinValue,
+        /// Address space
+        kAddressSpace,
+        /// Texel format
+        kTexelFormat,
+        /// Access
+        kAccess,
+        /// Interpolation Type
+        kInterpolationType,
+        /// Interpolation Sampling
+        kInterpolationSampling,
+    };
+
+    /// BuiltinInfo stores information about the builtin that a symbol represents.
+    struct BuiltinInfo {
+        /// @returns the builtin value
+        template <typename T>
+        T Value() const {
+            return std::get<T>(value);
+        }
+
+        BuiltinType type = BuiltinType::kNone;
+        std::variant<std::monostate,
+                     builtin::Function,
+                     builtin::Builtin,
+                     builtin::BuiltinValue,
+                     builtin::AddressSpace,
+                     builtin::TexelFormat,
+                     builtin::Access,
+                     builtin::InterpolationType,
+                     builtin::InterpolationSampling>
+            value = {};
+    };
+
+    /// Get the builtin info for a given symbol.
+    /// @param symbol the symbol
+    /// @returns the builtin info
+    DependencyScanner::BuiltinInfo GetBuiltinInfo(Symbol symbol) {
+        return builtin_info_map.GetOrCreate(symbol, [&] {
+            if (auto builtin_fn = builtin::ParseFunction(symbol.NameView());
+                builtin_fn != builtin::Function::kNone) {
+                return BuiltinInfo{BuiltinType::kFunction, builtin_fn};
+            }
+            if (auto builtin_ty = builtin::ParseBuiltin(symbol.NameView());
+                builtin_ty != builtin::Builtin::kUndefined) {
+                return BuiltinInfo{BuiltinType::kBuiltin, builtin_ty};
+            }
+            if (auto builtin_val = builtin::ParseBuiltinValue(symbol.NameView());
+                builtin_val != builtin::BuiltinValue::kUndefined) {
+                return BuiltinInfo{BuiltinType::kBuiltinValue, builtin_val};
+            }
+            if (auto addr = builtin::ParseAddressSpace(symbol.NameView());
+                addr != builtin::AddressSpace::kUndefined) {
+                return BuiltinInfo{BuiltinType::kAddressSpace, addr};
+            }
+            if (auto fmt = builtin::ParseTexelFormat(symbol.NameView());
+                fmt != builtin::TexelFormat::kUndefined) {
+                return BuiltinInfo{BuiltinType::kTexelFormat, fmt};
+            }
+            if (auto access = builtin::ParseAccess(symbol.NameView());
+                access != builtin::Access::kUndefined) {
+                return BuiltinInfo{BuiltinType::kAccess, access};
+            }
+            if (auto i_type = builtin::ParseInterpolationType(symbol.NameView());
+                i_type != builtin::InterpolationType::kUndefined) {
+                return BuiltinInfo{BuiltinType::kInterpolationType, i_type};
+            }
+            if (auto i_smpl = builtin::ParseInterpolationSampling(symbol.NameView());
+                i_smpl != builtin::InterpolationSampling::kUndefined) {
+                return BuiltinInfo{BuiltinType::kInterpolationSampling, i_smpl};
+            }
+            return BuiltinInfo{};
+        });
+    }
+
     /// Adds the dependency from @p from to @p to, erroring if @p to cannot be resolved.
     void AddDependency(const ast::Identifier* from, Symbol to) {
         auto* resolved = scope_stack_.Get(to);
         if (!resolved) {
-            switch (to.Type()) {
-                case Symbol::BuiltinType::kNone:
+            auto builtin_info = GetBuiltinInfo(to);
+            switch (builtin_info.type) {
+                case BuiltinType::kNone:
                     graph_.resolved_identifiers.Add(from, UnresolvedIdentifier{to.Name()});
                     break;
-                case Symbol::BuiltinType::kFunction:
+                case BuiltinType::kFunction:
                     graph_.resolved_identifiers.Add(
-                        from, ResolvedIdentifier(to.BuiltinValue<builtin::Function>()));
+                        from, ResolvedIdentifier(builtin_info.Value<builtin::Function>()));
                     break;
-                case Symbol::BuiltinType::kBuiltin:
+                case BuiltinType::kBuiltin:
                     graph_.resolved_identifiers.Add(
-                        from, ResolvedIdentifier(to.BuiltinValue<builtin::Builtin>()));
+                        from, ResolvedIdentifier(builtin_info.Value<builtin::Builtin>()));
                     break;
-                case Symbol::BuiltinType::kBuiltinValue:
+                case BuiltinType::kBuiltinValue:
                     graph_.resolved_identifiers.Add(
-                        from, ResolvedIdentifier(to.BuiltinValue<builtin::BuiltinValue>()));
+                        from, ResolvedIdentifier(builtin_info.Value<builtin::BuiltinValue>()));
                     break;
-                case Symbol::BuiltinType::kAddressSpace:
+                case BuiltinType::kAddressSpace:
                     graph_.resolved_identifiers.Add(
-                        from, ResolvedIdentifier(to.BuiltinValue<builtin::AddressSpace>()));
+                        from, ResolvedIdentifier(builtin_info.Value<builtin::AddressSpace>()));
                     break;
-                case Symbol::BuiltinType::kTexelFormat:
+                case BuiltinType::kTexelFormat:
                     graph_.resolved_identifiers.Add(
-                        from, ResolvedIdentifier(to.BuiltinValue<builtin::TexelFormat>()));
+                        from, ResolvedIdentifier(builtin_info.Value<builtin::TexelFormat>()));
                     break;
-                case Symbol::BuiltinType::kAccess:
+                case BuiltinType::kAccess:
                     graph_.resolved_identifiers.Add(
-                        from, ResolvedIdentifier(to.BuiltinValue<builtin::Access>()));
+                        from, ResolvedIdentifier(builtin_info.Value<builtin::Access>()));
                     break;
-                case Symbol::BuiltinType::kInterpolationType:
+                case BuiltinType::kInterpolationType:
                     graph_.resolved_identifiers.Add(
-                        from, ResolvedIdentifier(to.BuiltinValue<builtin::InterpolationType>()));
+                        from, ResolvedIdentifier(builtin_info.Value<builtin::InterpolationType>()));
                     break;
-                case Symbol::BuiltinType::kInterpolationSampling:
+                case BuiltinType::kInterpolationSampling:
                     graph_.resolved_identifiers.Add(
                         from,
-                        ResolvedIdentifier(to.BuiltinValue<builtin::InterpolationSampling>()));
+                        ResolvedIdentifier(builtin_info.Value<builtin::InterpolationSampling>()));
                     break;
             }
             return;
@@ -501,6 +587,8 @@
 
     ScopeStack<Symbol, const ast::Node*> scope_stack_;
     Global* current_global_ = nullptr;
+
+    utils::Hashmap<Symbol, BuiltinInfo, 64> builtin_info_map;
 };
 
 /// The global dependency analysis system
diff --git a/src/tint/symbol.cc b/src/tint/symbol.cc
index ad84add..7e69b5d 100644
--- a/src/tint/symbol.cc
+++ b/src/tint/symbol.cc
@@ -21,9 +21,7 @@
 Symbol::Symbol() = default;
 
 Symbol::Symbol(uint32_t val, tint::ProgramID pid, std::string_view name)
-    : val_(val), program_id_(pid), name_(name) {
-    DetermineBuiltinType();
-}
+    : val_(val), program_id_(pid), name_(name) {}
 
 Symbol::Symbol(const Symbol& o) = default;
 
@@ -62,51 +60,4 @@
     return std::string(name_);
 }
 
-void Symbol::DetermineBuiltinType() {
-    if (auto builtin_fn = builtin::ParseFunction(name_); builtin_fn != builtin::Function::kNone) {
-        builtin_type_ = BuiltinType::kFunction;
-        builtin_value_ = builtin_fn;
-        return;
-    }
-    if (auto builtin_ty = builtin::ParseBuiltin(name_);
-        builtin_ty != builtin::Builtin::kUndefined) {
-        builtin_type_ = BuiltinType::kBuiltin;
-        builtin_value_ = builtin_ty;
-        return;
-    }
-    if (auto builtin_val = builtin::ParseBuiltinValue(name_);
-        builtin_val != builtin::BuiltinValue::kUndefined) {
-        builtin_type_ = BuiltinType::kBuiltinValue;
-        builtin_value_ = builtin_val;
-        return;
-    }
-    if (auto addr = builtin::ParseAddressSpace(name_); addr != builtin::AddressSpace::kUndefined) {
-        builtin_type_ = BuiltinType::kAddressSpace;
-        builtin_value_ = addr;
-        return;
-    }
-    if (auto fmt = builtin::ParseTexelFormat(name_); fmt != builtin::TexelFormat::kUndefined) {
-        builtin_type_ = BuiltinType::kTexelFormat;
-        builtin_value_ = fmt;
-        return;
-    }
-    if (auto access = builtin::ParseAccess(name_); access != builtin::Access::kUndefined) {
-        builtin_type_ = BuiltinType::kAccess;
-        builtin_value_ = access;
-        return;
-    }
-    if (auto i_type = builtin::ParseInterpolationType(name_);
-        i_type != builtin::InterpolationType::kUndefined) {
-        builtin_type_ = BuiltinType::kInterpolationType;
-        builtin_value_ = i_type;
-        return;
-    }
-    if (auto i_smpl = builtin::ParseInterpolationSampling(name_);
-        i_smpl != builtin::InterpolationSampling::kUndefined) {
-        builtin_type_ = BuiltinType::kInterpolationSampling;
-        builtin_value_ = i_smpl;
-        return;
-    }
-}
-
 }  // namespace tint
diff --git a/src/tint/symbol.h b/src/tint/symbol.h
index ed6fe72..fdfa843 100644
--- a/src/tint/symbol.h
+++ b/src/tint/symbol.h
@@ -16,16 +16,7 @@
 #define SRC_TINT_SYMBOL_H_
 
 #include <string>
-#include <variant>
 
-#include "src/tint/builtin/access.h"
-#include "src/tint/builtin/address_space.h"
-#include "src/tint/builtin/builtin.h"
-#include "src/tint/builtin/builtin_value.h"
-#include "src/tint/builtin/function.h"
-#include "src/tint/builtin/interpolation_sampling.h"
-#include "src/tint/builtin/interpolation_type.h"
-#include "src/tint/builtin/texel_format.h"
 #include "src/tint/program_id.h"
 
 namespace tint {
@@ -33,28 +24,6 @@
 /// A symbol representing a string in the system
 class Symbol {
   public:
-    /// The type of builtin this symbol could represent, if any.
-    enum class BuiltinType {
-        /// No builtin matched
-        kNone = 0,
-        /// Builtin function
-        kFunction,
-        /// Builtin
-        kBuiltin,
-        /// Builtin value
-        kBuiltinValue,
-        /// Address space
-        kAddressSpace,
-        /// Texel format
-        kTexelFormat,
-        /// Access
-        kAccess,
-        /// Interpolation Type
-        kInterpolationType,
-        /// Interpolation Sampling
-        kInterpolationSampling,
-    };
-
     /// Constructor
     /// An invalid symbol
     Symbol();
@@ -121,33 +90,10 @@
     /// @returns the identifier of the Program that owns this symbol.
     tint::ProgramID ProgramID() const { return program_id_; }
 
-    /// @returns the builtin type
-    BuiltinType Type() const { return builtin_type_; }
-
-    /// @returns the builtin value
-    template <typename T>
-    T BuiltinValue() const {
-        return std::get<T>(builtin_value_);
-    }
-
   private:
-    void DetermineBuiltinType();
-
     uint32_t val_ = static_cast<uint32_t>(-1);
     tint::ProgramID program_id_;
     std::string_view name_;
-
-    BuiltinType builtin_type_ = BuiltinType::kNone;
-    std::variant<std::monostate,
-                 builtin::Function,
-                 builtin::Builtin,
-                 builtin::BuiltinValue,
-                 builtin::AddressSpace,
-                 builtin::TexelFormat,
-                 builtin::Access,
-                 builtin::InterpolationType,
-                 builtin::InterpolationSampling>
-        builtin_value_ = {};
 };
 
 /// @param sym the Symbol
diff --git a/src/tint/type/struct.h b/src/tint/type/struct.h
index 5a6c4dd..a13957a 100644
--- a/src/tint/type/struct.h
+++ b/src/tint/type/struct.h
@@ -22,6 +22,7 @@
 #include <utility>
 
 #include "src/tint/builtin/address_space.h"
+#include "src/tint/builtin/builtin_value.h"
 #include "src/tint/builtin/interpolation.h"
 #include "src/tint/symbol.h"
 #include "src/tint/type/node.h"
diff --git a/src/tint/writer/spirv/ir/generator_impl_ir.h b/src/tint/writer/spirv/ir/generator_impl_ir.h
index cb90d04..2a82d7f 100644
--- a/src/tint/writer/spirv/ir/generator_impl_ir.h
+++ b/src/tint/writer/spirv/ir/generator_impl_ir.h
@@ -17,6 +17,9 @@
 
 #include <vector>
 
+#include "src/tint/builtin/address_space.h"
+#include "src/tint/builtin/builtin_value.h"
+#include "src/tint/builtin/texel_format.h"
 #include "src/tint/constant/value.h"
 #include "src/tint/diagnostic/diagnostic.h"
 #include "src/tint/ir/constant.h"