for(const AggregateMember &m: kvp.second.members)
{
+ string name;
+ if(m.declaration)
+ name = format("%s_%s", kvp.second.declaration->name, m.declaration->name);
+ else
+ name = format("%s_%d", kvp.second.declaration->name, m.index);
+
VariableDeclaration *var = new VariableDeclaration;
var->source = kvp.first->source;
var->line = kvp.first->line;
- var->name = get_unused_variable_name(*kvp.second.decl_scope, format("%s_%s", kvp.second.declaration->name, m.declaration->name));
- var->type = m.declaration->type;
+ var->name = get_unused_variable_name(*kvp.second.decl_scope, name);
+ /* XXX This is kind of brittle and depends on the array declaration's
+ textual type not having brackets in it. */
+ var->type = (m.declaration ? m.declaration : kvp.second.declaration)->type;
if(m.initializer)
var->init_expression = m.initializer->clone();
{
r_aggregate_ref = 0;
expr->visit(*this);
- if(r_aggregate_ref && r_reference.chain_len==1 && (r_reference.chain[0]&0x3F)!=0x3F)
+ if(r_aggregate_ref && r_reference.chain_len==1)
{
- r_aggregate_ref->members[r_reference.chain[0]&0x3F].references.push_back(&expr);
- r_aggregate_ref->members_referenced = true;
+ if((r_reference.chain[0]&0x3F)!=0x3F)
+ {
+ r_aggregate_ref->members[r_reference.chain[0]&0x3F].references.push_back(&expr);
+ r_aggregate_ref->members_referenced = true;
+ }
+ else
+ /* If the accessed member is not known, mark the entire aggregate as
+ referenced. */
+ r_aggregate_ref->referenced = true;
}
r_aggregate_ref = 0;
}
r_reference.declaration = var.declaration;
else
{
+ /* If an aggregate variable is referenced as a whole, it should not be
+ dismantled. */
auto i = aggregates.find(var.declaration);
if(i!=aggregates.end())
i->second.referenced = true;
visit(binary.right);
}
- add_to_chain(r_reference, Assignment::Target::ARRAY, 0x3F);
+ unsigned index = 0x3F;
+ if(Literal *literal_subscript = dynamic_cast<Literal *>(binary.right.get()))
+ if(literal_subscript->value.check_type<int>())
+ index = literal_subscript->value.value<int>();
+ add_to_chain(r_reference, Assignment::Target::ARRAY, index);
+
+ if(r_reference.declaration && r_reference.chain_len==1)
+ {
+ auto i = aggregates.find(r_reference.declaration);
+ r_aggregate_ref = (i!=aggregates.end() ? &i->second : 0);
+ }
+ else
+ r_aggregate_ref = 0;
}
else
{
TraversingVisitor::visit(var);
if(var.interface.empty())
+ {
if(const StructDeclaration *strct = dynamic_cast<const StructDeclaration *>(var.type_declaration))
{
const FunctionCall *init_call = dynamic_cast<const FunctionCall *>(var.init_expression.get());
{
AggregateMember member;
member.declaration = mem_decl;
+ member.index = i;
if(init_call)
member.initializer = init_call->arguments[i];
aggre.members.push_back(member);
}
}
}
+ else if(const Literal *literal_size = dynamic_cast<const Literal *>(var.array_size.get()))
+ {
+ if(literal_size->value.check_type<int>())
+ {
+ Aggregate &aggre = aggregates[&var];
+ aggre.declaration = &var;
+ aggre.decl_scope = current_block;
+ aggre.insert_point = insert_point;
+
+ int size = literal_size->value.value<int>();
+ for(int i=0; i<size; ++i)
+ {
+ AggregateMember member;
+ member.index = i;
+ // Array initializers are not supported yet
+ aggre.members.push_back(member);
+ }
+ }
+ }
+ }
+}
+
+void AggregateDismantler::visit(FunctionDeclaration &func)
+{
+ func.body.visit(*this);
}
for(const auto &kvp: variables)
{
- if(kvp.second.output)
+ if(!kvp.second.referenced)
+ unused_nodes.insert(kvp.first);
+ else if(kvp.second.output)
{
/* The last visible assignments of output variables are used by the
next stage or the API. */
for(AssignmentInfo *a: kvp.second.assignments)
unused_nodes.erase(a->node);
}
-
- if(!kvp.second.output && !kvp.second.referenced)
- {
- // Don't remove variables from inside interface blocks.
- if(!kvp.second.interface_block)
- unused_nodes.insert(kvp.first);
- }
- else if(kvp.second.interface_block)
- // Interface blocks are kept if even one member is used.
- unused_nodes.erase(kvp.second.interface_block);
}
NodeRemover().apply(s, unused_nodes);
{
if(composite_reference)
r_reference.declaration = var.declaration;
- else
+ else if(var.declaration)
referenced(var.declaration, var);
}
{
if(composite_reference)
r_reference.declaration = iface.declaration;
- else
+ else if(iface.declaration)
referenced(iface.declaration, iface);
}
{
SetFlag clear_assignment(assignment_target, false);
SetFlag clear_composite(composite_reference, false);
+ SetForScope<Assignment::Target> clear_reference(r_reference, Assignment::Target());
binary.right->visit(*this);
}
return;
VariableInfo &var_info = variables[&var];
- var_info.interface_block = interface_block;
/* Mark variables as output if they're used by the next stage or the
graphics API. */
- if(interface_block)
- var_info.output = (interface_block->interface=="out" && (interface_block->linked_block || !interface_block->block_name.compare(0, 3, "gl_")));
- else
- var_info.output = (var.interface=="out" && (stage->type==Stage::FRAGMENT || var.linked_declaration || !var.name.compare(0, 3, "gl_")));
+ var_info.output = (var.interface=="out" && (stage->type==Stage::FRAGMENT || var.linked_declaration || !var.name.compare(0, 3, "gl_")));
+
+ // Linked outputs are automatically referenced.
+ if(var_info.output && var.linked_declaration)
+ var_info.referenced = true;
if(var.init_expression)
{