[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:
dan sinclair 2020-03-24 21:40:10 +00:00 committed by dan sinclair
parent 6cd52e30ef
commit 69b9c1b8e0
5 changed files with 220 additions and 17 deletions

View File

@ -17,7 +17,7 @@
namespace tint {
namespace ast {
StructMemberOffsetDecoration::StructMemberOffsetDecoration(size_t offset)
StructMemberOffsetDecoration::StructMemberOffsetDecoration(uint32_t offset)
: offset_(offset) {}
StructMemberOffsetDecoration::~StructMemberOffsetDecoration() = default;

View File

@ -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

View File

@ -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

View File

@ -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_

View File

@ -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;