]> git.tdb.fi Git - libs/gl.git/commitdiff
Extend unused variable analysis to assignments and across interfaces
authorMikko Rasa <tdb@tdb.fi>
Fri, 11 Nov 2016 11:37:18 +0000 (13:37 +0200)
committerMikko Rasa <tdb@tdb.fi>
Fri, 11 Nov 2016 11:47:23 +0000 (13:47 +0200)
Assignments are removed if there are no further references to the
assigned variable, except if it's a linked out variable.

source/programcompiler.cpp
source/programcompiler.h

index 6bf5ba66a83ed851075e48fda66f33a3a17b5d6e..ecdcd519f69c1cdb4410ee377b0073e9772028ea 100644 (file)
@@ -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<string, VariableDeclaration *> &prev_out = context->previous->out_variables;
                        map<string, VariableDeclaration *>::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<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;
        }
 }
 
@@ -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);
index 978b01e2d159135d3dcf5dbb7b0ef6b4b5bb6c0d..6bac5386828d928ba2d9379366d48b8efb9ae020 100644 (file)
@@ -90,15 +90,25 @@ private:
 
        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;
@@ -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 &);