spirv-reader: Handle OpInBoundsAccessChain for storage class translation

Fixed: tint:457
Change-Id: I25410a1e59cbc78f76da65c28312a8ddd6b3319b
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/39220
Auto-Submit: David Neto <dneto@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 596f90e..44abc7b 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -3653,6 +3653,7 @@
               // Keep the default decision based on the result type.
               break;
             case SpvOpAccessChain:
+            case SpvOpInBoundsAccessChain:
             case SpvOpCopyObject:
               // Inherit from the first operand. We need this so we can pick up
               // a remapped storage buffer.
diff --git a/src/reader/spirv/function_memory_test.cc b/src/reader/spirv/function_memory_test.cc
index d28cdba..379286c 100644
--- a/src/reader/spirv/function_memory_test.cc
+++ b/src/reader/spirv/function_memory_test.cc
@@ -848,8 +848,8 @@
   ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
   FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
   EXPECT_TRUE(fe.EmitBody()) << p->error();
-  EXPECT_THAT(ToString(p->builder().Symbols(), fe.ast_body()),
-              HasSubstr(R"(Assignment{
+  const auto got = ToString(p->builder().Symbols(), fe.ast_body());
+  EXPECT_THAT(got, HasSubstr(R"(Assignment{
   MemberAccessor[not set]{
     Identifier[not set]{myvar}
     Identifier[not set]{field0}
@@ -865,7 +865,50 @@
     ScalarConstructor[not set]{1}
   }
   ScalarConstructor[not set]{0}
-})")) << ToString(p->builder().Symbols(), fe.ast_body())
+})")) << got
+      << p->error();
+}
+
+TEST_F(SpvParserTest,
+       RemapStorageBuffer_ThroughAccessChain_NonCascaded_InBoundsAccessChain) {
+  // Like the previous test, but using OpInBoundsAccessChain.
+  const auto assembly = OldStorageBufferPreamble() + R"(
+  %100 = OpFunction %void None %voidfn
+  %entry = OpLabel
+
+  ; the scalar element
+  %1 = OpInBoundsAccessChain %ptr_uint %myvar %uint_0
+  OpStore %1 %uint_0
+
+  ; element in the runtime array
+  %2 = OpInBoundsAccessChain %ptr_uint %myvar %uint_1 %uint_1
+  OpStore %2 %uint_0
+
+  OpReturn
+  OpFunctionEnd
+)";
+  auto p = parser(test::Assemble(assembly));
+  ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
+  FunctionEmitter fe(p.get(), *spirv_function(p.get(), 100));
+  EXPECT_TRUE(fe.EmitBody()) << p->error();
+  const auto got = ToString(p->builder().Symbols(), fe.ast_body());
+  EXPECT_THAT(got, HasSubstr(R"(Assignment{
+  MemberAccessor[not set]{
+    Identifier[not set]{myvar}
+    Identifier[not set]{field0}
+  }
+  ScalarConstructor[not set]{0}
+}
+Assignment{
+  ArrayAccessor[not set]{
+    MemberAccessor[not set]{
+      Identifier[not set]{myvar}
+      Identifier[not set]{field1}
+    }
+    ScalarConstructor[not set]{1}
+  }
+  ScalarConstructor[not set]{0}
+})")) << got
       << p->error();
 }