void ProgramCompiler::process()
{
if(module->vertex_context.present)
- process(module->vertex_context);
+ generate(module->vertex_context);
if(module->geometry_context.present)
- process(module->geometry_context);
+ generate(module->geometry_context);
if(module->fragment_context.present)
- process(module->fragment_context);
+ generate(module->fragment_context);
+
+ if(module->vertex_context.present)
+ optimize(module->vertex_context);
+ if(module->geometry_context.present)
+ optimize(module->geometry_context);
+ if(module->fragment_context.present)
+ optimize(module->fragment_context);
}
-void ProgramCompiler::process(Context &context)
+void ProgramCompiler::generate(Context &context)
{
inject_block(context.content, module->global_context.content);
VariableRenamer renamer;
context.content.visit(renamer);
+}
+void ProgramCompiler::optimize(Context &context)
+{
while(1)
{
UnusedVariableLocator unused_locator;
- context.content.visit(unused_locator);
+ unused_locator.visit(context);
NodeRemover remover;
- remover.to_remove.insert(unused_locator.unused_variables.begin(), unused_locator.unused_variables.end());
- context.content.visit(remover);
+ remover.to_remove = unused_locator.unused_nodes;
+ remover.visit(context);
if(!remover.n_removed)
break;
else if(var.interface=="in")
{
context->in_variables[var.name] = &var;
- if(context->previous)
+ if(var.linked_declaration)
+ var.linked_declaration->linked_declaration = &var;
+ else if(context->previous)
{
const map<string, VariableDeclaration *> &prev_out = context->previous->out_variables;
map<string, VariableDeclaration *>::const_iterator i = prev_out.find(var.name);
}
+ProgramCompiler::UnusedVariableLocator::UnusedVariableLocator():
+ context(0),
+ assignment(false),
+ assignment_target(0)
+{ }
+
+void ProgramCompiler::UnusedVariableLocator::visit(Context &ctx)
+{
+ context = &ctx;
+ ctx.content.visit(*this);
+}
+
void ProgramCompiler::UnusedVariableLocator::visit(VariableReference &var)
{
- unused_variables.erase(var.declaration);
+ if(assignment)
+ assignment_target = var.declaration;
+ else
+ {
+ unused_nodes.erase(var.declaration);
+ map<VariableDeclaration *, Node *>::iterator i = assignments.find(var.declaration);
+ if(i!=assignments.end())
+ unused_nodes.erase(i->second);
+ }
}
void ProgramCompiler::UnusedVariableLocator::visit(MemberAccess &memacc)
{
TraversingVisitor::visit(memacc);
- unused_variables.erase(memacc.declaration);
+ unused_nodes.erase(memacc.declaration);
+}
+
+void ProgramCompiler::UnusedVariableLocator::visit(BinaryExpression &binary)
+{
+ if(binary.assignment)
+ {
+ binary.right->visit(*this);
+ assignment = true;
+ binary.left->visit(*this);
+ }
+ else
+ TraversingVisitor::visit(binary);
+}
+
+void ProgramCompiler::UnusedVariableLocator::visit(ExpressionStatement &expr)
+{
+ assignment = false;
+ assignment_target = 0;
+ TraversingVisitor::visit(expr);
+ if(assignment && assignment_target)
+ {
+ if(assignment_target->interface!="out" || (context->type!=FRAGMENT && !assignment_target->linked_declaration))
+ {
+ unused_nodes.insert(&expr);
+ assignments[assignment_target] = &expr;
+ }
+ else
+ unused_nodes.erase(assignment_target);
+ }
+ assignment = false;
}
void ProgramCompiler::UnusedVariableLocator::visit(VariableDeclaration &var)
{
- unused_variables.insert(&var);
+ unused_nodes.insert(&var);
TraversingVisitor::visit(var);
}
ProgramCompiler::NodeRemover::NodeRemover():
+ context(0),
n_removed(0),
immutable_block(false),
remove_block(false)
{ }
+void ProgramCompiler::NodeRemover::visit(Context &ctx)
+{
+ context = &ctx;
+ ctx.content.visit(*this);
+}
+
void ProgramCompiler::NodeRemover::visit(Block &block)
{
remove_block = immutable_block;
for(list<NodePtr<Node> >::iterator i=block.body.begin(); i!=block.body.end(); )
{
- bool remove = false;
- if(to_remove.count(&**i))
- remove = !immutable_block;
- else
- {
+ bool remove = to_remove.count(&**i);
+ if(!remove)
remove_block = false;
- (*i)->visit(*this);
- remove = remove_block;
- }
+ (*i)->visit(*this);
- if(remove)
+ if(remove ? !immutable_block : remove_block)
+ {
block.body.erase(i++);
+ ++n_removed;
+ }
else
++i;
-
- n_removed += remove;
}
}
TraversingVisitor::visit(strct);
}
+void ProgramCompiler::NodeRemover::visit(VariableDeclaration &var)
+{
+ if(to_remove.count(&var))
+ {
+ context->in_variables.erase(var.name);
+ context->out_variables.erase(var.name);
+ if(var.linked_declaration)
+ var.linked_declaration->linked_declaration = 0;
+ }
+}
+
void ProgramCompiler::NodeRemover::visit(InterfaceBlock &iface)
{
SetFlag set(immutable_block);
struct UnusedVariableLocator: ProgramSyntax::TraversingVisitor
{
- std::set<ProgramSyntax::VariableDeclaration *> unused_variables;
+ ProgramSyntax::Context *context;
+ std::set<ProgramSyntax::Node *> unused_nodes;
+ std::map<ProgramSyntax::VariableDeclaration *, ProgramSyntax::Node *> assignments;
+ bool assignment;
+ ProgramSyntax::VariableDeclaration *assignment_target;
+
+ UnusedVariableLocator();
+ void visit(ProgramSyntax::Context &);
virtual void visit(ProgramSyntax::VariableReference &);
virtual void visit(ProgramSyntax::MemberAccess &);
+ virtual void visit(ProgramSyntax::BinaryExpression &);
+ virtual void visit(ProgramSyntax::ExpressionStatement &);
virtual void visit(ProgramSyntax::VariableDeclaration &);
};
struct NodeRemover: ProgramSyntax::TraversingVisitor
{
+ ProgramSyntax::Context *context;
std::set<ProgramSyntax::Node *> to_remove;
unsigned n_removed;
bool immutable_block;
NodeRemover();
+ void visit(ProgramSyntax::Context &);
virtual void visit(ProgramSyntax::Block &);
virtual void visit(ProgramSyntax::StructDeclaration &);
+ virtual void visit(ProgramSyntax::VariableDeclaration &);
virtual void visit(ProgramSyntax::InterfaceBlock &);
};
private:
void process();
- void process(ProgramSyntax::Context &);
+ void generate(ProgramSyntax::Context &);
+ void optimize(ProgramSyntax::Context &);
static void inject_block(ProgramSyntax::Block &, const ProgramSyntax::Block &);
static void resolve_variables(ProgramSyntax::Context &);
std::string format_context(ProgramSyntax::Context &);