reader/spirv: Don't create disjoint AST nodes

This is a waste of memory, and now fires a TINT_ASSERT() in the resolver.

Add some more information to the resolver assertion message so that its easier to identify the node. This is especially useful when there's no source information available.

Fixed: tint:740
Bug: tint:469
Change-Id: I0cd4529db7b3906e64da6ed7290163509eb0c3f2
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/48689
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: David Neto <dneto@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2021-04-23 18:19:54 +00:00 committed by Commit Bot service account
parent ab215981fe
commit b205b872ae
3 changed files with 43 additions and 24 deletions

View File

@ -3450,17 +3450,12 @@ TypedExpression FunctionEmitter::MakeAccessChain(
return {}; return {};
} }
// A SPIR-V access chain is a single instruction with multiple indices
// walking down into composites. The Tint AST represents this as
// ever-deeper nested indexing expressions. Start off with an expression
// for the base, and then bury that inside nested indexing expressions.
TypedExpression current_expr(MakeOperand(inst, 0));
const auto constants = constant_mgr_->GetOperandConstants(&inst);
auto ptr_ty_id = def_use_mgr_->GetDef(base_id)->type_id(); auto ptr_ty_id = def_use_mgr_->GetDef(base_id)->type_id();
uint32_t first_index = 1; uint32_t first_index = 1;
const auto num_in_operands = inst.NumInOperands(); const auto num_in_operands = inst.NumInOperands();
TypedExpression current_expr;
// If the variable was originally gl_PerVertex, then in the AST we // If the variable was originally gl_PerVertex, then in the AST we
// have instead emitted a gl_Position variable. // have instead emitted a gl_Position variable.
// If computing the pointer to the Position builtin, then emit the // If computing the pointer to the Position builtin, then emit the
@ -3526,6 +3521,15 @@ TypedExpression FunctionEmitter::MakeAccessChain(
} }
} }
// A SPIR-V access chain is a single instruction with multiple indices
// walking down into composites. The Tint AST represents this as
// ever-deeper nested indexing expressions. Start off with an expression
// for the base, and then bury that inside nested indexing expressions.
if (!current_expr.expr) {
current_expr = MakeOperand(inst, 0);
}
const auto constants = constant_mgr_->GetOperandConstants(&inst);
const auto* ptr_type_inst = def_use_mgr_->GetDef(ptr_ty_id); const auto* ptr_type_inst = def_use_mgr_->GetDef(ptr_ty_id);
if (!ptr_type_inst || (ptr_type_inst->opcode() != SpvOpTypePointer)) { if (!ptr_type_inst || (ptr_type_inst->opcode() != SpvOpTypePointer)) {
Fail() << "Access chain %" << inst.result_id() Fail() << "Access chain %" << inst.result_id()

View File

@ -845,15 +845,13 @@ sem::Type* ParserImpl::ConvertType(
const spvtools::opt::analysis::Struct* struct_ty) { const spvtools::opt::analysis::Struct* struct_ty) {
// Compute the struct decoration. // Compute the struct decoration.
auto struct_decorations = this->GetDecorationsFor(type_id); auto struct_decorations = this->GetDecorationsFor(type_id);
ast::DecorationList ast_struct_decorations; bool is_block_decorated = false;
if (struct_decorations.size() == 1) { if (struct_decorations.size() == 1) {
const auto decoration = struct_decorations[0][0]; const auto decoration = struct_decorations[0][0];
if (decoration == SpvDecorationBlock) { if (decoration == SpvDecorationBlock) {
ast_struct_decorations.push_back( is_block_decorated = true;
create<ast::StructBlockDecoration>(Source{}));
} else if (decoration == SpvDecorationBufferBlock) { } else if (decoration == SpvDecorationBufferBlock) {
ast_struct_decorations.push_back( is_block_decorated = true;
create<ast::StructBlockDecoration>(Source{}));
remap_buffer_block_type_.insert(type_id); remap_buffer_block_type_.insert(type_id);
} else { } else {
Fail() << "struct with ID " << type_id Fail() << "struct with ID " << type_id
@ -869,7 +867,6 @@ sem::Type* ParserImpl::ConvertType(
ast::StructMemberList ast_members; ast::StructMemberList ast_members;
const auto members = struct_ty->element_types(); const auto members = struct_ty->element_types();
unsigned num_non_writable_members = 0; unsigned num_non_writable_members = 0;
bool is_per_vertex_struct = false;
for (uint32_t member_index = 0; member_index < members.size(); for (uint32_t member_index = 0; member_index < members.size();
++member_index) { ++member_index) {
const auto member_type_id = type_mgr_->GetId(members[member_index]); const auto member_type_id = type_mgr_->GetId(members[member_index]);
@ -878,8 +875,10 @@ sem::Type* ParserImpl::ConvertType(
// Already emitted diagnostics. // Already emitted diagnostics.
return nullptr; return nullptr;
} }
ast::DecorationList ast_member_decorations;
bool is_non_writable = false; // Scan member for built-in decorations. Some vertex built-ins are handled
// specially, and should not generate a structure member.
bool create_ast_member = true;
for (auto& decoration : GetDecorationsForMember(type_id, member_index)) { for (auto& decoration : GetDecorationsForMember(type_id, member_index)) {
if (decoration.empty()) { if (decoration.empty()) {
Fail() << "malformed SPIR-V decoration: it's empty"; Fail() << "malformed SPIR-V decoration: it's empty";
@ -892,23 +891,31 @@ sem::Type* ParserImpl::ConvertType(
builtin_position_.struct_type_id = type_id; builtin_position_.struct_type_id = type_id;
builtin_position_.position_member_index = member_index; builtin_position_.position_member_index = member_index;
builtin_position_.position_member_type_id = member_type_id; builtin_position_.position_member_type_id = member_type_id;
// Don't map the struct type. But this is not an error either. create_ast_member = false; // Not part of the WGSL structure.
is_per_vertex_struct = true;
break; break;
case SpvBuiltInPointSize: // not supported in WGSL, but ignore case SpvBuiltInPointSize: // not supported in WGSL, but ignore
builtin_position_.pointsize_member_index = member_index; builtin_position_.pointsize_member_index = member_index;
is_per_vertex_struct = true; create_ast_member = false; // Not part of the WGSL structure.
break; break;
case SpvBuiltInClipDistance: // not supported in WGSL case SpvBuiltInClipDistance: // not supported in WGSL
case SpvBuiltInCullDistance: // not supported in WGSL case SpvBuiltInCullDistance: // not supported in WGSL
// Silently ignore, so we can detect Position and PointSize create_ast_member = false; // Not part of the WGSL structure.
is_per_vertex_struct = true;
break; break;
default: default:
Fail() << "unrecognized builtin " << decoration[1]; Fail() << "unrecognized builtin " << decoration[1];
return nullptr; return nullptr;
} }
} else if (decoration[0] == SpvDecorationNonWritable) { }
}
if (!create_ast_member) {
// This member is decorated as a built-in, and is handled specially.
continue;
}
bool is_non_writable = false;
ast::DecorationList ast_member_decorations;
for (auto& decoration : GetDecorationsForMember(type_id, member_index)) {
if (decoration[0] == SpvDecorationNonWritable) {
// WGSL doesn't represent individual members as non-writable. Instead, // WGSL doesn't represent individual members as non-writable. Instead,
// apply the ReadOnly access control to the containing struct if all // apply the ReadOnly access control to the containing struct if all
// the members are non-writable. // the members are non-writable.
@ -924,6 +931,7 @@ sem::Type* ParserImpl::ConvertType(
} }
} }
} }
if (is_non_writable) { if (is_non_writable) {
// Count a member as non-writable only once, no matter how many // Count a member as non-writable only once, no matter how many
// NonWritable decorations are applied to it. // NonWritable decorations are applied to it.
@ -935,8 +943,9 @@ sem::Type* ParserImpl::ConvertType(
std::move(ast_member_decorations)); std::move(ast_member_decorations));
ast_members.push_back(ast_struct_member); ast_members.push_back(ast_struct_member);
} }
if (is_per_vertex_struct) {
// We're replacing it by the Position builtin alone. if (ast_members.empty()) {
// All members were likely built-ins. Don't generate an empty AST structure.
return nullptr; return nullptr;
} }
@ -946,6 +955,11 @@ sem::Type* ParserImpl::ConvertType(
// Now make the struct. // Now make the struct.
auto sym = builder_.Symbols().Register(name); auto sym = builder_.Symbols().Register(name);
ast::DecorationList ast_struct_decorations;
if (is_block_decorated) {
ast_struct_decorations.emplace_back(
create<ast::StructBlockDecoration>(Source{}));
}
auto* ast_struct = create<ast::Struct>(Source{}, sym, std::move(ast_members), auto* ast_struct = create<ast::Struct>(Source{}, sym, std::move(ast_members),
std::move(ast_struct_decorations)); std::move(ast_struct_decorations));
auto* result = builder_.create<sem::StructType>(ast_struct); auto* result = builder_.create<sem::StructType>(ast_struct);

View File

@ -272,7 +272,8 @@ bool Resolver::ResolveInternal() {
} }
TINT_ICE(diagnostics_) << "AST node '" << node->TypeInfo().name TINT_ICE(diagnostics_) << "AST node '" << node->TypeInfo().name
<< "' was not reached by the resolver\n" << "' was not reached by the resolver\n"
<< "At: " << node->source(); << "At: " << node->source() << "\n"
<< "Content: " << builder_->str(node);
} }
} }