[spirv-writer] Generate struct types
This CL adds generation of Struct types to the SPIR-V writer. Bug: tint:5 Change-Id: Ibcabf7b1a688026297de682f4825d5195d8007d2 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/17701 Reviewed-by: David Neto <dneto@google.com>
This commit is contained in:
parent
6cd52e30ef
commit
69b9c1b8e0
|
@ -17,7 +17,7 @@
|
|||
namespace tint {
|
||||
namespace ast {
|
||||
|
||||
StructMemberOffsetDecoration::StructMemberOffsetDecoration(size_t offset)
|
||||
StructMemberOffsetDecoration::StructMemberOffsetDecoration(uint32_t offset)
|
||||
: offset_(offset) {}
|
||||
|
||||
StructMemberOffsetDecoration::~StructMemberOffsetDecoration() = default;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<Operand> 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
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <vector>
|
||||
|
||||
#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<Instruction>& annot() const { return annotations_; }
|
||||
const std::vector<Instruction>& 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_
|
||||
|
|
|
@ -15,6 +15,9 @@
|
|||
#include <memory>
|
||||
|
||||
#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::Struct>();
|
||||
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<std::unique_ptr<ast::StructMemberDecoration>> decos;
|
||||
std::vector<std::unique_ptr<ast::StructMember>> members;
|
||||
members.push_back(
|
||||
std::make_unique<ast::StructMember>("a", &f32, std::move(decos)));
|
||||
|
||||
auto s = std::make_unique<ast::Struct>(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<std::unique_ptr<ast::StructMemberDecoration>> decos;
|
||||
std::vector<std::unique_ptr<ast::StructMember>> members;
|
||||
members.push_back(
|
||||
std::make_unique<ast::StructMember>("a", &f32, std::move(decos)));
|
||||
|
||||
auto s = std::make_unique<ast::Struct>(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<std::unique_ptr<ast::StructMemberDecoration>> a_decos;
|
||||
a_decos.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(0));
|
||||
std::vector<std::unique_ptr<ast::StructMemberDecoration>> b_decos;
|
||||
b_decos.push_back(std::make_unique<ast::StructMemberOffsetDecoration>(8));
|
||||
|
||||
std::vector<std::unique_ptr<ast::StructMember>> members;
|
||||
members.push_back(
|
||||
std::make_unique<ast::StructMember>("a", &f32, std::move(a_decos)));
|
||||
members.push_back(
|
||||
std::make_unique<ast::StructMember>("b", &f32, std::move(b_decos)));
|
||||
|
||||
auto s = std::make_unique<ast::Struct>(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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue