From 1bbc1cb2c122dae6ba854839b8327081a508c778 Mon Sep 17 00:00:00 2001 From: David Neto Date: Tue, 19 May 2020 14:46:41 +0000 Subject: [PATCH] [spirv-reader] Support null vector, matrix, arr, struct Bug: tint:3 Change-Id: I2fa25e5d28b965de4a419719e37bc999be8489ea Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/21581 Reviewed-by: dan sinclair --- src/reader/spirv/parser_impl.cc | 76 ++++++++ src/reader/spirv/parser_impl.h | 7 +- .../spirv/parser_impl_module_var_test.cc | 182 ++++++++++++++++++ 3 files changed, 264 insertions(+), 1 deletion(-) diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc index 7016e5ea40..a09401cb5d 100644 --- a/src/reader/spirv/parser_impl.cc +++ b/src/reader/spirv/parser_impl.cc @@ -914,11 +914,87 @@ TypedExpression ParserImpl::MakeConstantExpression(uint32_t id) { return {ast_type, std::make_unique( ast_type, std::move(ast_components))}; } + auto* spirv_null_const = spirv_const->AsNullConstant(); + if (spirv_null_const != nullptr) { + return {ast_type, MakeNullValue(ast_type)}; + } Fail() << "Unhandled constant type " << inst->type_id() << " for value ID " << id; return {}; } +std::unique_ptr ParserImpl::MakeNullValue( + ast::type::Type* type) { + // TODO(dneto): Use the no-operands constructor syntax when it becomes + // available in Tint. + // https://github.com/gpuweb/gpuweb/issues/685 + // https://bugs.chromium.org/p/tint/issues/detail?id=34 + + if (!type) { + Fail() << "trying to create null value for a null type"; + return nullptr; + } + + if (type->IsBool()) { + return std::make_unique( + std::make_unique(type, false)); + } + if (type->IsU32()) { + return std::make_unique( + std::make_unique(type, 0u)); + } + if (type->IsI32()) { + return std::make_unique( + std::make_unique(type, 0)); + } + if (type->IsF32()) { + return std::make_unique( + std::make_unique(type, 0.0f)); + } + if (type->IsVector()) { + const auto* vec_ty = type->AsVector(); + ast::ExpressionList ast_components; + for (size_t i = 0; i < vec_ty->size(); ++i) { + ast_components.emplace_back(MakeNullValue(vec_ty->type())); + } + return std::make_unique( + type, std::move(ast_components)); + } + if (type->IsMatrix()) { + const auto* mat_ty = type->AsMatrix(); + // Matrix components are columns + auto* column_ty = + ctx_.type_mgr().Get(std::make_unique( + mat_ty->type(), mat_ty->rows())); + ast::ExpressionList ast_components; + for (size_t i = 0; i < mat_ty->columns(); ++i) { + ast_components.emplace_back(MakeNullValue(column_ty)); + } + return std::make_unique( + type, std::move(ast_components)); + } + if (type->IsArray()) { + auto* arr_ty = type->AsArray(); + ast::ExpressionList ast_components; + for (size_t i = 0; i < arr_ty->size(); ++i) { + ast_components.emplace_back(MakeNullValue(arr_ty->type())); + } + return std::make_unique( + type, std::move(ast_components)); + } + if (type->IsStruct()) { + auto* struct_ty = type->AsStruct(); + ast::ExpressionList ast_components; + for (auto& member : struct_ty->impl()->members()) { + ast_components.emplace_back(MakeNullValue(member->type())); + } + return std::make_unique( + type, std::move(ast_components)); + } + Fail() << "can't make null value for type: " << type->type_name(); + return nullptr; +} + TypedExpression ParserImpl::RectifyOperandSignedness(SpvOp op, TypedExpression&& expr) { const bool requires_signed = AssumesSignedOperands(op); diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h index 743a5b25b4..554fe27cbe 100644 --- a/src/reader/spirv/parser_impl.h +++ b/src/reader/spirv/parser_impl.h @@ -244,9 +244,14 @@ class ParserImpl : Reader { /// Creates an AST expression node for a SPIR-V constant. /// @param id the SPIR-V ID of the constant - /// @returns a new Literal node + /// @returns a new expression TypedExpression MakeConstantExpression(uint32_t id); + /// Creates an AST expression node for the null value for the given type. + /// @param type the AST type + /// @returns a new expression + std::unique_ptr MakeNullValue(ast::type::Type* type); + /// Converts a given expression to the signedness demanded for an operand /// of the given SPIR-V opcode, if required. If the operation assumes /// signed integer operands, and |expr| is unsigned, then return an diff --git a/src/reader/spirv/parser_impl_module_var_test.cc b/src/reader/spirv/parser_impl_module_var_test.cc index eb60d25f7b..d46ab0ad99 100644 --- a/src/reader/spirv/parser_impl_module_var_test.cc +++ b/src/reader/spirv/parser_impl_module_var_test.cc @@ -50,6 +50,9 @@ std::string CommonTypes() { %int_m1 = OpConstant %int -1 %uint_2 = OpConstant %uint 2 + %v2bool = OpTypeVector %bool 2 + %v2uint = OpTypeVector %uint 2 + %v2int = OpTypeVector %int 2 %v2float = OpTypeVector %float 2 %m3v2float = OpTypeMatrix %v2float 3 @@ -300,6 +303,98 @@ TEST_F(SpvParserTest, ModuleScopeVar_VectorInitializer) { })")); } +TEST_F(SpvParserTest, ModuleScopeVar_VectorBoolNullInitializer) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %ptr = OpTypePointer Private %v2bool + %const = OpConstantNull %v2bool + %200 = OpVariable %ptr Private %const + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"(Variable{ + x_200 + private + __vec_2__bool + { + TypeConstructor{ + __vec_2__bool + ScalarConstructor{false} + ScalarConstructor{false} + } + } + })")); +} + +TEST_F(SpvParserTest, ModuleScopeVar_VectorUintNullInitializer) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %ptr = OpTypePointer Private %v2uint + %const = OpConstantNull %v2uint + %200 = OpVariable %ptr Private %const + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"(Variable{ + x_200 + private + __vec_2__u32 + { + TypeConstructor{ + __vec_2__u32 + ScalarConstructor{0} + ScalarConstructor{0} + } + } + })")); +} + +TEST_F(SpvParserTest, ModuleScopeVar_VectorIntNullInitializer) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %ptr = OpTypePointer Private %v2int + %const = OpConstantNull %v2int + %200 = OpVariable %ptr Private %const + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"(Variable{ + x_200 + private + __vec_2__i32 + { + TypeConstructor{ + __vec_2__i32 + ScalarConstructor{0} + ScalarConstructor{0} + } + } + })")); +} + +TEST_F(SpvParserTest, ModuleScopeVar_VectorFloatNullInitializer) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %ptr = OpTypePointer Private %v2float + %const = OpConstantNull %v2float + %200 = OpVariable %ptr Private %const + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"(Variable{ + x_200 + private + __vec_2__f32 + { + TypeConstructor{ + __vec_2__f32 + ScalarConstructor{0.000000} + ScalarConstructor{0.000000} + } + } + })")); +} + TEST_F(SpvParserTest, ModuleScopeVar_MatrixInitializer) { auto* p = parser(test::Assemble(CommonTypes() + R"( %ptr = OpTypePointer Private %m3v2float @@ -342,6 +437,42 @@ TEST_F(SpvParserTest, ModuleScopeVar_MatrixInitializer) { })")); } +TEST_F(SpvParserTest, ModuleScopeVar_MatrixNullInitializer) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %ptr = OpTypePointer Private %m3v2float + %const = OpConstantNull %m3v2float + %200 = OpVariable %ptr Private %const + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"(Variable{ + x_200 + private + __mat_2_3__f32 + { + TypeConstructor{ + __mat_2_3__f32 + TypeConstructor{ + __vec_2__f32 + ScalarConstructor{0.000000} + ScalarConstructor{0.000000} + } + TypeConstructor{ + __vec_2__f32 + ScalarConstructor{0.000000} + ScalarConstructor{0.000000} + } + TypeConstructor{ + __vec_2__f32 + ScalarConstructor{0.000000} + ScalarConstructor{0.000000} + } + } + } + })")); +} + TEST_F(SpvParserTest, ModuleScopeVar_ArrayInitializer) { auto* p = parser(test::Assemble(CommonTypes() + R"( %ptr = OpTypePointer Private %arr2uint @@ -366,6 +497,29 @@ TEST_F(SpvParserTest, ModuleScopeVar_ArrayInitializer) { })")); } +TEST_F(SpvParserTest, ModuleScopeVar_ArrayNullInitializer) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %ptr = OpTypePointer Private %arr2uint + %const = OpConstantNull %arr2uint + %200 = OpVariable %ptr Private %const + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"(Variable{ + x_200 + private + __array__u32_2 + { + TypeConstructor{ + __array__u32_2 + ScalarConstructor{0} + ScalarConstructor{0} + } + } + })")); +} + TEST_F(SpvParserTest, ModuleScopeVar_StructInitializer) { auto* p = parser(test::Assemble(CommonTypes() + R"( %ptr = OpTypePointer Private %strct @@ -396,6 +550,34 @@ TEST_F(SpvParserTest, ModuleScopeVar_StructInitializer) { })")); } +TEST_F(SpvParserTest, ModuleScopeVar_StructNullInitializer) { + auto* p = parser(test::Assemble(CommonTypes() + R"( + %ptr = OpTypePointer Private %strct + %const = OpConstantNull %strct + %200 = OpVariable %ptr Private %const + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"(Variable{ + x_200 + private + __struct_S + { + TypeConstructor{ + __struct_S + ScalarConstructor{0} + ScalarConstructor{0.000000} + TypeConstructor{ + __array__u32_2 + ScalarConstructor{0} + ScalarConstructor{0} + } + } + } + })")); +} + } // namespace } // namespace spirv } // namespace reader