+void ProgramCompiler::ConstantConditionEliminator::visit(Assignment &assign)
+{
+ variable_values.erase(assign.target_declaration);
+}
+
+void ProgramCompiler::ConstantConditionEliminator::visit(VariableDeclaration &var)
+{
+ if(var.constant || scope_level>1)
+ variable_values[&var] = var.init_expression.get();
+}
+
+void ProgramCompiler::ConstantConditionEliminator::visit(Conditional &cond)
+{
+ ExpressionEvaluator eval(&variable_values, in_loop);
+ cond.condition->visit(eval);
+ if(eval.result_valid)
+ flatten_block(eval.result ? cond.body : cond.else_body);
+ else
+ TraversingVisitor::visit(cond);
+}
+
+void ProgramCompiler::ConstantConditionEliminator::visit(Iteration &iter)
+{
+ // XXX Should this not visit init_statement first?
+ if(iter.condition)
+ {
+ ExpressionEvaluator eval(0, in_loop);
+ iter.condition->visit(eval);
+ if(eval.result_valid && !eval.result)
+ {
+ remove_node = true;
+ return;
+ }
+ }
+
+ SetFlag set_loop(in_loop);
+ TraversingVisitor::visit(iter);
+}
+
+
+ProgramCompiler::UnusedVariableLocator::UnusedVariableLocator():
+ aggregate(0),
+ assignment(0),
+ assignment_target(false),
+ global_scope(true)
+{ }
+
+void ProgramCompiler::UnusedVariableLocator::apply(Stage &s)
+{
+ variables.push_back(BlockVariableMap());
+ Visitor::apply(s);
+ BlockVariableMap &global_variables = variables.back();
+ for(BlockVariableMap::iterator i=global_variables.begin(); i!=global_variables.end(); ++i)
+ {
+ if(i->first->interface=="out" && (s.type==FRAGMENT || i->first->linked_declaration || !i->first->name.compare(0, 3, "gl_")))
+ continue;
+ if(!i->second.referenced)
+ {
+ unused_nodes.insert(i->first);
+ clear_assignments(i->second, true);
+ }
+ }
+ variables.pop_back();
+}
+
+void ProgramCompiler::UnusedVariableLocator::visit(VariableReference &var)
+{
+ map<VariableDeclaration *, Node *>::iterator i = aggregates.find(var.declaration);
+ if(i!=aggregates.end())
+ unused_nodes.erase(i->second);
+
+ if(var.declaration && !assignment_target)
+ {
+ VariableInfo &var_info = variables.back()[var.declaration];
+ var_info.assignments.clear();
+ var_info.referenced = true;
+ }
+}
+
+void ProgramCompiler::UnusedVariableLocator::visit(MemberAccess &memacc)
+{
+ TraversingVisitor::visit(memacc);
+ unused_nodes.erase(memacc.declaration);
+}
+
+void ProgramCompiler::UnusedVariableLocator::visit(BinaryExpression &binary)
+{
+ if(binary.oper=="[")
+ {
+ binary.left->visit(*this);
+ SetForScope<bool> set(assignment_target, false);
+ binary.right->visit(*this);
+ }
+ else
+ TraversingVisitor::visit(binary);
+}
+
+void ProgramCompiler::UnusedVariableLocator::visit(Assignment &assign)
+{
+ {
+ SetForScope<bool> set(assignment_target, !assign.self_referencing);
+ assign.left->visit(*this);
+ }
+ assign.right->visit(*this);
+ assignment = &assign;
+}
+
+void ProgramCompiler::UnusedVariableLocator::record_assignment(VariableDeclaration &var, Node &node, bool self_ref)
+{
+ VariableInfo &var_info = variables.back()[&var];
+ if(!self_ref)
+ clear_assignments(var_info, true);
+ var_info.assignments.push_back(&node);
+ var_info.conditionally_assigned = false;
+}
+
+void ProgramCompiler::UnusedVariableLocator::clear_assignments(VariableInfo &var_info, bool mark_unused)
+{
+ if(mark_unused)
+ {
+ for(vector<Node *>::iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i)
+ unused_nodes.insert(*i);
+ }
+ var_info.assignments.clear();
+}
+
+void ProgramCompiler::UnusedVariableLocator::visit(ExpressionStatement &expr)
+{
+ assignment = 0;
+ TraversingVisitor::visit(expr);
+ if(assignment && assignment->target_declaration)
+ record_assignment(*assignment->target_declaration, expr, assignment->self_referencing);
+}
+
+void ProgramCompiler::UnusedVariableLocator::visit(StructDeclaration &strct)
+{
+ SetForScope<Node *> set(aggregate, &strct);
+ unused_nodes.insert(&strct);
+ TraversingVisitor::visit(strct);
+}
+
+void ProgramCompiler::UnusedVariableLocator::visit(VariableDeclaration &var)
+{
+ if(aggregate)
+ aggregates[&var] = aggregate;
+ else
+ {
+ variables.back()[&var].local = true;
+ if(var.init_expression)
+ record_assignment(var, *var.init_expression, false);
+ }
+ unused_nodes.erase(var.type_declaration);
+ TraversingVisitor::visit(var);
+}
+
+void ProgramCompiler::UnusedVariableLocator::visit(InterfaceBlock &iface)
+{
+ SetForScope<Node *> set(aggregate, &iface);
+ unused_nodes.insert(&iface);
+ TraversingVisitor::visit(iface);
+}
+
+void ProgramCompiler::UnusedVariableLocator::visit(FunctionDeclaration &func)
+{
+ variables.push_back(BlockVariableMap());
+
+ {
+ SetForScope<bool> set(global_scope, false);
+ for(vector<RefPtr<VariableDeclaration> >::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
+ (*i)->visit(*this);
+ func.body.visit(*this);
+ }
+
+ BlockVariableMap &block_variables = variables.back();
+ for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
+ i->second.conditionally_assigned = true;
+ for(vector<RefPtr<VariableDeclaration> >::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
+ block_variables[i->get()].referenced = true;
+ merge_down_variables();
+}
+
+void ProgramCompiler::UnusedVariableLocator::merge_down_variables()
+{
+ BlockVariableMap &parent_variables = variables[variables.size()-2];
+ BlockVariableMap &block_variables = variables.back();
+ for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
+ {
+ if(i->second.local)
+ {
+ if(!i->second.referenced)
+ unused_nodes.insert(i->first);
+ clear_assignments(i->second, true);
+ continue;
+ }
+
+ BlockVariableMap::iterator j = parent_variables.find(i->first);
+ if(j==parent_variables.end())
+ parent_variables.insert(*i);
+ else
+ {
+ if(i->second.referenced || !i->second.conditionally_assigned)
+ clear_assignments(j->second, !i->second.referenced);
+ j->second.conditionally_assigned = i->second.conditionally_assigned;
+ j->second.referenced |= i->second.referenced;
+ j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin(), i->second.assignments.end());
+ }
+ }
+ variables.pop_back();
+}
+
+void ProgramCompiler::UnusedVariableLocator::visit(Conditional &cond)
+{
+ cond.condition->visit(*this);
+ variables.push_back(BlockVariableMap());
+ cond.body.visit(*this);
+
+ BlockVariableMap if_variables;
+ swap(variables.back(), if_variables);
+ cond.else_body.visit(*this);
+
+ BlockVariableMap &else_variables = variables.back();
+ for(BlockVariableMap::iterator i=else_variables.begin(); i!=else_variables.end(); ++i)
+ {
+ BlockVariableMap::iterator j = if_variables.find(i->first);
+ if(j!=if_variables.end())
+ {
+ i->second.assignments.insert(i->second.assignments.end(), j->second.assignments.begin(), j->second.assignments.end());
+ i->second.conditionally_assigned |= j->second.conditionally_assigned;
+ if_variables.erase(j);
+ }
+ else
+ i->second.conditionally_assigned = true;
+ }
+
+ for(BlockVariableMap::iterator i=if_variables.begin(); i!=if_variables.end(); ++i)
+ {
+ i->second.conditionally_assigned = true;
+ else_variables.insert(*i);
+ }
+
+ merge_down_variables();
+}
+
+void ProgramCompiler::UnusedVariableLocator::visit(Iteration &iter)
+{
+ variables.push_back(BlockVariableMap());
+ TraversingVisitor::visit(iter);
+
+ BlockVariableMap &block_variables = variables.back();
+ for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
+ if(!i->second.local && i->second.referenced)
+ i->second.assignments.clear();
+
+ merge_down_variables();
+}
+
+
+ProgramCompiler::UnusedVariableLocator::VariableInfo::VariableInfo():
+ local(false),
+ conditionally_assigned(false),
+ referenced(false)
+{ }
+
+
+void ProgramCompiler::UnusedFunctionLocator::visit(FunctionCall &call)
+{
+ TraversingVisitor::visit(call);
+
+ unused_nodes.erase(call.declaration);
+ if(call.declaration && call.declaration->definition!=call.declaration)
+ used_definitions.insert(call.declaration->definition);
+}
+
+void ProgramCompiler::UnusedFunctionLocator::visit(FunctionDeclaration &func)
+{
+ TraversingVisitor::visit(func);
+
+ if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func))
+ unused_nodes.insert(&func);
+}
+
+
+ProgramCompiler::NodeRemover::NodeRemover(const set<Node *> &r):
+ to_remove(r)
+{ }