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>
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index a6270c1..ea87c3d 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -3450,17 +3450,12 @@
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();
uint32_t first_index = 1;
const auto num_in_operands = inst.NumInOperands();
+ TypedExpression current_expr;
+
// If the variable was originally gl_PerVertex, then in the AST we
// have instead emitted a gl_Position variable.
// If computing the pointer to the Position builtin, then emit the
@@ -3526,6 +3521,15 @@
}
}
+ // 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);
if (!ptr_type_inst || (ptr_type_inst->opcode() != SpvOpTypePointer)) {
Fail() << "Access chain %" << inst.result_id()
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index 336e18b..cfcf986 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -845,15 +845,13 @@
const spvtools::opt::analysis::Struct* struct_ty) {
// Compute the struct decoration.
auto struct_decorations = this->GetDecorationsFor(type_id);
- ast::DecorationList ast_struct_decorations;
+ bool is_block_decorated = false;
if (struct_decorations.size() == 1) {
const auto decoration = struct_decorations[0][0];
if (decoration == SpvDecorationBlock) {
- ast_struct_decorations.push_back(
- create<ast::StructBlockDecoration>(Source{}));
+ is_block_decorated = true;
} else if (decoration == SpvDecorationBufferBlock) {
- ast_struct_decorations.push_back(
- create<ast::StructBlockDecoration>(Source{}));
+ is_block_decorated = true;
remap_buffer_block_type_.insert(type_id);
} else {
Fail() << "struct with ID " << type_id
@@ -869,7 +867,6 @@
ast::StructMemberList ast_members;
const auto members = struct_ty->element_types();
unsigned num_non_writable_members = 0;
- bool is_per_vertex_struct = false;
for (uint32_t member_index = 0; member_index < members.size();
++member_index) {
const auto member_type_id = type_mgr_->GetId(members[member_index]);
@@ -878,8 +875,10 @@
// Already emitted diagnostics.
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)) {
if (decoration.empty()) {
Fail() << "malformed SPIR-V decoration: it's empty";
@@ -892,23 +891,31 @@
builtin_position_.struct_type_id = type_id;
builtin_position_.position_member_index = member_index;
builtin_position_.position_member_type_id = member_type_id;
- // Don't map the struct type. But this is not an error either.
- is_per_vertex_struct = true;
+ create_ast_member = false; // Not part of the WGSL structure.
break;
case SpvBuiltInPointSize: // not supported in WGSL, but ignore
builtin_position_.pointsize_member_index = member_index;
- is_per_vertex_struct = true;
+ create_ast_member = false; // Not part of the WGSL structure.
break;
case SpvBuiltInClipDistance: // not supported in WGSL
case SpvBuiltInCullDistance: // not supported in WGSL
- // Silently ignore, so we can detect Position and PointSize
- is_per_vertex_struct = true;
+ create_ast_member = false; // Not part of the WGSL structure.
break;
default:
Fail() << "unrecognized builtin " << decoration[1];
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,
// apply the ReadOnly access control to the containing struct if all
// the members are non-writable.
@@ -924,6 +931,7 @@
}
}
}
+
if (is_non_writable) {
// Count a member as non-writable only once, no matter how many
// NonWritable decorations are applied to it.
@@ -935,8 +943,9 @@
std::move(ast_member_decorations));
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;
}
@@ -946,6 +955,11 @@
// Now make the struct.
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),
std::move(ast_struct_decorations));
auto* result = builder_.create<sem::StructType>(ast_struct);
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index 85501b0..ebb18c0 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -272,7 +272,8 @@
}
TINT_ICE(diagnostics_) << "AST node '" << node->TypeInfo().name
<< "' was not reached by the resolver\n"
- << "At: " << node->source();
+ << "At: " << node->source() << "\n"
+ << "Content: " << builder_->str(node);
}
}