[spir-reader] Emit alias types (named types)

Bug: tint:3
Change-Id: I4882160d9fe533d956f29ca15e65bf99eb80f5df
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/18360
Reviewed-by: dan sinclair <dsinclair@google.com>
This commit is contained in:
David Neto 2020-03-31 20:02:36 +00:00
parent 4493d13d49
commit a7640d6d4c
6 changed files with 260 additions and 51 deletions

View File

@ -327,6 +327,7 @@ if(${TINT_BUILD_SPV_READER})
reader/spirv/parser_impl_entry_point_test.cc reader/spirv/parser_impl_entry_point_test.cc
reader/spirv/parser_impl_get_decorations_test.cc reader/spirv/parser_impl_get_decorations_test.cc
reader/spirv/parser_impl_import_test.cc reader/spirv/parser_impl_import_test.cc
reader/spirv/parser_impl_named_types_test.cc
reader/spirv/parser_impl_user_name_test.cc reader/spirv/parser_impl_user_name_test.cc
reader/spirv/parser_impl_test.cc reader/spirv/parser_impl_test.cc
reader/spirv/parser_test.cc reader/spirv/parser_test.cc

View File

@ -32,6 +32,7 @@
#include "src/ast/struct_member.h" #include "src/ast/struct_member.h"
#include "src/ast/struct_member_decoration.h" #include "src/ast/struct_member_decoration.h"
#include "src/ast/struct_member_offset_decoration.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/array_type.h"
#include "src/ast/type/bool_type.h" #include "src/ast/type/bool_type.h"
#include "src/ast/type/f32_type.h" #include "src/ast/type/f32_type.h"
@ -77,7 +78,6 @@ ParserImpl::ParserImpl(Context* ctx, const std::vector<uint32_t>& spv_binary)
// For binary validation errors, we only have the instruction // For binary validation errors, we only have the instruction
// number. It's not text, so there is no column number. // number. It's not text, so there is no column number.
this->Fail() << "line:" << position.index << ": " << message; this->Fail() << "line:" << position.index << ": " << message;
this->Fail() << "error: line " << position.index << ": " << message;
} }
}; };
} }
@ -85,23 +85,27 @@ ParserImpl::ParserImpl(Context* ctx, const std::vector<uint32_t>& spv_binary)
ParserImpl::~ParserImpl() = default; ParserImpl::~ParserImpl() = default;
bool ParserImpl::Parse() { bool ParserImpl::Parse() {
// Set up use of SPIRV-Tools utilities.
spvtools::SpirvTools spv_tools(kTargetEnv);
// Error messages from SPIRV-Tools are forwarded as failures, including
// setting |success_| to false.
spv_tools.SetMessageConsumer(message_consumer_);
if (!success_) { if (!success_) {
return false; return false;
} }
// Set up use of SPIRV-Tools utilities. // Only consider valid modules. On failure, the message consumer
spvtools::SpirvTools spv_tools(kTargetEnv); // will set the error status.
if (!spv_tools.Validate(spv_binary_)) {
// Error messages from SPIRV-Tools are forwarded as failures. return false;
spv_tools.SetMessageConsumer(message_consumer_);
// Only consider valid modules.
if (success_) {
success_ = spv_tools.Validate(spv_binary_);
} }
if (!BuildInternalModule()) {
if (success_) { return false;
success_ = BuildInternalModule(); }
if (!ParseInternalModule()) {
return false;
} }
return success_; return success_;
@ -160,6 +164,11 @@ ast::type::Type* ParserImpl::ConvertType(uint32_t type_id) {
return save(ConvertType(spirv_type->AsArray())); return save(ConvertType(spirv_type->AsArray()));
case spvtools::opt::analysis::Type::kStruct: case spvtools::opt::analysis::Type::kStruct:
return save(ConvertType(spirv_type->AsStruct())); return save(ConvertType(spirv_type->AsStruct()));
case spvtools::opt::analysis::Type::kFunction:
case spvtools::opt::analysis::Type::kPointer:
// For now, just return null without erroring out.
// TODO(dneto)
return nullptr;
default: default:
break; break;
} }
@ -228,6 +237,9 @@ ParserImpl::ConvertMemberDecoration(const Decoration& decoration) {
} }
bool ParserImpl::BuildInternalModule() { bool ParserImpl::BuildInternalModule() {
if (!success_) {
return false;
}
tools_.SetMessageConsumer(message_consumer_); tools_.SetMessageConsumer(message_consumer_);
const spv_context& context = tools_context_.CContext(); const spv_context& context = tools_context_.CContext();
@ -243,7 +255,7 @@ bool ParserImpl::BuildInternalModule() {
type_mgr_ = ir_context_->get_type_mgr(); type_mgr_ = ir_context_->get_type_mgr();
deco_mgr_ = ir_context_->get_decoration_mgr(); deco_mgr_ = ir_context_->get_decoration_mgr();
return true; return success_;
} }
void ParserImpl::ResetInternalModule() { void ParserImpl::ResetInternalModule() {
@ -265,12 +277,18 @@ bool ParserImpl::ParseInternalModule() {
if (!RegisterExtendedInstructionImports()) { if (!RegisterExtendedInstructionImports()) {
return false; return false;
} }
if (!RegisterUserNames()) { if (!RegisterUserAndStructMemberNames()) {
return false; return false;
} }
if (!EmitEntryPoints()) { if (!EmitEntryPoints()) {
return false; return false;
} }
if (!RegisterTypes()) {
return false;
}
if (!EmitAliasTypes()) {
return false;
}
// TODO(dneto): fill in the rest // TODO(dneto): fill in the rest
return true; return true;
} }
@ -297,7 +315,10 @@ bool ParserImpl::RegisterExtendedInstructionImports() {
return true; return true;
} }
bool ParserImpl::RegisterUserNames() { bool ParserImpl::RegisterUserAndStructMemberNames() {
if (!success_) {
return false;
}
// Register entry point names. An entry point name is the point of contact // Register entry point names. An entry point name is the point of contact
// between the API and the shader. It has the highest priority for // between the API and the shader. It has the highest priority for
// preservation, so register it first. // preservation, so register it first.
@ -490,14 +511,77 @@ ast::type::Type* ParserImpl::ConvertType(
// Now make the struct. // Now make the struct.
auto ast_struct = std::make_unique<ast::Struct>(ast_struct_decoration, auto ast_struct = std::make_unique<ast::Struct>(ast_struct_decoration,
std::move(ast_members)); std::move(ast_members));
// The struct type will be assigned a name during EmitAliasTypes.
auto ast_struct_type = auto ast_struct_type =
std::make_unique<ast::type::StructType>(std::move(ast_struct)); std::make_unique<ast::type::StructType>(std::move(ast_struct));
// The struct might not have a name yet. Suggest one. // Set the struct name before registering it.
namer_.SuggestSanitizedName(type_id, "S"); namer_.SuggestSanitizedName(type_id, "S");
ast_struct_type->set_name(namer_.GetName(type_id)); ast_struct_type->set_name(namer_.GetName(type_id));
return ctx_.type_mgr().Get(std::move(ast_struct_type)); return ctx_.type_mgr().Get(std::move(ast_struct_type));
} }
bool ParserImpl::RegisterTypes() {
if (!success_) {
return false;
}
for (auto& type_or_const : module_->types_values()) {
const auto* type = type_mgr_->GetType(type_or_const.result_id());
if (type == nullptr) {
continue;
}
ConvertType(type_or_const.result_id());
}
return success_;
}
bool ParserImpl::EmitAliasTypes() {
if (!success_) {
return false;
}
// The algorithm here emits type definitions in the order presented in
// the SPIR-V module. This is valid because:
//
// - There are no back-references. OpTypeForwarddPointer is not supported
// by the WebGPU shader programming model.
// - Arrays are always sized by an OpConstant of scalar integral type.
// WGSL currently doesn't have specialization constants.
// crbug.com/32 tracks implementation in case they are added.
for (auto& type_or_const : module_->types_values()) {
const auto type_id = type_or_const.result_id();
// We only care about struct, arrays, and runtime arrays.
switch (type_or_const.opcode()) {
case SpvOpTypeStruct:
// The struct already got a name when the type was first registered.
break;
case SpvOpTypeRuntimeArray:
// Runtime arrays are always decorated with ArrayStride so always get a
// type alias.
namer_.SuggestSanitizedName(type_id, "RTArr");
break;
case SpvOpTypeArray:
// Only make a type aliase for arrays with decorations.
if (GetDecorationsFor(type_id).empty()) {
continue;
}
namer_.SuggestSanitizedName(type_id, "Arr");
break;
default:
// Ignore constants, and any other types.
continue;
}
auto* ast_underlying_type = id_to_type_[type_id];
if (ast_underlying_type == nullptr) {
Fail() << "internal error: no type registered for SPIR-V ID: " << type_id;
return false;
}
const auto name = namer_.GetName(type_id);
auto* ast_type = ctx_.type_mgr().Get(
std::make_unique<ast::type::AliasType>(name, ast_underlying_type));
ast_module_.AddAliasType(ast_type->AsAlias());
}
return success_;
}
} // namespace spirv } // namespace spirv
} // namespace reader } // namespace reader
} // namespace tint } // namespace tint

View File

@ -126,33 +126,54 @@ class ParserImpl : Reader {
std::unique_ptr<ast::StructMemberDecoration> ConvertMemberDecoration( std::unique_ptr<ast::StructMemberDecoration> ConvertMemberDecoration(
const Decoration& decoration); const Decoration& decoration);
private:
/// Builds the internal representation of the SPIR-V module. /// Builds the internal representation of the SPIR-V module.
/// Assumes the module is somewhat well-formed. Normally you /// Assumes the module is somewhat well-formed. Normally you
/// would want to validate the SPIR-V module before attempting /// would want to validate the SPIR-V module before attempting
/// to build this internal representation. /// to build this internal representation.
/// @returns true if successful. /// This is a no-op if the parser has already failed.
/// @returns true if the parser is still successful.
bool BuildInternalModule(); bool BuildInternalModule();
/// Walks the internal representation of the module to populate /// Walks the internal representation of the module to populate
/// the AST form of the module. /// the AST form of the module.
/// @returns true on success /// This is a no-op if the parser has already failed.
/// @returns true if the parser is still successful.
bool ParseInternalModule(); bool ParseInternalModule();
/// Destroys the internal representation of the SPIR-V module. /// Destroys the internal representation of the SPIR-V module.
void ResetInternalModule(); void ResetInternalModule();
/// Registers extended instruction imports. Only "GLSL.std.450" is supported. /// Registers extended instruction imports. Only "GLSL.std.450" is supported.
/// This is a no-op if the parser has already failed.
/// @returns true if parser is still successful.
bool RegisterExtendedInstructionImports(); bool RegisterExtendedInstructionImports();
/// Registers user names for SPIR-V objects, from OpName, and OpMemberName. /// Registers user names for SPIR-V objects, from OpName, and OpMemberName.
/// Also synthesizes struct field names. Ensures uniqueness for names for /// Also synthesizes struct field names. Ensures uniqueness for names for
/// SPIR-V IDs, and uniqueness of names of fields within any single struct. /// SPIR-V IDs, and uniqueness of names of fields within any single struct.
bool RegisterUserNames(); /// This is a no-op if the parser has already failed.
/// @returns true if parser is still successful.
bool RegisterUserAndStructMemberNames();
/// Emit entry point AST nodes. /// Emit entry point AST nodes.
/// This is a no-op if the parser has already failed.
/// @returns true if parser is still successful.
bool EmitEntryPoints(); bool EmitEntryPoints();
/// Register Tint AST types for SPIR-V types.
/// This is a no-op if the parser has already failed.
/// @returns true if parser is still successful.
bool RegisterTypes();
/// Emit type alias declarations for types requiring user-specified names:
/// - struct types
/// - decorated arrays and runtime arrays
/// TODO(dneto): I expect images and samplers to require names as well.
/// This is a no-op if the parser has already failed.
/// @returns true if parser is still successful.
bool EmitAliasTypes();
private:
/// Converts a specific SPIR-V type to a Tint type. Integer case /// Converts a specific SPIR-V type to a Tint type. Integer case
ast::type::Type* ConvertType(const spvtools::opt::analysis::Integer* int_ty); ast::type::Type* ConvertType(const spvtools::opt::analysis::Integer* int_ty);
/// Converts a specific SPIR-V type to a Tint type. Float case /// Converts a specific SPIR-V type to a Tint type. Float case

View File

@ -53,7 +53,7 @@ TEST_F(SpvParserTest, ConvertType_RequiresInternalRepresntation) {
TEST_F(SpvParserTest, ConvertType_NotAnId) { TEST_F(SpvParserTest, ConvertType_NotAnId) {
auto p = parser(test::Assemble("%1 = OpExtInstImport \"GLSL.std.450\"")); auto p = parser(test::Assemble("%1 = OpExtInstImport \"GLSL.std.450\""));
EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error(); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(10); auto* type = p->ConvertType(10);
EXPECT_EQ(type, nullptr); EXPECT_EQ(type, nullptr);
@ -63,7 +63,7 @@ TEST_F(SpvParserTest, ConvertType_NotAnId) {
TEST_F(SpvParserTest, ConvertType_IdExistsButIsNotAType) { TEST_F(SpvParserTest, ConvertType_IdExistsButIsNotAType) {
auto p = parser(test::Assemble("%1 = OpExtInstImport \"GLSL.std.450\"")); auto p = parser(test::Assemble("%1 = OpExtInstImport \"GLSL.std.450\""));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(1); auto* type = p->ConvertType(1);
EXPECT_EQ(nullptr, type); EXPECT_EQ(nullptr, type);
@ -73,7 +73,7 @@ TEST_F(SpvParserTest, ConvertType_IdExistsButIsNotAType) {
TEST_F(SpvParserTest, ConvertType_UnhandledType) { TEST_F(SpvParserTest, ConvertType_UnhandledType) {
// Pipes are an OpenCL type. Tint doesn't support them. // Pipes are an OpenCL type. Tint doesn't support them.
auto p = parser(test::Assemble("%70 = OpTypePipe WriteOnly")); auto p = parser(test::Assemble("%70 = OpTypePipe WriteOnly"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(70); auto* type = p->ConvertType(70);
EXPECT_EQ(nullptr, type); EXPECT_EQ(nullptr, type);
@ -82,7 +82,7 @@ TEST_F(SpvParserTest, ConvertType_UnhandledType) {
TEST_F(SpvParserTest, ConvertType_Void) { TEST_F(SpvParserTest, ConvertType_Void) {
auto p = parser(test::Assemble("%1 = OpTypeVoid")); auto p = parser(test::Assemble("%1 = OpTypeVoid"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(1); auto* type = p->ConvertType(1);
EXPECT_TRUE(type->IsVoid()); EXPECT_TRUE(type->IsVoid());
@ -91,7 +91,7 @@ TEST_F(SpvParserTest, ConvertType_Void) {
TEST_F(SpvParserTest, ConvertType_Bool) { TEST_F(SpvParserTest, ConvertType_Bool) {
auto p = parser(test::Assemble("%100 = OpTypeBool")); auto p = parser(test::Assemble("%100 = OpTypeBool"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(100); auto* type = p->ConvertType(100);
EXPECT_TRUE(type->IsBool()); EXPECT_TRUE(type->IsBool());
@ -100,7 +100,7 @@ TEST_F(SpvParserTest, ConvertType_Bool) {
TEST_F(SpvParserTest, ConvertType_I32) { TEST_F(SpvParserTest, ConvertType_I32) {
auto p = parser(test::Assemble("%2 = OpTypeInt 32 1")); auto p = parser(test::Assemble("%2 = OpTypeInt 32 1"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(2); auto* type = p->ConvertType(2);
EXPECT_TRUE(type->IsI32()); EXPECT_TRUE(type->IsI32());
@ -109,7 +109,7 @@ TEST_F(SpvParserTest, ConvertType_I32) {
TEST_F(SpvParserTest, ConvertType_U32) { TEST_F(SpvParserTest, ConvertType_U32) {
auto p = parser(test::Assemble("%3 = OpTypeInt 32 0")); auto p = parser(test::Assemble("%3 = OpTypeInt 32 0"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(3); auto* type = p->ConvertType(3);
EXPECT_TRUE(type->IsU32()); EXPECT_TRUE(type->IsU32());
@ -118,7 +118,7 @@ TEST_F(SpvParserTest, ConvertType_U32) {
TEST_F(SpvParserTest, ConvertType_F32) { TEST_F(SpvParserTest, ConvertType_F32) {
auto p = parser(test::Assemble("%4 = OpTypeFloat 32")); auto p = parser(test::Assemble("%4 = OpTypeFloat 32"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(4); auto* type = p->ConvertType(4);
EXPECT_TRUE(type->IsF32()); EXPECT_TRUE(type->IsF32());
@ -127,7 +127,7 @@ TEST_F(SpvParserTest, ConvertType_F32) {
TEST_F(SpvParserTest, ConvertType_BadIntWidth) { TEST_F(SpvParserTest, ConvertType_BadIntWidth) {
auto p = parser(test::Assemble("%5 = OpTypeInt 17 1")); auto p = parser(test::Assemble("%5 = OpTypeInt 17 1"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(5); auto* type = p->ConvertType(5);
EXPECT_EQ(type, nullptr); EXPECT_EQ(type, nullptr);
@ -136,7 +136,7 @@ TEST_F(SpvParserTest, ConvertType_BadIntWidth) {
TEST_F(SpvParserTest, ConvertType_BadFloatWidth) { TEST_F(SpvParserTest, ConvertType_BadFloatWidth) {
auto p = parser(test::Assemble("%6 = OpTypeFloat 19")); auto p = parser(test::Assemble("%6 = OpTypeFloat 19"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(6); auto* type = p->ConvertType(6);
EXPECT_EQ(type, nullptr); EXPECT_EQ(type, nullptr);
@ -148,7 +148,7 @@ TEST_F(SpvParserTest, DISABLED_ConvertType_InvalidVectorElement) {
%5 = OpTypePipe ReadOnly %5 = OpTypePipe ReadOnly
%20 = OpTypeVector %5 2 %20 = OpTypeVector %5 2
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(20); auto* type = p->ConvertType(20);
EXPECT_EQ(type, nullptr); EXPECT_EQ(type, nullptr);
@ -162,7 +162,7 @@ TEST_F(SpvParserTest, ConvertType_VecOverF32) {
%30 = OpTypeVector %float 3 %30 = OpTypeVector %float 3
%40 = OpTypeVector %float 4 %40 = OpTypeVector %float 4
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* v2xf32 = p->ConvertType(20); auto* v2xf32 = p->ConvertType(20);
EXPECT_TRUE(v2xf32->IsVector()); EXPECT_TRUE(v2xf32->IsVector());
@ -189,7 +189,7 @@ TEST_F(SpvParserTest, ConvertType_VecOverI32) {
%30 = OpTypeVector %int 3 %30 = OpTypeVector %int 3
%40 = OpTypeVector %int 4 %40 = OpTypeVector %int 4
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* v2xi32 = p->ConvertType(20); auto* v2xi32 = p->ConvertType(20);
EXPECT_TRUE(v2xi32->IsVector()); EXPECT_TRUE(v2xi32->IsVector());
@ -216,7 +216,7 @@ TEST_F(SpvParserTest, ConvertType_VecOverU32) {
%30 = OpTypeVector %uint 3 %30 = OpTypeVector %uint 3
%40 = OpTypeVector %uint 4 %40 = OpTypeVector %uint 4
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* v2xu32 = p->ConvertType(20); auto* v2xu32 = p->ConvertType(20);
EXPECT_TRUE(v2xu32->IsVector()); EXPECT_TRUE(v2xu32->IsVector());
@ -242,7 +242,7 @@ TEST_F(SpvParserTest, DISABLED_ConvertType_InvalidMatrixElement) {
%10 = OpTypeVector %5 2 %10 = OpTypeVector %5 2
%20 = OpTypeMatrix %10 2 %20 = OpTypeMatrix %10 2
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(20); auto* type = p->ConvertType(20);
EXPECT_EQ(type, nullptr); EXPECT_EQ(type, nullptr);
@ -268,7 +268,7 @@ TEST_F(SpvParserTest, ConvertType_MatrixOverF32) {
%43 = OpTypeMatrix %v4 3 %43 = OpTypeMatrix %v4 3
%44 = OpTypeMatrix %v4 4 %44 = OpTypeMatrix %v4 4
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* m22 = p->ConvertType(22); auto* m22 = p->ConvertType(22);
EXPECT_TRUE(m22->IsMatrix()); EXPECT_TRUE(m22->IsMatrix());
@ -332,7 +332,7 @@ TEST_F(SpvParserTest, ConvertType_RuntimeArray) {
%uint = OpTypeInt 32 0 %uint = OpTypeInt 32 0
%10 = OpTypeRuntimeArray %uint %10 = OpTypeRuntimeArray %uint
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(10); auto* type = p->ConvertType(10);
ASSERT_NE(type, nullptr); ASSERT_NE(type, nullptr);
@ -353,7 +353,7 @@ TEST_F(SpvParserTest, ConvertType_Array) {
%uint_42 = OpConstant %uint 42 %uint_42 = OpConstant %uint 42
%10 = OpTypeArray %uint %uint_42 %10 = OpTypeArray %uint %uint_42
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(10); auto* type = p->ConvertType(10);
ASSERT_NE(type, nullptr); ASSERT_NE(type, nullptr);
@ -375,7 +375,7 @@ TEST_F(SpvParserTest, ConvertType_ArrayBadLengthIsSpecConstantValue) {
%uint_42 = OpSpecConstant %uint 42 %uint_42 = OpSpecConstant %uint 42
%10 = OpTypeArray %uint %uint_42 %10 = OpTypeArray %uint %uint_42
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(10); auto* type = p->ConvertType(10);
ASSERT_EQ(type, nullptr); ASSERT_EQ(type, nullptr);
@ -390,7 +390,7 @@ TEST_F(SpvParserTest, ConvertType_ArrayBadLengthIsSpecConstantExpr) {
%sum = OpSpecConstantOp %uint IAdd %uint_42 %uint_42 %sum = OpSpecConstantOp %uint IAdd %uint_42 %uint_42
%10 = OpTypeArray %uint %sum %10 = OpTypeArray %uint %sum
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(10); auto* type = p->ConvertType(10);
ASSERT_EQ(type, nullptr); ASSERT_EQ(type, nullptr);
@ -408,7 +408,7 @@ TEST_F(SpvParserTest, ConvertType_ArrayBadTooBig) {
%uint64_big = OpConstant %uint64 5000000000 %uint64_big = OpConstant %uint64 5000000000
%10 = OpTypeArray %uint64 %uint64_big %10 = OpTypeArray %uint64 %uint64_big
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
auto* type = p->ConvertType(10); auto* type = p->ConvertType(10);
ASSERT_EQ(type, nullptr); ASSERT_EQ(type, nullptr);
@ -423,10 +423,11 @@ TEST_F(SpvParserTest, ConvertType_StructTwoMembers) {
%float = OpTypeFloat 32 %float = OpTypeFloat 32
%10 = OpTypeStruct %uint %float %10 = OpTypeStruct %uint %float
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
EXPECT_TRUE(p->RegisterUserAndStructMemberNames());
auto* type = p->ConvertType(10); auto* type = p->ConvertType(10);
ASSERT_NE(type, nullptr) << p->error(); ASSERT_NE(type, nullptr);
EXPECT_TRUE(type->IsStruct()); EXPECT_TRUE(type->IsStruct());
std::stringstream ss; std::stringstream ss;
type->AsStruct()->impl()->to_str(ss, 0); type->AsStruct()->impl()->to_str(ss, 0);
@ -443,7 +444,8 @@ TEST_F(SpvParserTest, ConvertType_StructWithBlockDecoration) {
%uint = OpTypeInt 32 0 %uint = OpTypeInt 32 0
%10 = OpTypeStruct %uint %10 = OpTypeStruct %uint
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
EXPECT_TRUE(p->RegisterUserAndStructMemberNames());
auto* type = p->ConvertType(10); auto* type = p->ConvertType(10);
ASSERT_NE(type, nullptr); ASSERT_NE(type, nullptr);
@ -466,10 +468,11 @@ TEST_F(SpvParserTest, ConvertType_StructWithMemberDecorations) {
%mat = OpTypeMatrix %vec 2 %mat = OpTypeMatrix %vec 2
%10 = OpTypeStruct %float %vec %mat %10 = OpTypeStruct %float %vec %mat
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildInternalModule());
EXPECT_TRUE(p->RegisterUserAndStructMemberNames());
auto* type = p->ConvertType(10); auto* type = p->ConvertType(10);
ASSERT_NE(type, nullptr) << p->error(); ASSERT_NE(type, nullptr);
EXPECT_TRUE(type->IsStruct()); EXPECT_TRUE(type->IsStruct());
std::stringstream ss; std::stringstream ss;
type->AsStruct()->impl()->to_str(ss, 0); type->AsStruct()->impl()->to_str(ss, 0);

View File

@ -97,7 +97,8 @@ TEST_F(SpvParserTest, GetDecorationsForMember_MemberWithoutDecoration) {
EXPECT_TRUE(p->error().empty()); EXPECT_TRUE(p->error().empty());
} }
TEST_F(SpvParserTest, GetDecorationsForMember_OneDecoration) { // TODO(dneto): Enable when ArrayStride is handled
TEST_F(SpvParserTest, DISABLED_GetDecorationsForMember_OneDecoration) {
auto p = parser(test::Assemble(R"( auto p = parser(test::Assemble(R"(
OpMemberDecorate %10 1 ArrayStride 12 OpMemberDecorate %10 1 ArrayStride 12
%uint = OpTypeInt 32 0 %uint = OpTypeInt 32 0
@ -105,14 +106,17 @@ TEST_F(SpvParserTest, GetDecorationsForMember_OneDecoration) {
%arr = OpTypeArray %uint %uint_2 %arr = OpTypeArray %uint %uint_2
%10 = OpTypeStruct %uint %arr %10 = OpTypeStruct %uint %arr
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
auto decorations = p->GetDecorationsForMember(10, 1); auto decorations = p->GetDecorationsForMember(10, 1);
EXPECT_THAT(decorations, EXPECT_THAT(decorations,
UnorderedElementsAre(Decoration{SpvDecorationArrayStride, 12})); UnorderedElementsAre(Decoration{SpvDecorationArrayStride, 12}));
EXPECT_TRUE(p->error().empty()); EXPECT_TRUE(p->error().empty());
} }
TEST_F(SpvParserTest, GetDecorationsForMember_MultiDecoration) { // TODO(dneto): Enable when ArrayStride, MatrixStride, ColMajor are handled
// crbug.com/tint/30 for ArrayStride
// crbug.com/tint/31 for matrix layout
TEST_F(SpvParserTest, DISABLED_GetDecorationsForMember_MultiDecoration) {
auto p = parser(test::Assemble(R"( auto p = parser(test::Assemble(R"(
OpMemberDecorate %50 1 RelaxedPrecision OpMemberDecorate %50 1 RelaxedPrecision
OpMemberDecorate %50 2 ArrayStride 16 OpMemberDecorate %50 2 ArrayStride 16
@ -126,7 +130,7 @@ TEST_F(SpvParserTest, GetDecorationsForMember_MultiDecoration) {
%arr = OpTypeArray %mat %uint_2 %arr = OpTypeArray %mat %uint_2
%50 = OpTypeStruct %uint %float %arr %50 = OpTypeStruct %uint %float %arr
)")); )"));
EXPECT_TRUE(p->BuildAndParseInternalModule()); EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
EXPECT_TRUE(p->GetDecorationsForMember(50, 0).empty()); EXPECT_TRUE(p->GetDecorationsForMember(50, 0).empty());
EXPECT_THAT(p->GetDecorationsForMember(50, 1), EXPECT_THAT(p->GetDecorationsForMember(50, 1),

View File

@ -0,0 +1,96 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <cstdint>
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "src/ast/struct.h"
#include "src/ast/type/array_type.h"
#include "src/ast/type/matrix_type.h"
#include "src/ast/type/struct_type.h"
#include "src/ast/type/vector_type.h"
#include "src/reader/spirv/parser_impl.h"
#include "src/reader/spirv/parser_impl_test_helper.h"
#include "src/reader/spirv/spirv_tools_helpers_test.h"
#include "src/type_manager.h"
namespace tint {
namespace reader {
namespace spirv {
namespace {
using ::testing::HasSubstr;
TEST_F(SpvParserTest, NamedTypes_AnonStruct) {
auto p = parser(test::Assemble(R"(
%uint = OpTypeInt 32 0
%s = OpTypeStruct %uint %uint
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_THAT(p->module().to_str(), HasSubstr("S -> __struct_"));
}
TEST_F(SpvParserTest, NamedTypes_NamedStruct) {
auto p = parser(test::Assemble(R"(
OpName %s "mystruct"
%uint = OpTypeInt 32 0
%s = OpTypeStruct %uint %uint
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_THAT(p->module().to_str(), HasSubstr("mystruct -> __struct_"));
}
// TODO(dneto): Enable this when array types can have ArrayStride
TEST_F(SpvParserTest, DISABLED_NamedTypes_AnonArrayWithDecoration) {
auto p = parser(test::Assemble(R"(
OpDecorate %arr ArrayStride 16
%uint = OpTypeInt 32 0
%uint_3 = OpConstant %uint 3
%arr = OpTypeArray %uint %uint_3
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_THAT(p->module().to_str(), HasSubstr("Arr -> __array__u32"));
}
// TODO(dneto): Should we make an alias for an un-decoratrd array with
// an OpName?
TEST_F(SpvParserTest, NamedTypes_AnonRTArray) {
auto p = parser(test::Assemble(R"(
%uint = OpTypeInt 32 0
%arr = OpTypeRuntimeArray %uint
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_THAT(p->module().to_str(), HasSubstr("RTArr -> __array__u32"));
}
TEST_F(SpvParserTest, NamedTypes_NamedRTArray) {
auto p = parser(test::Assemble(R"(
OpName %arr "myrtarr"
%uint = OpTypeInt 32 0
%arr = OpTypeRuntimeArray %uint
)"));
EXPECT_TRUE(p->BuildAndParseInternalModule());
EXPECT_THAT(p->module().to_str(), HasSubstr("myrtarr -> __array__u32"));
}
// TODO(dneto): Handle arrays sized by a spec constant.
// Blocked by crbug.com/tint/32
} // namespace
} // namespace spirv
} // namespace reader
} // namespace tint