diff --git a/src/ast/struct_member_offset_decoration.cc b/src/ast/struct_member_offset_decoration.cc index 0a70a95e70..ec49b1975e 100644 --- a/src/ast/struct_member_offset_decoration.cc +++ b/src/ast/struct_member_offset_decoration.cc @@ -17,7 +17,7 @@ namespace tint { namespace ast { -StructMemberOffsetDecoration::StructMemberOffsetDecoration(size_t offset) +StructMemberOffsetDecoration::StructMemberOffsetDecoration(uint32_t offset) : offset_(offset) {} StructMemberOffsetDecoration::~StructMemberOffsetDecoration() = default; diff --git a/src/ast/struct_member_offset_decoration.h b/src/ast/struct_member_offset_decoration.h index 8e15a635e0..4e59b2a880 100644 --- a/src/ast/struct_member_offset_decoration.h +++ b/src/ast/struct_member_offset_decoration.h @@ -29,20 +29,20 @@ class StructMemberOffsetDecoration : public StructMemberDecoration { public: /// constructor /// @param offset the offset value - explicit StructMemberOffsetDecoration(size_t offset); + explicit StructMemberOffsetDecoration(uint32_t offset); ~StructMemberOffsetDecoration() override; /// @returns true if this is an offset decoration bool IsOffset() const override { return true; } /// @returns the offset value - size_t offset() const { return offset_; } + uint32_t offset() const { return offset_; } /// @returns the decoration as a string std::string to_str() const override; private: - size_t offset_; + uint32_t offset_; }; } // namespace ast diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc index 1a386db315..6a9063dfc0 100644 --- a/src/writer/spirv/builder.cc +++ b/src/writer/spirv/builder.cc @@ -15,7 +15,11 @@ #include "src/writer/spirv/builder.h" #include "spirv/unified1/spirv.h" +#include "src/ast/struct.h" +#include "src/ast/struct_member.h" +#include "src/ast/struct_member_offset_decoration.h" #include "src/ast/type/matrix_type.h" +#include "src/ast/type/struct_type.h" #include "src/ast/type/vector_type.h" namespace tint { @@ -168,25 +172,19 @@ uint32_t Builder::GenerateTypeIfNeeded(ast::type::Type* type) { } else if (type->IsI32()) { push_type(spv::Op::OpTypeInt, {result, Operand::Int(32), Operand::Int(1)}); } else if (type->IsMatrix()) { - auto mat = type->AsMatrix(); - ast::type::VectorType col_type(mat->type(), mat->rows()); - auto type_id = GenerateTypeIfNeeded(&col_type); - if (has_error()) { + if (!GenerateMatrixType(type->AsMatrix(), result)) { + return 0; + } + } else if (type->IsStruct()) { + if (!GenerateStructType(type->AsStruct(), result)) { return 0; } - - push_type(spv::Op::OpTypeMatrix, - {result, Operand::Int(type_id), Operand::Int(mat->columns())}); } else if (type->IsU32()) { push_type(spv::Op::OpTypeInt, {result, Operand::Int(32), Operand::Int(0)}); } else if (type->IsVector()) { - auto vec = type->AsVector(); - auto col_type_id = GenerateTypeIfNeeded(vec->type()); - if (has_error()) { + if (!GenerateVectorType(type->AsVector(), result)) { return 0; } - push_type(spv::Op::OpTypeVector, - {result, Operand::Int(col_type_id), Operand::Int(vec->size())}); } else if (type->IsVoid()) { push_type(spv::Op::OpTypeVoid, {result}); } else { @@ -198,6 +196,84 @@ uint32_t Builder::GenerateTypeIfNeeded(ast::type::Type* type) { return id; } +bool Builder::GenerateMatrixType(ast::type::MatrixType* mat, + const Operand& result) { + ast::type::VectorType col_type(mat->type(), mat->rows()); + auto col_type_id = GenerateTypeIfNeeded(&col_type); + if (has_error()) { + return false; + } + + push_type(spv::Op::OpTypeMatrix, + {result, Operand::Int(col_type_id), Operand::Int(mat->columns())}); + return true; +} + +bool Builder::GenerateStructType(ast::type::StructType* struct_type, + const Operand& result) { + auto struct_id = result.to_i(); + auto impl = struct_type->impl(); + + std::vector ops; + ops.push_back(result); + + if (impl->decoration() == ast::StructDecoration::kBlock) { + push_annot(spv::Op::OpDecorate, + {Operand::Int(struct_id), Operand::Int(SpvDecorationBlock)}); + } else { + if (impl->decoration() != ast::StructDecoration::kNone) { + error_ = "unknown struct decoration"; + return false; + } + } + + auto& members = impl->members(); + for (uint32_t i = 0; i < members.size(); ++i) { + auto mem_id = GenerateStructMember(struct_id, i, members[i].get()); + if (mem_id == 0) { + return false; + } + + ops.push_back(Operand::Int(mem_id)); + } + + push_type(spv::Op::OpTypeStruct, std::move(ops)); + return true; +} + +uint32_t Builder::GenerateStructMember(uint32_t struct_id, + uint32_t idx, + ast::StructMember* member) { + push_debug(spv::Op::OpMemberName, {Operand::Int(struct_id), Operand::Int(idx), + Operand::String(member->name())}); + + for (const auto& deco : member->decorations()) { + if (deco->IsOffset()) { + push_annot(spv::Op::OpMemberDecorate, + {Operand::Int(struct_id), Operand::Int(idx), + Operand::Int(SpvDecorationOffset), + Operand::Int(deco->AsOffset()->offset())}); + } else { + error_ = "unknown struct member decoration"; + return 0; + } + } + + return GenerateTypeIfNeeded(member->type()); +} + +bool Builder::GenerateVectorType(ast::type::VectorType* vec, + const Operand& result) { + auto type_id = GenerateTypeIfNeeded(vec->type()); + if (has_error()) { + return false; + } + + push_type(spv::Op::OpTypeVector, + {result, Operand::Int(type_id), Operand::Int(vec->size())}); + return true; +} + } // namespace spirv } // namespace writer } // namespace tint diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h index 7a42e3edf0..31efbde760 100644 --- a/src/writer/spirv/builder.h +++ b/src/writer/spirv/builder.h @@ -21,6 +21,7 @@ #include #include "src/ast/module.h" +#include "src/ast/struct_member.h" #include "src/writer/spirv/instruction.h" namespace tint { @@ -117,7 +118,7 @@ class Builder { annotations_.push_back(Instruction{op, operands}); } /// @returns the annotations - const std::vector& annot() const { return annotations_; } + const std::vector& annots() const { return annotations_; } /// Generates an entry point instruction /// @param ep the entry point @@ -130,6 +131,30 @@ class Builder { /// @param type the type to create /// @returns the ID to use for the given type. Returns 0 on unknown type. uint32_t GenerateTypeIfNeeded(ast::type::Type* type); + /// Generates a matrix type declaration + /// @param mat the matrix to generate + /// @param result the result operand + /// @returns true if the matrix was successfully generated + bool GenerateMatrixType(ast::type::MatrixType* mat, const Operand& result); + /// Generates a vector type declaration + /// @param struct_type the vector to generate + /// @param result the result operand + /// @returns true if the vector was successfully generated + bool GenerateStructType(ast::type::StructType* struct_type, + const Operand& result); + /// Generates a vector type declaration + /// @param vec the vector to generate + /// @param result the result operand + /// @returns true if the vector was successfully generated + bool GenerateVectorType(ast::type::VectorType* vec, const Operand& result); + /// Generates a struct member + /// @param struct_id the id of the parent structure + /// @param idx the index of the member + /// @param member the member to generate + /// @returns the id of the struct member or 0 on error. + uint32_t GenerateStructMember(uint32_t struct_id, + uint32_t idx, + ast::StructMember* member); private: /// @returns an Operand with a new result ID in it. Increments the next_id_ diff --git a/src/writer/spirv/builder_type_test.cc b/src/writer/spirv/builder_type_test.cc index 014d8c17f7..7dca01cd37 100644 --- a/src/writer/spirv/builder_type_test.cc +++ b/src/writer/spirv/builder_type_test.cc @@ -15,6 +15,9 @@ #include #include "gtest/gtest.h" +#include "src/ast/struct.h" +#include "src/ast/struct_member.h" +#include "src/ast/struct_member_offset_decoration.h" #include "src/ast/type/alias_type.h" #include "src/ast/type/array_type.h" #include "src/ast/type/bool_type.h" @@ -22,6 +25,7 @@ #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/u32_type.h" #include "src/ast/type/vector_type.h" #include "src/ast/type/void_type.h" @@ -171,6 +175,104 @@ TEST_F(BuilderTest_Type, ReturnsGeneratedMatrix) { ASSERT_FALSE(b.has_error()) << b.error(); } +TEST_F(BuilderTest_Type, GenerateStruct_Empty) { + auto s = std::make_unique(); + ast::type::StructType s_type(std::move(s)); + + Builder b; + auto id = b.GenerateTypeIfNeeded(&s_type); + ASSERT_FALSE(b.has_error()) << b.error(); + EXPECT_EQ(id, 1); + + EXPECT_EQ(b.types().size(), 1); + EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeStruct +)"); +} + +TEST_F(BuilderTest_Type, GenerateStruct) { + ast::type::F32Type f32; + + std::vector> decos; + std::vector> members; + members.push_back( + std::make_unique("a", &f32, std::move(decos))); + + auto s = std::make_unique(ast::StructDecoration::kNone, + std::move(members)); + ast::type::StructType s_type(std::move(s)); + + Builder b; + auto id = b.GenerateTypeIfNeeded(&s_type); + ASSERT_FALSE(b.has_error()) << b.error(); + EXPECT_EQ(id, 1); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32 +%1 = OpTypeStruct %2 +)"); + EXPECT_EQ(DumpInstructions(b.debug()), R"(OpMemberName %1 0 "a" +)"); +} + +TEST_F(BuilderTest_Type, GenerateStruct_Decorated) { + ast::type::F32Type f32; + + std::vector> decos; + std::vector> members; + members.push_back( + std::make_unique("a", &f32, std::move(decos))); + + auto s = std::make_unique(ast::StructDecoration::kBlock, + std::move(members)); + ast::type::StructType s_type(std::move(s)); + + Builder b; + auto id = b.GenerateTypeIfNeeded(&s_type); + ASSERT_FALSE(b.has_error()) << b.error(); + EXPECT_EQ(id, 1); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32 +%1 = OpTypeStruct %2 +)"); + EXPECT_EQ(DumpInstructions(b.debug()), R"(OpMemberName %1 0 "a" +)"); + EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 Block +)"); +} + +TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers) { + ast::type::F32Type f32; + + std::vector> a_decos; + a_decos.push_back(std::make_unique(0)); + std::vector> b_decos; + b_decos.push_back(std::make_unique(8)); + + std::vector> members; + members.push_back( + std::make_unique("a", &f32, std::move(a_decos))); + members.push_back( + std::make_unique("b", &f32, std::move(b_decos))); + + auto s = std::make_unique(ast::StructDecoration::kNone, + std::move(members)); + ast::type::StructType s_type(std::move(s)); + + Builder b; + auto id = b.GenerateTypeIfNeeded(&s_type); + ASSERT_FALSE(b.has_error()) << b.error(); + EXPECT_EQ(id, 1); + + EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32 +%1 = OpTypeStruct %2 %2 +)"); + EXPECT_EQ(DumpInstructions(b.debug()), R"(OpMemberName %1 0 "a" +OpMemberName %1 1 "b" +)"); + EXPECT_EQ(DumpInstructions(b.annots()), R"(OpMemberDecorate %1 0 Offset 0 +OpMemberDecorate %1 1 Offset 8 +)"); +} + TEST_F(BuilderTest_Type, GenerateU32) { ast::type::U32Type u32;