From 269a2c6a911b1dffd1d4bcd4812ef7c021b0fd73 Mon Sep 17 00:00:00 2001 From: David Neto Date: Wed, 1 Apr 2020 13:22:34 +0000 Subject: [PATCH] [spirv-reader] Convert pointer type Bug: tint:3 Change-Id: Ibba1472a1aa3f1399e9596ee6662a29121d88eca Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/18420 Reviewed-by: dan sinclair --- src/reader/spirv/parser_impl.cc | 28 ++- src/reader/spirv/parser_impl.h | 2 + .../spirv/parser_impl_convert_type_test.cc | 215 +++++++++++++++++- 3 files changed, 241 insertions(+), 4 deletions(-) diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc index 2480a348e0..efa2d3e859 100644 --- a/src/reader/spirv/parser_impl.cc +++ b/src/reader/spirv/parser_impl.cc @@ -38,6 +38,7 @@ #include "src/ast/type/f32_type.h" #include "src/ast/type/i32_type.h" #include "src/ast/type/matrix_type.h" +#include "src/ast/type/pointer_type.h" #include "src/ast/type/struct_type.h" #include "src/ast/type/type.h" #include "src/ast/type/u32_type.h" @@ -164,10 +165,10 @@ ast::type::Type* ParserImpl::ConvertType(uint32_t type_id) { return save(ConvertType(spirv_type->AsArray())); case spvtools::opt::analysis::Type::kStruct: return save(ConvertType(spirv_type->AsStruct())); - case spvtools::opt::analysis::Type::kFunction: case spvtools::opt::analysis::Type::kPointer: - // For now, just return null without erroring out. - // TODO(dneto) + return save(ConvertType(spirv_type->AsPointer())); + case spvtools::opt::analysis::Type::kFunction: + // TODO(dneto). For now return null without erroring out. return nullptr; default: break; @@ -520,6 +521,27 @@ ast::type::Type* ParserImpl::ConvertType( return ctx_.type_mgr().Get(std::move(ast_struct_type)); } +ast::type::Type* ParserImpl::ConvertType( + const spvtools::opt::analysis::Pointer* ptr_ty) { + auto* ast_elem_ty = ConvertType(type_mgr_->GetId(ptr_ty->pointee_type())); + if (ast_elem_ty == nullptr) { + Fail() << "SPIR-V pointer type with ID " << type_mgr_->GetId(ptr_ty) + << " has invalid pointee type " + << type_mgr_->GetId(ptr_ty->pointee_type()); + return nullptr; + } + auto ast_storage_class = + enum_converter_.ToStorageClass(ptr_ty->storage_class()); + if (ast_storage_class == ast::StorageClass::kNone) { + Fail() << "SPIR-V pointer type with ID " << type_mgr_->GetId(ptr_ty) + << " has invalid storage class " + << static_cast(ptr_ty->storage_class()); + return nullptr; + } + return ctx_.type_mgr().Get( + std::make_unique(ast_elem_ty, ast_storage_class)); +} + bool ParserImpl::RegisterTypes() { if (!success_) { return false; diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h index a38ddafe7c..4ddcf190f8 100644 --- a/src/reader/spirv/parser_impl.h +++ b/src/reader/spirv/parser_impl.h @@ -190,6 +190,8 @@ class ParserImpl : Reader { /// Converts a specific SPIR-V type to a Tint type. Struct case ast::type::Type* ConvertType( const spvtools::opt::analysis::Struct* struct_ty); + /// Converts a specific SPIR-V type to a Tint type. Pointer case + ast::type::Type* ConvertType(const spvtools::opt::analysis::Pointer* ptr_ty); // The SPIR-V binary we're parsing std::vector spv_binary_; diff --git a/src/reader/spirv/parser_impl_convert_type_test.cc b/src/reader/spirv/parser_impl_convert_type_test.cc index f5daed01e8..aa0fe09f78 100644 --- a/src/reader/spirv/parser_impl_convert_type_test.cc +++ b/src/reader/spirv/parser_impl_convert_type_test.cc @@ -20,7 +20,9 @@ #include "src/ast/struct.h" #include "src/ast/type/array_type.h" #include "src/ast/type/matrix_type.h" +#include "src/ast/type/pointer_type.h" #include "src/ast/type/struct_type.h" +#include "src/ast/type/type.h" #include "src/ast/type/vector_type.h" #include "src/reader/spirv/parser_impl.h" #include "src/reader/spirv/parser_impl_test_helper.h" @@ -484,11 +486,222 @@ TEST_F(SpvParserTest, ConvertType_StructWithMemberDecorations) { )")); } -// TODO(dneto): Demonstrate other member deocrations. Blocked on +// TODO(dneto): Demonstrate other member decorations. Blocked on // crbug.com/tint/30 // TODO(dneto): Demonstrate multiple member deocrations. Blocked on // crbug.com/tint/30 +TEST_F(SpvParserTest, ConvertType_InvalidPointeetype) { + // Disallow pointer-to-function + auto p = parser(test::Assemble(R"( + %void = OpTypeVoid + %42 = OpTypeFunction %void + %3 = OpTypePointer Input %42 + )")); + EXPECT_TRUE(p->BuildInternalModule()) << p->error(); + + auto* type = p->ConvertType(3); + EXPECT_EQ(type, nullptr); + EXPECT_THAT(p->error(), + Eq("SPIR-V pointer type with ID 3 has invalid pointee type 42")); +} + +TEST_F(SpvParserTest, DISABLED_ConvertType_InvalidStorageClass) { + // Disallow invalid storage class + auto p = parser(test::Assemble(R"( + %1 = OpTypeFloat 32 + %3 = OpTypePointer !999 %1 ; Special syntax to inject 999 as the storage class + )")); + // TODO(dneto): I can't get it past module building. + EXPECT_FALSE(p->BuildInternalModule()) << p->error(); +} + +TEST_F(SpvParserTest, ConvertType_PointerInput) { + auto p = parser(test::Assemble(R"( + %float = OpTypeFloat 32 + %3 = OpTypePointer Input %float + )")); + EXPECT_TRUE(p->BuildInternalModule()); + + auto* type = p->ConvertType(3); + EXPECT_TRUE(type->IsPointer()); + auto* ptr_ty = type->AsPointer(); + EXPECT_NE(ptr_ty, nullptr); + EXPECT_TRUE(ptr_ty->type()->IsF32()); + EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kInput); + EXPECT_TRUE(p->error().empty()); +} + +TEST_F(SpvParserTest, ConvertType_PointerOutput) { + auto p = parser(test::Assemble(R"( + %float = OpTypeFloat 32 + %3 = OpTypePointer Output %float + )")); + EXPECT_TRUE(p->BuildInternalModule()); + + auto* type = p->ConvertType(3); + EXPECT_TRUE(type->IsPointer()); + auto* ptr_ty = type->AsPointer(); + EXPECT_NE(ptr_ty, nullptr); + EXPECT_TRUE(ptr_ty->type()->IsF32()); + EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kOutput); + EXPECT_TRUE(p->error().empty()); +} + +TEST_F(SpvParserTest, ConvertType_PointerUniform) { + auto p = parser(test::Assemble(R"( + %float = OpTypeFloat 32 + %3 = OpTypePointer Uniform %float + )")); + EXPECT_TRUE(p->BuildInternalModule()); + + auto* type = p->ConvertType(3); + EXPECT_TRUE(type->IsPointer()); + auto* ptr_ty = type->AsPointer(); + EXPECT_NE(ptr_ty, nullptr); + EXPECT_TRUE(ptr_ty->type()->IsF32()); + EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kUniform); + EXPECT_TRUE(p->error().empty()); +} + +TEST_F(SpvParserTest, ConvertType_PointerWorkgroup) { + auto p = parser(test::Assemble(R"( + %float = OpTypeFloat 32 + %3 = OpTypePointer Workgroup %float + )")); + EXPECT_TRUE(p->BuildInternalModule()); + + auto* type = p->ConvertType(3); + EXPECT_TRUE(type->IsPointer()); + auto* ptr_ty = type->AsPointer(); + EXPECT_NE(ptr_ty, nullptr); + EXPECT_TRUE(ptr_ty->type()->IsF32()); + EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kWorkgroup); + EXPECT_TRUE(p->error().empty()); +} + +TEST_F(SpvParserTest, ConvertType_PointerUniformConstant) { + auto p = parser(test::Assemble(R"( + %float = OpTypeFloat 32 + %3 = OpTypePointer UniformConstant %float + )")); + EXPECT_TRUE(p->BuildInternalModule()); + + auto* type = p->ConvertType(3); + EXPECT_TRUE(type->IsPointer()); + auto* ptr_ty = type->AsPointer(); + EXPECT_NE(ptr_ty, nullptr); + EXPECT_TRUE(ptr_ty->type()->IsF32()); + EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kUniformConstant); + EXPECT_TRUE(p->error().empty()); +} + +TEST_F(SpvParserTest, ConvertType_PointerStorageBuffer) { + auto p = parser(test::Assemble(R"( + %float = OpTypeFloat 32 + %3 = OpTypePointer StorageBuffer %float + )")); + EXPECT_TRUE(p->BuildInternalModule()); + + auto* type = p->ConvertType(3); + EXPECT_TRUE(type->IsPointer()); + auto* ptr_ty = type->AsPointer(); + EXPECT_NE(ptr_ty, nullptr); + EXPECT_TRUE(ptr_ty->type()->IsF32()); + EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kStorageBuffer); + EXPECT_TRUE(p->error().empty()); +} + +TEST_F(SpvParserTest, ConvertType_PointerImage) { + auto p = parser(test::Assemble(R"( + %float = OpTypeFloat 32 + %3 = OpTypePointer Image %float + )")); + EXPECT_TRUE(p->BuildInternalModule()); + + auto* type = p->ConvertType(3); + EXPECT_TRUE(type->IsPointer()); + auto* ptr_ty = type->AsPointer(); + EXPECT_NE(ptr_ty, nullptr); + EXPECT_TRUE(ptr_ty->type()->IsF32()); + EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kImage); + EXPECT_TRUE(p->error().empty()); +} + +TEST_F(SpvParserTest, ConvertType_PointerPushConstant) { + auto p = parser(test::Assemble(R"( + %float = OpTypeFloat 32 + %3 = OpTypePointer PushConstant %float + )")); + EXPECT_TRUE(p->BuildInternalModule()); + + auto* type = p->ConvertType(3); + EXPECT_TRUE(type->IsPointer()); + auto* ptr_ty = type->AsPointer(); + EXPECT_NE(ptr_ty, nullptr); + EXPECT_TRUE(ptr_ty->type()->IsF32()); + EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kPushConstant); + EXPECT_TRUE(p->error().empty()); +} + +TEST_F(SpvParserTest, ConvertType_PointerPrivate) { + auto p = parser(test::Assemble(R"( + %float = OpTypeFloat 32 + %3 = OpTypePointer Private %float + )")); + EXPECT_TRUE(p->BuildInternalModule()); + + auto* type = p->ConvertType(3); + EXPECT_TRUE(type->IsPointer()); + auto* ptr_ty = type->AsPointer(); + EXPECT_NE(ptr_ty, nullptr); + EXPECT_TRUE(ptr_ty->type()->IsF32()); + EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kPrivate); + EXPECT_TRUE(p->error().empty()); +} + +TEST_F(SpvParserTest, ConvertType_PointerFunction) { + auto p = parser(test::Assemble(R"( + %float = OpTypeFloat 32 + %3 = OpTypePointer Function %float + )")); + EXPECT_TRUE(p->BuildInternalModule()); + + auto* type = p->ConvertType(3); + EXPECT_TRUE(type->IsPointer()); + auto* ptr_ty = type->AsPointer(); + EXPECT_NE(ptr_ty, nullptr); + EXPECT_TRUE(ptr_ty->type()->IsF32()); + EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kFunction); + EXPECT_TRUE(p->error().empty()); +} + +TEST_F(SpvParserTest, ConvertType_PointerToPointer) { + // FYI: The reader suports pointer-to-pointer even while WebGPU does not. + auto p = parser(test::Assemble(R"( + %float = OpTypeFloat 32 + %42 = OpTypePointer Output %float + %3 = OpTypePointer Input %42 + )")); + EXPECT_TRUE(p->BuildInternalModule()); + + auto* type = p->ConvertType(3); + EXPECT_NE(type, nullptr); + EXPECT_TRUE(type->IsPointer()); + + auto* ptr_ty = type->AsPointer(); + EXPECT_NE(ptr_ty, nullptr); + EXPECT_EQ(ptr_ty->storage_class(), ast::StorageClass::kInput); + EXPECT_TRUE(ptr_ty->type()->IsPointer()); + + auto* ptr_ptr_ty = ptr_ty->type()->AsPointer(); + EXPECT_NE(ptr_ptr_ty, nullptr); + EXPECT_EQ(ptr_ptr_ty->storage_class(), ast::StorageClass::kOutput); + EXPECT_TRUE(ptr_ptr_ty->type()->IsF32()); + + EXPECT_TRUE(p->error().empty()); +} + } // namespace } // namespace spirv } // namespace reader