spirv-reader: Don't deduplicate SPIR-V array types

Bug: tint:1173
Change-Id: I2adefadf4b79c70f58ed32acda3ea50cd84c8550
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/64681
Auto-Submit: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: David Neto <dneto@google.com>
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index 4160354..68e544d 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -986,11 +986,17 @@
 const Type* ParserImpl::ConvertType(
     uint32_t type_id,
     const spvtools::opt::analysis::Array* arr_ty) {
-  const auto elem_type_id = type_mgr_->GetId(arr_ty->element_type());
+  // Get the element type. The SPIR-V optimizer's types representation
+  // deduplicates array types that have the same parameterization.
+  // We don't want that deduplication, so get the element type from
+  // the SPIR-V type directly.
+  const auto* inst = def_use_mgr_->GetDef(type_id);
+  const auto elem_type_id = inst->GetSingleWordInOperand(0);
   auto* ast_elem_ty = ConvertType(elem_type_id);
   if (ast_elem_ty == nullptr) {
     return nullptr;
   }
+  // Get the length.
   const auto& length_info = arr_ty->length_info();
   if (length_info.words.empty()) {
     // The internal representation is invalid. The discriminant vector
diff --git a/src/reader/spirv/parser_impl_convert_type_test.cc b/src/reader/spirv/parser_impl_convert_type_test.cc
index 6757647..d5b1167 100644
--- a/src/reader/spirv/parser_impl_convert_type_test.cc
+++ b/src/reader/spirv/parser_impl_convert_type_test.cc
@@ -639,6 +639,100 @@
   EXPECT_THAT(program.str(str), Eq(R"(__type_name_S)"));
 }
 
+TEST_F(SpvParserTest, ConvertType_Struct_NoDeduplication) {
+  // Prove that distinct SPIR-V structs map to distinct WGSL types.
+  auto p = parser(test::Assemble(Preamble() + R"(
+    %uint = OpTypeInt 32 0
+    %10 = OpTypeStruct %uint
+    %11 = OpTypeStruct %uint
+  )" + MainBody()));
+  EXPECT_TRUE(p->BuildAndParseInternalModule());
+
+  auto* type10 = p->ConvertType(10);
+  ASSERT_NE(type10, nullptr);
+  EXPECT_TRUE(type10->Is<Struct>());
+  auto* struct_type10 = type10->As<Struct>();
+  ASSERT_NE(struct_type10, nullptr);
+  EXPECT_EQ(struct_type10->members.size(), 1u);
+  EXPECT_TRUE(struct_type10->members[0]->Is<U32>());
+
+  auto* type11 = p->ConvertType(11);
+  ASSERT_NE(type11, nullptr);
+  EXPECT_TRUE(type11->Is<Struct>());
+  auto* struct_type11 = type11->As<Struct>();
+  ASSERT_NE(struct_type11, nullptr);
+  EXPECT_EQ(struct_type11->members.size(), 1u);
+  EXPECT_TRUE(struct_type11->members[0]->Is<U32>());
+
+  // They map to distinct types in WGSL
+  EXPECT_NE(type11, type10);
+}
+
+TEST_F(SpvParserTest, ConvertType_Array_NoDeduplication) {
+  // Prove that distinct SPIR-V arrays map to distinct WGSL types.
+  auto assembly = Preamble() + R"(
+    %uint = OpTypeInt 32 0
+    %10 = OpTypeStruct %uint
+    %11 = OpTypeStruct %uint
+    %uint_1 = OpConstant %uint 1
+    %20 = OpTypeArray %10 %uint_1
+    %21 = OpTypeArray %11 %uint_1
+  )" + MainBody();
+  auto p = parser(test::Assemble(assembly));
+  EXPECT_TRUE(p->BuildAndParseInternalModule());
+
+  auto* type20 = p->ConvertType(20);
+  ASSERT_NE(type20, nullptr);
+  EXPECT_TRUE(type20->Is<Array>());
+
+  auto* type21 = p->ConvertType(21);
+  ASSERT_NE(type21, nullptr);
+  EXPECT_TRUE(type21->Is<Array>());
+
+  // They map to distinct types in WGSL
+  EXPECT_NE(type21, type20);
+}
+
+TEST_F(SpvParserTest, ConvertType_RuntimeArray_NoDeduplication) {
+  // Prove that distinct SPIR-V runtime arrays map to distinct WGSL types.
+  // The implementation already deduplciates them because it knows
+  // runtime-arrays normally have stride decorations.
+  auto assembly = Preamble() + R"(
+    %uint = OpTypeInt 32 0
+    %10 = OpTypeStruct %uint
+    %11 = OpTypeStruct %uint
+    %20 = OpTypeRuntimeArray %10
+    %21 = OpTypeRuntimeArray %11
+    %22 = OpTypeRuntimeArray %10
+  )" + MainBody();
+  auto p = parser(test::Assemble(assembly));
+  std::cout << assembly << std::endl;
+  EXPECT_TRUE(p->BuildAndParseInternalModule());
+
+  auto* type20 = p->ConvertType(20);
+  ASSERT_NE(type20, nullptr);
+  EXPECT_TRUE(type20->Is<Alias>());
+  EXPECT_TRUE(type20->UnwrapAll()->Is<Array>());
+  EXPECT_EQ(type20->UnwrapAll()->As<Array>()->size, 0u);
+
+  auto* type21 = p->ConvertType(21);
+  ASSERT_NE(type21, nullptr);
+  EXPECT_TRUE(type21->Is<Alias>());
+  EXPECT_TRUE(type21->UnwrapAll()->Is<Array>());
+  EXPECT_EQ(type21->UnwrapAll()->As<Array>()->size, 0u);
+
+  auto* type22 = p->ConvertType(22);
+  ASSERT_NE(type22, nullptr);
+  EXPECT_TRUE(type22->Is<Alias>());
+  EXPECT_TRUE(type22->UnwrapAll()->Is<Array>());
+  EXPECT_EQ(type22->UnwrapAll()->As<Array>()->size, 0u);
+
+  // They map to distinct types in WGSL
+  EXPECT_NE(type21, type20);
+  EXPECT_NE(type22, type21);
+  EXPECT_NE(type22, type20);
+}
+
 // TODO(dneto): Demonstrate other member decorations. Blocked on
 // crbug.com/tint/30
 // TODO(dneto): Demonstrate multiple member deocrations. Blocked on