diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc index 9c1a158b8b..3cd3d7e2aa 100644 --- a/src/reader/spirv/parser_impl.cc +++ b/src/reader/spirv/parser_impl.cc @@ -35,12 +35,14 @@ #include "spirv-tools/libspirv.hpp" #include "src/ast/as_expression.h" #include "src/ast/binary_expression.h" +#include "src/ast/binding_decoration.h" #include "src/ast/bool_literal.h" #include "src/ast/builtin.h" #include "src/ast/builtin_decoration.h" #include "src/ast/decorated_variable.h" #include "src/ast/float_literal.h" #include "src/ast/scalar_constructor_expression.h" +#include "src/ast/set_decoration.h" #include "src/ast/sint_literal.h" #include "src/ast/struct.h" #include "src/ast/struct_decoration.h" @@ -985,6 +987,24 @@ std::unique_ptr ParserImpl::MakeVariable(uint32_t id, ast_decorations.emplace_back( std::make_unique(deco[1])); } + if (deco[0] == SpvDecorationDescriptorSet) { + if (deco.size() == 1) { + Fail() << "malformed DescriptorSet decoration on ID " << id + << ": has no operand"; + return nullptr; + } + ast_decorations.emplace_back( + std::make_unique(deco[1])); + } + if (deco[0] == SpvDecorationBinding) { + if (deco.size() == 1) { + Fail() << "malformed Binding decoration on ID " << id + << ": has no operand"; + return nullptr; + } + ast_decorations.emplace_back( + std::make_unique(deco[1])); + } } if (!ast_decorations.empty()) { auto decorated_var = diff --git a/src/reader/spirv/parser_impl_module_var_test.cc b/src/reader/spirv/parser_impl_module_var_test.cc index 83895af7f8..dac84673c5 100644 --- a/src/reader/spirv/parser_impl_module_var_test.cc +++ b/src/reader/spirv/parser_impl_module_var_test.cc @@ -1184,6 +1184,114 @@ TEST_F(SpvParserTest, "instruction, found '4'.")); } +TEST_F(SpvParserTest, ModuleScopeVar_DescriptorSetDecoration_Valid) { + auto* p = parser(test::Assemble(R"( + OpName %myvar "myvar" + OpDecorate %myvar DescriptorSet 3 + OpDecorate %strct Block +)" + CommonTypes() + R"( + %ptr_sb_strct = OpTypePointer StorageBuffer %strct + %myvar = OpVariable %ptr_sb_strct StorageBuffer + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error(); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"( + DecoratedVariable{ + Decorations{ + SetDecoration{3} + } + myvar + storage_buffer + __alias_S__struct_S + })")) + << module_str; +} + +TEST_F(SpvParserTest, + ModuleScopeVar_DescriptorSetDecoration_MissingOperandWontAssemble) { + const auto assembly = R"( + OpName %myvar "myvar" + OpDecorate %myvar DescriptorSet + OpDecorate %strct Block +)" + CommonTypes() + R"( + %ptr_sb_strct = OpTypePointer StorageBuffer %strct + %myvar = OpVariable %ptr_sb_strct StorageBuffer + )"; + EXPECT_THAT(test::AssembleFailure(assembly), + Eq("3:5: Expected operand, found next instruction instead.")); +} + +TEST_F(SpvParserTest, + ModuleScopeVar_DescriptorSetDecoration_TwoOperandsWontAssemble) { + const auto assembly = R"( + OpName %myvar "myvar" + OpDecorate %myvar DescriptorSet 3 4 + OpDecorate %strct Block +)" + CommonTypes() + R"( + %ptr_sb_strct = OpTypePointer StorageBuffer %strct + %myvar = OpVariable %ptr_sb_strct StorageBuffer + )"; + EXPECT_THAT( + test::AssembleFailure(assembly), + Eq("2:39: Expected or at the beginning of an " + "instruction, found '4'.")); +} + +TEST_F(SpvParserTest, ModuleScopeVar_BindingDecoration_Valid) { + auto* p = parser(test::Assemble(R"( + OpName %myvar "myvar" + OpDecorate %myvar Binding 3 + OpDecorate %strct Block +)" + CommonTypes() + R"( + %ptr_sb_strct = OpTypePointer StorageBuffer %strct + %myvar = OpVariable %ptr_sb_strct StorageBuffer + )")); + ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error(); + EXPECT_TRUE(p->error().empty()); + const auto module_str = p->module().to_str(); + EXPECT_THAT(module_str, HasSubstr(R"( + DecoratedVariable{ + Decorations{ + BindingDecoration{3} + } + myvar + storage_buffer + __alias_S__struct_S + })")) + << module_str; +} + +TEST_F(SpvParserTest, + ModuleScopeVar_BindingDecoration_MissingOperandWontAssemble) { + const auto assembly = R"( + OpName %myvar "myvar" + OpDecorate %myvar Binding + OpDecorate %strct Block +)" + CommonTypes() + R"( + %ptr_sb_strct = OpTypePointer StorageBuffer %strct + %myvar = OpVariable %ptr_sb_strct StorageBuffer + )"; + EXPECT_THAT(test::AssembleFailure(assembly), + Eq("3:5: Expected operand, found next instruction instead.")); +} + +TEST_F(SpvParserTest, + ModuleScopeVar_BindingDecoration_TwoOperandsWontAssemble) { + const auto assembly = R"( + OpName %myvar "myvar" + OpDecorate %myvar Binding 3 4 + OpDecorate %strct Block +)" + CommonTypes() + R"( + %ptr_sb_strct = OpTypePointer StorageBuffer %strct + %myvar = OpVariable %ptr_sb_strct StorageBuffer + )"; + EXPECT_THAT( + test::AssembleFailure(assembly), + Eq("2:33: Expected or at the beginning of an " + "instruction, found '4'.")); +} + } // namespace } // namespace spirv } // namespace reader