[ir] Speed up `CheckType` validation.

We don't need to validate types over and over again if we are validating
with the same capabilities. This Cl adds a cache of the previously
checked types and only does the full check if we have no already checked
the given type.

Bug: 372301201
Change-Id: I613d6f05d9faabe4790e417bef6e68ffb27ecd2c
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/211694
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index 4a5b1d6..9766d25 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -29,6 +29,7 @@
 
 #include <algorithm>
 #include <cstdint>
+#include <functional>
 #include <memory>
 #include <string>
 #include <string_view>
@@ -109,6 +110,11 @@
 
 namespace tint::core::ir {
 
+struct ValidatedType {
+    const type::Type* ty;
+    Capabilities caps;
+};
+
 namespace {
 
 /// @returns the parent block of @p block
@@ -776,6 +782,8 @@
     Hashmap<const ir::Function*, Hashset<const ir::UserCall*, 4>, 4> user_func_calls_;
     Hashset<const ir::Discard*, 4> discards_;
     core::ir::ReferencedModuleVars<const Module> referenced_module_vars_;
+
+    Hashset<ValidatedType, 16> validated_types_{};
 };
 
 Validator::Validator(const Module& mod, Capabilities capabilities)
@@ -1188,6 +1196,14 @@
 void Validator::CheckType(const core::type::Type* root,
                           std::function<diag::Diagnostic&()> diag,
                           Capabilities ignore_caps) {
+    if (root == nullptr) {
+        return;
+    }
+
+    if (!validated_types_.Add(ValidatedType{root, ignore_caps})) {
+        return;
+    }
+
     auto visit = [&](const type::Type* type) {
         return tint::Switch(
             type,
@@ -2525,3 +2541,20 @@
 }
 
 }  // namespace tint::core::ir
+
+namespace std {
+
+template <>
+struct hash<tint::core::ir::ValidatedType> {
+    size_t operator()(const tint::core::ir::ValidatedType& v) const { return Hash(v.ty, v.caps); }
+};
+
+template <>
+struct equal_to<tint::core::ir::ValidatedType> {
+    bool operator()(const tint::core::ir::ValidatedType& a,
+                    const tint::core::ir::ValidatedType& b) const {
+        return a.ty->Equals(*(b.ty)) && a.caps == b.caps;
+    }
+};
+
+}  // namespace std
diff --git a/test/tint/benchmark/skinned-shadowed-pbr-fragment.wgsl.expected.ir.glsl b/test/tint/benchmark/skinned-shadowed-pbr-fragment.wgsl.expected.ir.glsl
deleted file mode 100644
index 708a412..0000000
--- a/test/tint/benchmark/skinned-shadowed-pbr-fragment.wgsl.expected.ir.glsl
+++ /dev/null
@@ -1,3 +0,0 @@
-SKIP: FAILED
-
-Times out on bots