spirv-reader: Ignore Restrict, RestrictPointer decorations

They have no effect in graphics APIs.

Fixes: tint:1440
Change-Id: I80a4b2f5875fbabbd53fd1ebd085ba146401ca71
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/80980
Auto-Submit: David Neto <dneto@google.com>
Kokoro: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index c6b192e..d8c1a64 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -396,11 +396,19 @@
     // Example: OpDecorate %struct_id Block
     // Example: OpDecorate %array_ty ArrayStride 16
     auto decoration_kind = inst->GetSingleWordInOperand(1);
-    if (visited.emplace(decoration_kind).second) {
-      std::vector<uint32_t> inst_as_words;
-      inst->ToBinaryWithoutAttachedDebugInsts(&inst_as_words);
-      Decoration d(inst_as_words.begin() + 2, inst_as_words.end());
-      result.push_back(d);
+    switch (decoration_kind) {
+      // Restrict and RestrictPointer have no effect in graphics APIs.
+      case SpvDecorationRestrict:
+      case SpvDecorationRestrictPointer:
+        break;
+      default:
+        if (visited.emplace(decoration_kind).second) {
+          std::vector<uint32_t> inst_as_words;
+          inst->ToBinaryWithoutAttachedDebugInsts(&inst_as_words);
+          Decoration d(inst_as_words.begin() + 2, inst_as_words.end());
+          result.push_back(d);
+        }
+        break;
     }
   }
   return result;
@@ -419,11 +427,18 @@
       continue;
     }
     auto decoration_kind = inst->GetSingleWordInOperand(2);
-    if (visited.emplace(decoration_kind).second) {
-      std::vector<uint32_t> inst_as_words;
-      inst->ToBinaryWithoutAttachedDebugInsts(&inst_as_words);
-      Decoration d(inst_as_words.begin() + 3, inst_as_words.end());
-      result.push_back(d);
+    switch (decoration_kind) {
+      // Restrict and RestrictPointer have no effect in graphics APIs.
+      case SpvDecorationRestrict:
+      case SpvDecorationRestrictPointer:
+        break;
+      default:
+        if (visited.emplace(decoration_kind).second) {
+          std::vector<uint32_t> inst_as_words;
+          inst->ToBinaryWithoutAttachedDebugInsts(&inst_as_words);
+          Decoration d(inst_as_words.begin() + 3, inst_as_words.end());
+          result.push_back(d);
+        }
     }
   }
   return result;
diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h
index ffa6251..f67d81a 100644
--- a/src/reader/spirv/parser_impl.h
+++ b/src/reader/spirv/parser_impl.h
@@ -221,6 +221,8 @@
   /// Gets the list of unique decorations for a SPIR-V result ID.  Returns an
   /// empty vector if the ID is not a result ID, or if no decorations target
   /// that ID. The internal representation must have already been built.
+  /// Ignores decorations that have no effect in graphics APIs, e.g. Restrict
+  /// and RestrictPointer.
   /// @param id SPIR-V ID
   /// @returns the list of decorations on the given ID
   DecorationList GetDecorationsFor(uint32_t id) const;
@@ -228,6 +230,8 @@
   /// an empty list if the `id` is not the ID of a struct, or if the member
   /// index is out of range, or if the target member has no decorations. The
   /// internal representation must have already been built.
+  /// Ignores decorations that have no effect in graphics APIs, e.g. Restrict
+  /// and RestrictPointer.
   /// @param id SPIR-V ID of a struct
   /// @param member_index the member within the struct
   /// @returns the list of decorations on the member
diff --git a/src/reader/spirv/parser_impl_get_decorations_test.cc b/src/reader/spirv/parser_impl_get_decorations_test.cc
index fc41141..7b2818e 100644
--- a/src/reader/spirv/parser_impl_get_decorations_test.cc
+++ b/src/reader/spirv/parser_impl_get_decorations_test.cc
@@ -198,6 +198,68 @@
   EXPECT_TRUE(p->error().empty());
 }
 
+TEST_F(SpvParserGetDecorationsTest, GetDecorationsFor_Restrict) {
+  // RestrictPointer applies to a memory object declaration. Use a variable.
+  auto p = parser(test::Assemble(R"(
+    OpDecorate %10 Restrict
+    %float = OpTypeFloat 32
+    %ptr = OpTypePointer Workgroup %float
+    %10 = OpVariable %ptr Workgroup
+  )"));
+  EXPECT_TRUE(p->BuildAndParseInternalModule());
+  auto decorations = p->GetDecorationsFor(10);
+  EXPECT_TRUE(decorations.empty());
+  EXPECT_TRUE(p->error().empty());
+  p->SkipDumpingPending(kSkipReason);
+}
+
+TEST_F(SpvParserGetDecorationsTest, GetDecorationsForMember_Restrict) {
+  // Restrict applies to a memory object declaration.
+  // But OpMemberDecorate can only be applied to a structure type.
+  // Test the reader's ability to be resilient to more than what SPIR-V allows.
+  auto p = parser(test::Assemble(R"(
+    OpMemberDecorate %10 0 Restrict
+    %float = OpTypeFloat 32
+    %10 = OpTypeStruct %float
+  )"));
+  EXPECT_TRUE(p->BuildAndParseInternalModule());
+  auto decorations = p->GetDecorationsForMember(10, 0);
+  EXPECT_TRUE(decorations.empty());
+  EXPECT_TRUE(p->error().empty());
+  p->SkipDumpingPending(kSkipReason);
+}
+
+TEST_F(SpvParserGetDecorationsTest, GetDecorationsFor_RestrictPointer) {
+  // RestrictPointer applies to a memory object declaration. Use a variable.
+  auto p = parser(test::Assemble(R"(
+    OpDecorate %10 RestrictPointer
+    %float = OpTypeFloat 32
+    %ptr = OpTypePointer Workgroup %float
+    %10 = OpVariable %ptr Workgroup
+  )"));
+  EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+  auto decorations = p->GetDecorationsFor(10);
+  EXPECT_TRUE(decorations.empty());
+  EXPECT_TRUE(p->error().empty());
+  p->SkipDumpingPending(kSkipReason);
+}
+
+TEST_F(SpvParserGetDecorationsTest, GetDecorationsForMember_RestrictPointer) {
+  // RestrictPointer applies to a memory object declaration.
+  // But OpMemberDecorate can only be applied to a structure type.
+  // Test the reader's ability to be resilient to more than what SPIR-V allows.
+  auto p = parser(test::Assemble(R"(
+    OpMemberDecorate %10 0 RestrictPointer
+    %float = OpTypeFloat 32
+    %10 = OpTypeStruct %float
+  )"));
+  EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+  auto decorations = p->GetDecorationsFor(10);
+  EXPECT_TRUE(decorations.empty());
+  EXPECT_TRUE(p->error().empty());
+  p->SkipDumpingPending(kSkipReason);
+}
+
 }  // namespace
 }  // namespace spirv
 }  // namespace reader