[spirv-reader] Support duplicate type definitions
Affects structs, runtime arrays
Bug: tint:3, tint:99
Change-Id: I9ca73f8f3f6395c829d134460ad4b1a9e50c3ec9
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/24720
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index e4c1327..6794a37 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -281,7 +281,7 @@
if (type != nullptr) {
id_to_type_[type_id] = type;
}
- MaybeGenerateAlias(spirv_type);
+ MaybeGenerateAlias(type_id, spirv_type);
return type;
};
@@ -303,7 +303,7 @@
case spvtools::opt::analysis::Type::kArray:
return save(ConvertType(spirv_type->AsArray()));
case spvtools::opt::analysis::Type::kStruct:
- return save(ConvertType(spirv_type->AsStruct()));
+ return save(ConvertType(type_id, spirv_type->AsStruct()));
case spvtools::opt::analysis::Type::kPointer:
return save(ConvertType(spirv_type->AsPointer()));
case spvtools::opt::analysis::Type::kFunction:
@@ -671,8 +671,8 @@
}
ast::type::Type* ParserImpl::ConvertType(
+ uint32_t type_id,
const spvtools::opt::analysis::Struct* struct_ty) {
- const auto type_id = type_mgr_->GetId(struct_ty);
// Compute the struct decoration.
auto struct_decorations = this->GetDecorationsFor(type_id);
auto ast_struct_decoration = ast::StructDecoration::kNone;
@@ -757,11 +757,11 @@
return success_;
}
-void ParserImpl::MaybeGenerateAlias(const spvtools::opt::analysis::Type* type) {
+void ParserImpl::MaybeGenerateAlias(uint32_t type_id,
+ const spvtools::opt::analysis::Type* type) {
if (!success_) {
return;
}
- const auto type_id = type_mgr_->GetId(type);
// We only care about struct, arrays, and runtime arrays.
switch (type->kind()) {
diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h
index c4b717f..281adaa 100644
--- a/src/reader/spirv/parser_impl.h
+++ b/src/reader/spirv/parser_impl.h
@@ -146,8 +146,10 @@
/// - decorated arrays and runtime arrays
/// TODO(dneto): I expect images and samplers to require names as well.
/// This is a no-op if the parser has already failed.
+ /// @param type_id the SPIR-V ID for the type
/// @param type the type that might get an alias
- void MaybeGenerateAlias(const spvtools::opt::analysis::Type* type);
+ void MaybeGenerateAlias(uint32_t type_id,
+ const spvtools::opt::analysis::Type* type);
/// @returns the fail stream object
FailStream& fail_stream() { return fail_stream_; }
@@ -324,14 +326,28 @@
/// Converts a specific SPIR-V type to a Tint type. Matrix case
ast::type::Type* ConvertType(const spvtools::opt::analysis::Matrix* mat_ty);
/// Converts a specific SPIR-V type to a Tint type. RuntimeArray case
+ /// @param rtarr_ty the Tint type
ast::type::Type* ConvertType(
const spvtools::opt::analysis::RuntimeArray* rtarr_ty);
/// Converts a specific SPIR-V type to a Tint type. Array case
+ /// @param arr_ty the Tint type
ast::type::Type* ConvertType(const spvtools::opt::analysis::Array* arr_ty);
- /// Converts a specific SPIR-V type to a Tint type. Struct case
+ /// Converts a specific SPIR-V type to a Tint type. Struct case.
+ /// SPIR-V allows distinct struct type definitions for two OpTypeStruct
+ /// that otherwise have the same set of members (and struct and member
+ /// decorations). However, the SPIRV-Tools always produces a unique
+ /// |spvtools::opt::analysis::Struct| object in these cases. For this type
+ /// conversion, we need to have the original SPIR-V ID because we can't always
+ /// recover it from the optimizer's struct type object. This also lets us
+ /// preserve member names, which are given by OpMemberName which is normally
+ /// not significant to the optimizer's module representation.
+ /// @param type_id the SPIR-V ID for the type.
+ /// @param struct_ty the Tint type
ast::type::Type* ConvertType(
+ uint32_t type_id,
const spvtools::opt::analysis::Struct* struct_ty);
/// Converts a specific SPIR-V type to a Tint type. Pointer case
+ /// @param ptr_ty the Tint type
ast::type::Type* ConvertType(const spvtools::opt::analysis::Pointer* ptr_ty);
/// Applies SPIR-V decorations to the given array or runtime-array type.
diff --git a/src/reader/spirv/parser_impl_named_types_test.cc b/src/reader/spirv/parser_impl_named_types_test.cc
index 0c6ba73..1784c04 100644
--- a/src/reader/spirv/parser_impl_named_types_test.cc
+++ b/src/reader/spirv/parser_impl_named_types_test.cc
@@ -53,38 +53,83 @@
EXPECT_THAT(p->module().to_str(), HasSubstr("mystruct -> __struct_"));
}
-// TODO(dneto): Enable this when array types can have ArrayStride
-TEST_F(SpvParserTest, DISABLED_NamedTypes_AnonArrayWithDecoration) {
+TEST_F(SpvParserTest, NamedTypes_Dup_EmitBoth) {
auto* p = parser(test::Assemble(R"(
- OpDecorate %arr ArrayStride 16
%uint = OpTypeInt 32 0
- %uint_3 = OpConstant %uint 3
- %arr = OpTypeArray %uint %uint_3
+ %s = OpTypeStruct %uint %uint
+ %s2 = OpTypeStruct %uint %uint
)"));
- EXPECT_TRUE(p->BuildAndParseInternalModule());
- EXPECT_THAT(p->module().to_str(), HasSubstr("Arr -> __array__u32"));
+ EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+ EXPECT_THAT(p->module().to_str(),
+ HasSubstr("S -> __struct_S\nS_1 -> __struct_S_1"));
}
// TODO(dneto): Should we make an alias for an un-decoratrd array with
// an OpName?
-TEST_F(SpvParserTest, NamedTypes_AnonRTArray) {
+TEST_F(SpvParserTest, NamedTypes_AnonRTArrayWithDecoration) {
+ // Runtime arrays are always in SSBO, and those are always laid out.
auto* p = parser(test::Assemble(R"(
+ OpDecorate %arr ArrayStride 8
%uint = OpTypeInt 32 0
%arr = OpTypeRuntimeArray %uint
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
- EXPECT_THAT(p->module().to_str(), HasSubstr("RTArr -> __array__u32"));
+ // TODO(dneto): this is a string collision with array<u32,8>
+ // https://bugs.chromium.org/p/tint/issues/detail?id=102
+ EXPECT_THAT(p->module().to_str(), HasSubstr("RTArr -> __array__u32_8\n"));
+}
+
+TEST_F(SpvParserTest, NamedTypes_AnonRTArray_Dup_EmitBoth) {
+ auto* p = parser(test::Assemble(R"(
+ OpDecorate %arr ArrayStride 8
+ OpDecorate %arr2 ArrayStride 8
+ %uint = OpTypeInt 32 0
+ %arr = OpTypeRuntimeArray %uint
+ %arr2 = OpTypeRuntimeArray %uint
+ )"));
+ EXPECT_TRUE(p->BuildAndParseInternalModule());
+ EXPECT_THAT(
+ p->module().to_str(),
+ HasSubstr("RTArr -> __array__u32_8\nRTArr_1 -> __array__u32_8\n"));
}
TEST_F(SpvParserTest, NamedTypes_NamedRTArray) {
auto* p = parser(test::Assemble(R"(
OpName %arr "myrtarr"
+ OpDecorate %arr ArrayStride 8
%uint = OpTypeInt 32 0
%arr = OpTypeRuntimeArray %uint
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
- EXPECT_THAT(p->module().to_str(), HasSubstr("myrtarr -> __array__u32"));
+ EXPECT_THAT(p->module().to_str(), HasSubstr("myrtarr -> __array__u32_8\n"));
+}
+
+TEST_F(SpvParserTest, NamedTypes_NamedArray) {
+ auto* p = parser(test::Assemble(R"(
+ OpName %arr "myarr"
+ OpDecorate %arr ArrayStride 8
+ %uint = OpTypeInt 32 0
+ %uint_5 = OpConstant %uint 5
+ %arr = OpTypeArray %uint %uint_5
+ %arr2 = OpTypeArray %uint %uint_5
+ )"));
+ EXPECT_TRUE(p->BuildAndParseInternalModule());
+ EXPECT_THAT(p->module().to_str(), HasSubstr("myarr -> __array__u32_5_8"));
+}
+
+TEST_F(SpvParserTest, NamedTypes_AnonArray_Dup_EmitBoth) {
+ auto* p = parser(test::Assemble(R"(
+ OpDecorate %arr ArrayStride 8
+ OpDecorate %arr2 ArrayStride 8
+ %uint = OpTypeInt 32 0
+ %uint_5 = OpConstant %uint 5
+ %arr = OpTypeArray %uint %uint_5
+ %arr2 = OpTypeArray %uint %uint_5
+ )"));
+ EXPECT_TRUE(p->BuildAndParseInternalModule());
+ EXPECT_THAT(p->module().to_str(),
+ HasSubstr("Arr -> __array__u32_5_8\nArr_1 -> __array__u32_5_8"));
}
// TODO(dneto): Handle arrays sized by a spec constant.