]> git.tdb.fi Git - libs/gl.git/commitdiff
Refactor and improve unused variable detection in ProgramCompiler
authorMikko Rasa <tdb@tdb.fi>
Sat, 10 Dec 2016 17:24:58 +0000 (19:24 +0200)
committerMikko Rasa <tdb@tdb.fi>
Sat, 10 Dec 2016 17:24:58 +0000 (19:24 +0200)
It now recognizes and marks for removal assignments to global variables
if the variable is not read in any function.

source/programcompiler.cpp
source/programcompiler.h

index 4e4b4814f171b531bfffedea17c9b9d46101fab1..5f8c6f9b91f612c218992ff8553620803b1f269a 100644 (file)
@@ -1213,41 +1213,39 @@ ProgramCompiler::UnusedVariableLocator::UnusedVariableLocator():
        aggregate(0),
        assignment(0),
        assignment_target(false),
-       iteration(false)
+       global_scope(true)
 { }
 
 void ProgramCompiler::UnusedVariableLocator::apply(Stage &s)
 {
-       assignments.push_back(BlockAssignmentMap());
+       variables.push_back(BlockVariableMap());
        Visitor::apply(s);
-       assignments.pop_back();
+       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);
+                       for(vector<Node *>::iterator j=i->second.assignments.begin(); j!=i->second.assignments.end(); ++j)
+                               unused_nodes.insert(*j);
+               }
+       }
+       variables.pop_back();
 }
 
 void ProgramCompiler::UnusedVariableLocator::visit(VariableReference &var)
 {
-       unused_nodes.erase(var.declaration);
-
        map<VariableDeclaration *, Node *>::iterator i = aggregates.find(var.declaration);
        if(i!=aggregates.end())
                unused_nodes.erase(i->second);
 
-       if(assignment_target)
-               return;
-
-       if(iteration)
-               used_in_iteration.insert(var.declaration);
-
-       for(vector<BlockAssignmentMap>::iterator j=assignments.end(); j!=assignments.begin(); )
+       if(var.declaration && !assignment_target)
        {
-               --j;
-               BlockAssignmentMap::iterator k = j->find(var.declaration);
-               if(k!=j->end())
-               {
-                       for(vector<Node *>::iterator l=k->second.nodes.begin(); l!=k->second.nodes.end(); ++l)
-                               unused_nodes.erase(*l);
-                       j->erase(k);
-                       break;
-               }
+               VariableInfo &var_info = variables.back()[var.declaration];
+               var_info.assignments.clear();
+               var_info.referenced = true;
        }
 }
 
@@ -1281,15 +1279,11 @@ void ProgramCompiler::UnusedVariableLocator::visit(Assignment &assign)
 
 void ProgramCompiler::UnusedVariableLocator::record_assignment(VariableDeclaration &var, Node &node, bool self_ref)
 {
-       if(!used_in_iteration.count(&var))
-               unused_nodes.insert(&node);
-       BlockAssignmentMap &block_assignments = assignments.back();
-       AssignmentList &var_assignments = block_assignments[&var];
+       VariableInfo &var_info = variables.back()[&var];
        if(!self_ref)
-               var_assignments.nodes.clear();
-       var_assignments.nodes.push_back(&node);
-       var_assignments.conditional = false;
-       var_assignments.self_referencing = self_ref;
+               var_info.assignments.clear();
+       var_info.assignments.push_back(&node);
+       var_info.conditionally_assigned = false;
 }
 
 void ProgramCompiler::UnusedVariableLocator::visit(ExpressionStatement &expr)
@@ -1313,7 +1307,7 @@ void ProgramCompiler::UnusedVariableLocator::visit(VariableDeclaration &var)
                aggregates[&var] = aggregate;
        else
        {
-               unused_nodes.insert(&var);
+               variables.back()[&var].local = true;
                if(var.init_expression)
                        record_assignment(var, *var.init_expression, false);
        }
@@ -1330,95 +1324,107 @@ void ProgramCompiler::UnusedVariableLocator::visit(InterfaceBlock &iface)
 
 void ProgramCompiler::UnusedVariableLocator::visit(FunctionDeclaration &func)
 {
-       assignments.push_back(BlockAssignmentMap());
-
-       for(vector<RefPtr<VariableDeclaration> >::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
-               (*i)->visit(*this);
-       func.body.visit(*this);
+       variables.push_back(BlockVariableMap());
 
-       BlockAssignmentMap &block_assignments = assignments.back();
-       for(map<string, VariableDeclaration *>::iterator i=func.body.variables.begin(); i!=func.body.variables.end(); ++i)
-               block_assignments.erase(i->second);
-       for(BlockAssignmentMap::iterator i=block_assignments.begin(); i!=block_assignments.end(); ++i)
        {
-               if(i->first->interface=="out" && stage->type!=FRAGMENT && !i->first->linked_declaration)
-                       continue;
-
-               for(vector<Node *>::iterator j=i->second.nodes.begin(); j!=i->second.nodes.end(); ++j)
-                       unused_nodes.erase(*j);
+               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);
        }
 
-       assignments.pop_back();
+       BlockVariableMap &block_variables = variables.back();
+       for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
+               i->second.conditionally_assigned = true;
+       merge_down_variables();
 }
 
-void ProgramCompiler::UnusedVariableLocator::merge_down_assignments()
+void ProgramCompiler::UnusedVariableLocator::merge_down_variables()
 {
-       BlockAssignmentMap &parent_assignments = assignments[assignments.size()-2];
-       BlockAssignmentMap &block_assignments = assignments.back();
-       for(BlockAssignmentMap::iterator i=block_assignments.begin(); i!=block_assignments.end(); ++i)
+       BlockVariableMap &parent_variables = variables[variables.size()-2];
+       BlockVariableMap &block_variables = variables.back();
+       for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
        {
-               BlockAssignmentMap::iterator j = parent_assignments.find(i->first);
-               if(j==parent_assignments.end())
-                       parent_assignments.insert(*i);
-               else if(i->second.self_referencing || i->second.conditional)
+               if(i->second.local)
                {
-                       j->second.nodes.insert(j->second.nodes.end(), i->second.nodes.begin(), i->second.nodes.end());
-                       j->second.conditional |= i->second.conditional;
-                       j->second.self_referencing |= i->second.self_referencing;
+                       if(!i->second.referenced)
+                               unused_nodes.insert(i->first);
+                       for(vector<Node *>::iterator j=i->second.assignments.begin(); j!=i->second.assignments.end(); ++j)
+                               unused_nodes.insert(*j);
+                       continue;
                }
+
+               BlockVariableMap::iterator j = parent_variables.find(i->first);
+               if(j==parent_variables.end())
+                       parent_variables.insert(*i);
                else
-                       j->second = i->second;
+               {
+                       if(!i->second.conditionally_assigned)
+                       {
+                               j->second.assignments.clear();
+                               j->second.conditionally_assigned = true;
+                       }
+                       j->second.referenced |= i->second.referenced;
+                       j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin(), i->second.assignments.end());
+               }
        }
-       assignments.pop_back();
+       variables.pop_back();
 }
 
 void ProgramCompiler::UnusedVariableLocator::visit(Conditional &cond)
 {
        cond.condition->visit(*this);
-       assignments.push_back(BlockAssignmentMap());
+       variables.push_back(BlockVariableMap());
        cond.body.visit(*this);
 
-       BlockAssignmentMap if_assignments;
-       swap(assignments.back(), if_assignments);
+       BlockVariableMap if_variables;
+       swap(variables.back(), if_variables);
        cond.else_body.visit(*this);
 
-       BlockAssignmentMap &else_assignments = assignments.back();
-       for(BlockAssignmentMap::iterator i=else_assignments.begin(); i!=else_assignments.end(); ++i)
+       BlockVariableMap &else_variables = variables.back();
+       for(BlockVariableMap::iterator i=else_variables.begin(); i!=else_variables.end(); ++i)
        {
-               BlockAssignmentMap::iterator j = if_assignments.find(i->first);
-               if(j!=if_assignments.end())
+               BlockVariableMap::iterator j = if_variables.find(i->first);
+               if(j!=if_variables.end())
                {
-                       i->second.nodes.insert(i->second.nodes.end(), j->second.nodes.begin(), j->second.nodes.end());
-                       i->second.conditional |= j->second.conditional;
-                       i->second.self_referencing |= j->second.self_referencing;
-                       if_assignments.erase(j);
+                       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.conditional = true;
+                       i->second.conditionally_assigned = true;
        }
 
-       for(BlockAssignmentMap::iterator i=if_assignments.begin(); i!=if_assignments.end(); ++i)
+       for(BlockVariableMap::iterator i=if_variables.begin(); i!=if_variables.end(); ++i)
        {
-               i->second.conditional = true;
-               else_assignments.insert(*i);
+               i->second.conditionally_assigned = true;
+               else_variables.insert(*i);
        }
 
-       merge_down_assignments();
+       merge_down_variables();
 }
 
 void ProgramCompiler::UnusedVariableLocator::visit(Iteration &iter)
 {
-       assignments.push_back(BlockAssignmentMap());
-       {
-               SetFlag set(iteration);
-               TraversingVisitor::visit(iter);
-       }
-       merge_down_assignments();
-       if(!iteration)
-               used_in_iteration.clear();
+       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);
index db63eb3645d62d39fbb6a8717b28d9735d9b5234..0ff4f667d3feb830013d30c908a4eb97847b4ec4 100644 (file)
@@ -246,24 +246,26 @@ private:
 
        struct UnusedVariableLocator: Visitor
        {
-               struct AssignmentList
+               struct VariableInfo
                {
-                       std::vector<ProgramSyntax::Node *> nodes;
-                       bool conditional;
-                       bool self_referencing;
+                       bool local;
+                       std::vector<ProgramSyntax::Node *> assignments;
+                       bool conditionally_assigned;
+                       bool referenced;
+
+                       VariableInfo();
                };
 
                typedef std::set<ProgramSyntax::Node *> ResultType;
-               typedef std::map<ProgramSyntax::VariableDeclaration *, AssignmentList> BlockAssignmentMap;
+               typedef std::map<ProgramSyntax::VariableDeclaration *, VariableInfo> BlockVariableMap;
 
                std::set<ProgramSyntax::Node *> unused_nodes;
                std::map<ProgramSyntax::VariableDeclaration *, ProgramSyntax::Node *> aggregates;
                ProgramSyntax::Node *aggregate;
-               std::vector<BlockAssignmentMap> assignments;
+               std::vector<BlockVariableMap> variables;
                ProgramSyntax::Assignment *assignment;
                bool assignment_target;
-               bool iteration;
-               std::set<ProgramSyntax::Node *> used_in_iteration;
+               bool global_scope;
 
                UnusedVariableLocator();
 
@@ -279,7 +281,7 @@ private:
                virtual void visit(ProgramSyntax::VariableDeclaration &);
                virtual void visit(ProgramSyntax::InterfaceBlock &);
                virtual void visit(ProgramSyntax::FunctionDeclaration &);
-               void merge_down_assignments();
+               void merge_down_variables();
                virtual void visit(ProgramSyntax::Conditional &);
                virtual void visit(ProgramSyntax::Iteration &);
        };