return r_any_inlined;
}
-void FunctionInliner::visit_and_inline(RefPtr<Expression> &ptr)
+void FunctionInliner::visit(RefPtr<Expression> &ptr)
{
r_inline_result = 0;
ptr->visit(*this);
ptr = r_inline_result;
r_any_inlined = true;
}
+ r_inline_result = 0;
}
void FunctionInliner::visit(Block &block)
}
}
-void FunctionInliner::visit(UnaryExpression &unary)
-{
- visit_and_inline(unary.expression);
- r_inline_result = 0;
-}
-
-void FunctionInliner::visit(BinaryExpression &binary)
-{
- visit_and_inline(binary.left);
- visit_and_inline(binary.right);
- r_inline_result = 0;
-}
-
-void FunctionInliner::visit(MemberAccess &memacc)
-{
- visit_and_inline(memacc.left);
- r_inline_result = 0;
-}
-
void FunctionInliner::visit(FunctionCall &call)
{
for(NodeArray<Expression>::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
- visit_and_inline(*i);
+ visit(*i);
FunctionDeclaration *def = call.declaration;
if(def)
inlined further. */
inlineable.erase(current_function);
}
- else
- r_inline_result = 0;
-}
-
-void FunctionInliner::visit(ExpressionStatement &expr)
-{
- visit_and_inline(expr.expression);
-}
-
-void FunctionInliner::visit(VariableDeclaration &var)
-{
- if(var.init_expression)
- visit_and_inline(var.init_expression);
- r_inline_result = 0;
}
void FunctionInliner::visit(FunctionDeclaration &func)
TraversingVisitor::visit(func);
}
-void FunctionInliner::visit(Conditional &cond)
-{
- visit_and_inline(cond.condition);
- cond.body.visit(*this);
-}
-
void FunctionInliner::visit(Iteration &iter)
{
/* Visit the initialization statement before entering the loop body so the
iter.body.visit(*this);
}
-void FunctionInliner::visit(Return &ret)
-{
- if(ret.expression)
- visit_and_inline(ret.expression);
-}
-
ExpressionInliner::ExpressionInfo::ExpressionInfo():
expression(0),
r_ref_info->inline_on_rhs = on_rhs;
}
}
+ r_ref_info = 0;
}
void ExpressionInliner::inline_expression(Expression &expr, RefPtr<Expression> &ptr, const Operator *outer_oper, const Operator *inner_oper, bool on_rhs)
{
TraversingVisitor::visit(block);
- for(map<VariableDeclaration *, ExpressionInfo>::iterator i=expressions.begin(); i!=expressions.end(); )
+ for(map<string, VariableDeclaration *>::iterator i=block.variables.begin(); i!=block.variables.end(); ++i)
{
- map<string, VariableDeclaration *>::iterator j = block.variables.find(i->first->name);
- if(j!=block.variables.end() && j->second==i->first)
+ map<Assignment::Target, ExpressionInfo>::iterator j = expressions.lower_bound(i->second);
+ for(; (j!=expressions.end() && j->first.declaration==i->second); )
{
- if(i->second.expression && i->second.inline_point)
- inline_expression(*i->second.expression, *i->second.inline_point, i->second.outer_oper, i->second.inner_oper, i->second.inline_on_rhs);
+ if(j->second.expression && j->second.inline_point)
+ inline_expression(*j->second.expression, *j->second.inline_point, j->second.outer_oper, j->second.inner_oper, j->second.inline_on_rhs);
- expressions.erase(i++);
- }
- else
- {
- /* The expression was assigned in this block and may depend on local
- variables of the block. If this is a conditionally executed block,
- the assignment might not always happen. Mark the expression as not
- available to any outer blocks. */
- if(i->second.assign_scope==&block)
- i->second.available = false;
-
- ++i;
+ expressions.erase(j++);
}
}
+
+ /* Expressions assigned in this block may depend on local variables of the
+ block. If this is a conditionally executed block, the assignments might not
+ always happen. Mark the expressions as not available to any outer blocks. */
+ for(map<Assignment::Target, ExpressionInfo>::iterator i=expressions.begin(); i!=expressions.end(); ++i)
+ if(i->second.assign_scope==&block)
+ i->second.available = false;
+}
+
+void ExpressionInliner::visit(RefPtr<Expression> &expr)
+{
+ visit_and_record(expr, 0, false);
}
void ExpressionInliner::visit(VariableReference &var)
{
if(var.declaration)
{
- map<VariableDeclaration *, ExpressionInfo>::iterator i = expressions.find(var.declaration);
+ map<Assignment::Target, ExpressionInfo>::iterator i = expressions.find(var.declaration);
if(i!=expressions.end())
{
/* If a non-trivial expression is referenced multiple times, don't
void ExpressionInliner::visit(MemberAccess &memacc)
{
visit_and_record(memacc.left, memacc.oper, false);
- r_ref_info = 0;
r_oper = memacc.oper;
r_trivial = false;
}
+void ExpressionInliner::visit(Swizzle &swizzle)
+{
+ visit_and_record(swizzle.left, swizzle.oper, false);
+ r_oper = swizzle.oper;
+ r_trivial = false;
+}
+
void ExpressionInliner::visit(UnaryExpression &unary)
{
SetFlag set_target(mutating, mutating || unary.oper->token[1]=='+' || unary.oper->token[1]=='-');
visit_and_record(unary.expression, unary.oper, false);
- r_ref_info = 0;
r_oper = unary.oper;
r_trivial = false;
}
SetFlag clear_target(mutating, false);
visit_and_record(binary.right, binary.oper, true);
}
- r_ref_info = 0;
r_oper = binary.oper;
r_trivial = false;
}
r_oper = 0;
visit_and_record(assign.right, assign.oper, true);
- if(assign.target_declaration)
+ map<Assignment::Target, ExpressionInfo>::iterator i = expressions.find(assign.target);
+ if(i!=expressions.end())
{
- map<VariableDeclaration *, ExpressionInfo>::iterator i = expressions.find(assign.target_declaration);
- if(i!=expressions.end())
- {
- /* Self-referencing assignments can't be inlined without additional
- work. Just clear any previous expression. */
- i->second.expression = (assign.self_referencing ? 0 : assign.right.get());
- i->second.assign_scope = current_block;
- i->second.inline_point = 0;
- i->second.inner_oper = r_oper;
- i->second.available = true;
- }
+ /* Self-referencing assignments can't be inlined without additional
+ work. Just clear any previous expression. */
+ i->second.expression = (assign.self_referencing ? 0 : assign.right.get());
+ i->second.assign_scope = current_block;
+ i->second.inline_point = 0;
+ i->second.inner_oper = r_oper;
+ i->second.available = true;
}
- r_ref_info = 0;
r_oper = assign.oper;
r_trivial = false;
}
void ExpressionInliner::visit(FunctionCall &call)
{
- for(NodeArray<Expression>::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
- visit_and_record(*i, 0, false);
- r_ref_info = 0;
+ TraversingVisitor::visit(call);
r_oper = 0;
r_trivial = false;
}
{
r_oper = 0;
r_trivial = true;
- if(var.init_expression)
- visit_and_record(var.init_expression, 0, false);
+ TraversingVisitor::visit(var);
bool constant = var.constant;
if(constant && var.layout)
}
}
-void ExpressionInliner::visit(Conditional &cond)
-{
- visit_and_record(cond.condition, 0, false);
- cond.body.visit(*this);
-}
-
void ExpressionInliner::visit(Iteration &iter)
{
SetForScope<Block *> set_block(current_block, &iter.body);
SetForScope<Block *> set_body(iteration_body, &iter.body);
if(iter.condition)
- iter.condition->visit(*this);
+ visit(iter.condition);
iter.body.visit(*this);
if(iter.loop_expression)
- iter.loop_expression->visit(*this);
-}
-
-void ExpressionInliner::visit(Return &ret)
-{
- if(ret.expression)
- visit_and_record(ret.expression, 0, false);
+ visit(iter.loop_expression);
}
UnusedVariableRemover::VariableInfo::VariableInfo():
local(false),
+ output(false),
conditionally_assigned(false),
- referenced(false)
+ referenced(false),
+ interface_block(0)
{ }
return !unused_nodes.empty();
}
+void UnusedTypeRemover::visit(Literal &literal)
+{
+ unused_nodes.erase(literal.type);
+}
+
+void UnusedTypeRemover::visit(UnaryExpression &unary)
+{
+ unused_nodes.erase(unary.type);
+ TraversingVisitor::visit(unary);
+}
+
+void UnusedTypeRemover::visit(BinaryExpression &binary)
+{
+ unused_nodes.erase(binary.type);
+ TraversingVisitor::visit(binary);
+}
+
+void UnusedTypeRemover::visit(FunctionCall &call)
+{
+ unused_nodes.erase(call.type);
+ TraversingVisitor::visit(call);
+}
+
void UnusedTypeRemover::visit(BasicTypeDeclaration &type)
{
if(type.base_type)
unused_nodes.erase(var.type_declaration);
}
+void UnusedTypeRemover::visit(InterfaceBlock &iface)
+{
+ unused_nodes.erase(iface.type_declaration);
+}
+
void UnusedTypeRemover::visit(FunctionDeclaration &func)
{
unused_nodes.erase(func.return_type_declaration);
UnusedVariableRemover::UnusedVariableRemover():
- aggregate(0),
+ stage(0),
+ interface_block(0),
r_assignment(0),
assignment_target(false),
- r_assign_to_subfield(false),
r_side_effects(false)
{ }
-bool UnusedVariableRemover::apply(Stage &stage)
+bool UnusedVariableRemover::apply(Stage &s)
{
+ stage = &s;
variables.push_back(BlockVariableMap());
- stage.content.visit(*this);
+ s.content.visit(*this);
+
BlockVariableMap &global_variables = variables.back();
+ set<InterfaceBlock *> used_interface_blocks;
+ Statement *prev_decl = 0;
+ bool output;
for(BlockVariableMap::iterator i=global_variables.begin(); i!=global_variables.end(); ++i)
{
- /* Don't remove output variables which are used by the next stage or the
- graphics API. */
- if(i->first->interface=="out" && (stage.type==Stage::FRAGMENT || i->first->linked_declaration || !i->first->name.compare(0, 3, "gl_")))
+ if(i->first.declaration!=prev_decl)
+ {
+ prev_decl = i->first.declaration;
+ output = i->second.output;
+ }
+ if(output)
+ {
+ if(!i->second.assignments.empty() && i->second.interface_block)
+ used_interface_blocks.insert(i->second.interface_block);
continue;
+ }
// Mark other unreferenced global variables as unused.
if(!i->second.referenced)
{
- unused_nodes.insert(i->first);
+ if(!i->second.interface_block && !i->first.chain_len)
+ unused_nodes.insert(i->first.declaration);
clear_assignments(i->second, true);
}
+ else if(i->second.interface_block)
+ used_interface_blocks.insert(i->second.interface_block);
}
variables.pop_back();
- NodeRemover().apply(stage, unused_nodes);
+ for(map<string, InterfaceBlock *>::const_iterator i=s.interface_blocks.begin(); i!=s.interface_blocks.end(); ++i)
+ if(i->second->instance_name.empty() && !used_interface_blocks.count(i->second))
+ unused_nodes.insert(i->second);
+
+ NodeRemover().apply(s, unused_nodes);
return !unused_nodes.empty();
}
-void UnusedVariableRemover::visit(VariableReference &var)
+void UnusedVariableRemover::reference_used(Statement &declaration)
{
- map<VariableDeclaration *, Node *>::iterator i = aggregates.find(var.declaration);
- if(i!=aggregates.end())
- unused_nodes.erase(i->second);
-
- if(var.declaration && !assignment_target)
+ BlockVariableMap &block_vars = variables.back();
+ /* Previous assignments of all subfields of this variable are used by
+ this reference. */
+ for(BlockVariableMap::iterator i=block_vars.lower_bound(&declaration); (i!=block_vars.end() && i->first.declaration==&declaration); ++i)
{
- VariableInfo &var_info = variables.back()[var.declaration];
- // Previous assignments are used by this reference.
- clear_assignments(var_info, false);
- var_info.referenced = true;
+ clear_assignments(i->second, false);
+ i->second.referenced = true;
}
+
+ // Always record a reference to the primary declaration, even if it didn't exist before
+ block_vars[&declaration].referenced = true;
}
-void UnusedVariableRemover::visit(InterfaceBlockReference &iface)
+void UnusedVariableRemover::visit(VariableReference &var)
{
- unused_nodes.erase(iface.declaration);
+ if(var.declaration && !assignment_target)
+ reference_used(*var.declaration);
}
-void UnusedVariableRemover::visit(MemberAccess &memacc)
+void UnusedVariableRemover::visit(InterfaceBlockReference &iface)
{
- if(assignment_target)
- r_assign_to_subfield = true;
- TraversingVisitor::visit(memacc);
- unused_nodes.erase(memacc.declaration);
+ if(iface.declaration && !assignment_target)
+ reference_used(*iface.declaration);
}
void UnusedVariableRemover::visit(UnaryExpression &unary)
{
if(binary.oper->token[0]=='[')
{
- if(assignment_target)
- r_assign_to_subfield = true;
binary.left->visit(*this);
SetFlag set(assignment_target, false);
binary.right->visit(*this);
r_side_effects = true;
}
-void UnusedVariableRemover::record_assignment(VariableDeclaration &var, Node &node, bool chained)
+void UnusedVariableRemover::record_assignment(const Assignment::Target &target, Node &node, bool chained)
{
- VariableInfo &var_info = variables.back()[&var];
- /* An assignment which completely replaces the value of the variable causes
- any previous unreferenced assignments to be unused. */
- if(!chained)
- clear_assignments(var_info, true);
+ BlockVariableMap &block_vars = variables.back();
+ for(BlockVariableMap::iterator i=block_vars.lower_bound(target); (i!=block_vars.end() && i->first.declaration==target.declaration); ++i)
+ {
+ bool subfield = (i->first.chain_len>=target.chain_len);
+ for(unsigned j=0; (subfield && j<target.chain_len); ++j)
+ subfield = (i->first.chain[j]==target.chain[j]);
+ if(!subfield)
+ break;
+
+ /* An assignment to the target causes any previous unreferenced
+ assignments to the same target or its subfields to be unused. */
+ if(!chained)
+ clear_assignments(i->second, true);
+ }
+
+ VariableInfo &var_info = variables.back()[target];
var_info.assignments.push_back(&node);
var_info.conditionally_assigned = false;
}
void UnusedVariableRemover::visit(ExpressionStatement &expr)
{
r_assignment = 0;
- r_assign_to_subfield = false;
r_side_effects = false;
TraversingVisitor::visit(expr);
- if(r_assignment && r_assignment->target_declaration)
- record_assignment(*r_assignment->target_declaration, expr, (r_assignment->self_referencing || r_assign_to_subfield));
+ if(r_assignment && r_assignment->target.declaration)
+ record_assignment(r_assignment->target, expr, r_assignment->self_referencing);
if(!r_side_effects)
unused_nodes.insert(&expr);
}
-void UnusedVariableRemover::visit(StructDeclaration &strct)
-{
- SetForScope<Node *> set(aggregate, &strct);
- TraversingVisitor::visit(strct);
-}
-
void UnusedVariableRemover::visit(VariableDeclaration &var)
{
- if(aggregate)
- aggregates[&var] = aggregate;
+ VariableInfo &var_info = variables.back()[&var];
+ var_info.local = true;
+ 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->name.compare(0, 3, "gl_")));
else
- {
- variables.back()[&var].local = true;
- if(var.init_expression)
- record_assignment(var, *var.init_expression, false);
- }
+ var_info.output = (var.interface=="out" && (stage->type==Stage::FRAGMENT || var.linked_declaration || !var.name.compare(0, 3, "gl_")));
+
+ if(var.init_expression)
+ record_assignment(&var, *var.init_expression, false);
TraversingVisitor::visit(var);
}
void UnusedVariableRemover::visit(InterfaceBlock &iface)
{
- SetForScope<Node *> set(aggregate, &iface);
- unused_nodes.insert(&iface);
- TraversingVisitor::visit(iface);
+ if(iface.instance_name.empty())
+ {
+ SetForScope<InterfaceBlock *> set_block(interface_block, &iface);
+ iface.struct_declaration->members.visit(*this);
+ }
+ else
+ {
+ VariableInfo &var_info = variables.back()[&iface];
+ var_info.local = true;
+ var_info.output = (iface.interface=="out" && (iface.linked_block || !iface.name.compare(0, 3, "gl_")));
+ }
}
void UnusedVariableRemover::visit(FunctionDeclaration &func)
{
if(i->second.local)
{
- if(!i->second.referenced)
- unused_nodes.insert(i->first);
+ if(!i->second.referenced && !i->first.chain_len)
+ unused_nodes.insert(i->first.declaration);
/* Any unreferenced assignments when a variable runs out of scope
become unused. */
clear_assignments(i->second, true);