[ir] Add vector-element-ptr validation capability

The IR validation APIs now take an optional list of allowed
capabilities which can be used to relax certain core IR validation
rules.

The `kVectorElementPointer` rule will be used by the SPIR-V dialect.

Bug: tint:1952
Change-Id: Id1317e9f6970f2d2be4b83650d7249f2e08fc379
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/170001
Reviewed-by: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/src/tint/lang/core/ir/validator.cc b/src/tint/lang/core/ir/validator.cc
index 2aa16f8..65c952a 100644
--- a/src/tint/lang/core/ir/validator.cc
+++ b/src/tint/lang/core/ir/validator.cc
@@ -90,7 +90,8 @@
   public:
     /// Create a core validator
     /// @param mod the module to be validated
-    explicit Validator(const Module& mod);
+    /// @param capabilities the optional capabilities that are allowed
+    explicit Validator(const Module& mod, EnumSet<Capability> capabilities);
 
     /// Destructor
     ~Validator();
@@ -286,6 +287,7 @@
 
   private:
     const Module& mod_;
+    EnumSet<Capability> capabilities_;
     std::shared_ptr<Source::File> disassembly_file;
     diag::List diagnostics_;
     Disassembler dis_{mod_};
@@ -297,7 +299,8 @@
     void DisassembleIfNeeded();
 };
 
-Validator::Validator(const Module& mod) : mod_(mod) {}
+Validator::Validator(const Module& mod, EnumSet<Capability> capabilities)
+    : mod_(mod), capabilities_(capabilities) {}
 
 Validator::~Validator() = default;
 
@@ -651,9 +654,11 @@
             return;
         }
 
-        if (obj_ptr && el_ty->Is<core::type::Vector>()) {
-            err("cannot obtain address of vector element");
-            return;
+        if (!capabilities_.Contains(Capability::kAllowVectorElementPointer)) {
+            if (obj_ptr && el_ty->Is<core::type::Vector>()) {
+                err("cannot obtain address of vector element");
+                return;
+            }
         }
 
         if (auto* const_index = index->As<ir::Constant>()) {
@@ -1024,13 +1029,14 @@
 
 }  // namespace
 
-Result<SuccessType> Validate(const Module& mod) {
-    Validator v(mod);
+Result<SuccessType> Validate(const Module& mod, EnumSet<Capability> capabilities) {
+    Validator v(mod, capabilities);
     return v.Run();
 }
 
 Result<SuccessType> ValidateAndDumpIfNeeded([[maybe_unused]] const Module& ir,
-                                            [[maybe_unused]] const char* msg) {
+                                            [[maybe_unused]] const char* msg,
+                                            [[maybe_unused]] EnumSet<Capability> capabilities) {
 #if TINT_DUMP_IR_WHEN_VALIDATING
     std::cout << "=========================================================" << std::endl;
     std::cout << "== IR dump before " << msg << ":" << std::endl;
@@ -1039,7 +1045,7 @@
 #endif
 
 #ifndef NDEBUG
-    auto result = Validate(ir);
+    auto result = Validate(ir, capabilities);
     if (result != Success) {
         return result.Failure();
     }