From: Mikko Rasa Date: Fri, 11 Nov 2016 11:37:18 +0000 (+0200) Subject: Extend unused variable analysis to assignments and across interfaces X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=009918a51aa309eeceb6c02ecaebe45e8d357033;p=libs%2Fgl.git Extend unused variable analysis to assignments and across interfaces Assignments are removed if there are no further references to the assigned variable, except if it's a linked out variable. --- diff --git a/source/programcompiler.cpp b/source/programcompiler.cpp index 6bf5ba66..ecdcd519 100644 --- a/source/programcompiler.cpp +++ b/source/programcompiler.cpp @@ -51,14 +51,21 @@ void ProgramCompiler::add_shaders(Program &program) 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); @@ -71,15 +78,18 @@ void ProgramCompiler::process(Context &context) 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; @@ -535,7 +545,9 @@ void ProgramCompiler::InterfaceGenerator::visit(VariableDeclaration &var) 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 &prev_out = context->previous->out_variables; map::const_iterator i = prev_out.find(var.name); @@ -595,51 +607,104 @@ void ProgramCompiler::VariableRenamer::visit(VariableDeclaration &var) } +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::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 >::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; } } @@ -649,6 +714,17 @@ void ProgramCompiler::NodeRemover::visit(StructDeclaration &strct) 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); diff --git a/source/programcompiler.h b/source/programcompiler.h index 978b01e2..6bac5386 100644 --- a/source/programcompiler.h +++ b/source/programcompiler.h @@ -90,15 +90,25 @@ private: struct UnusedVariableLocator: ProgramSyntax::TraversingVisitor { - std::set unused_variables; + ProgramSyntax::Context *context; + std::set unused_nodes; + std::map 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 to_remove; unsigned n_removed; bool immutable_block; @@ -106,8 +116,10 @@ private: 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 &); }; @@ -123,7 +135,8 @@ public: 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 &);