From e2357c3e5438706ab6fcda86199cd897d46cfcd3 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Tue, 9 Mar 2021 10:21:18 +0200 Subject: [PATCH] Refactor UnusedVariableRemover It can now track and remove named interface blocks. --- source/glsl/optimize.cpp | 161 ++++++++++++++++++++++----------------- source/glsl/optimize.h | 19 ++--- 2 files changed, 99 insertions(+), 81 deletions(-) diff --git a/source/glsl/optimize.cpp b/source/glsl/optimize.cpp index 85f97fae..215466b2 100644 --- a/source/glsl/optimize.cpp +++ b/source/glsl/optimize.cpp @@ -620,8 +620,10 @@ void ConstantConditionEliminator::visit(Iteration &iter) UnusedVariableRemover::VariableInfo::VariableInfo(): local(false), + output(false), conditionally_assigned(false), - referenced(false) + referenced(false), + interface_block(0) { } @@ -693,82 +695,83 @@ void UnusedTypeRemover::visit(FunctionDeclaration &func) UnusedVariableRemover::UnusedVariableRemover(): - aggregate(0), + stage(0), + interface_block(0), r_assignment(0), assignment_target(false), - r_assign_to_subfield(false), r_side_effects(false) { } -bool UnusedVariableRemover::apply(Stage &stage) +bool UnusedVariableRemover::apply(Stage &s) { + stage = &s; variables.push_back(BlockVariableMap()); - stage.content.visit(*this); + s.content.visit(*this); + BlockVariableMap &global_variables = variables.back(); + set used_interface_blocks; + Statement *prev_decl = 0; + bool output; for(BlockVariableMap::iterator i=global_variables.begin(); i!=global_variables.end(); ++i) { - string interface = i->first->interface; - bool linked = i->first->linked_declaration; - map::iterator j = aggregates.find(i->first); - if(j!=aggregates.end()) - if(InterfaceBlock *iface = dynamic_cast(j->second)) - { - interface = iface->interface; - linked = iface->linked_block; - } - - /* Don't remove output variables which are used by the next stage or the - graphics API. */ - if(interface=="out" && (stage.type==Stage::FRAGMENT || linked || !i->first->name.compare(0, 3, "gl_"))) + if(i->first.declaration!=prev_decl) + { + prev_decl = i->first.declaration; + output = i->second.output; + } + if(output) + { + if(!i->second.assignments.empty() && i->second.interface_block) + used_interface_blocks.insert(i->second.interface_block); continue; + } // Mark other unreferenced global variables as unused. if(!i->second.referenced) { - unused_nodes.insert(i->first); + if(!i->second.interface_block && !i->first.chain_len) + unused_nodes.insert(i->first.declaration); clear_assignments(i->second, true); } + else if(i->second.interface_block) + used_interface_blocks.insert(i->second.interface_block); } variables.pop_back(); - NodeRemover().apply(stage, unused_nodes); + for(map::const_iterator i=s.interface_blocks.begin(); i!=s.interface_blocks.end(); ++i) + if(i->second->instance_name.empty() && !used_interface_blocks.count(i->second)) + unused_nodes.insert(i->second); + + NodeRemover().apply(s, unused_nodes); return !unused_nodes.empty(); } -void UnusedVariableRemover::visit(VariableReference &var) +void UnusedVariableRemover::reference_used(Statement &declaration) { - map::iterator i = aggregates.find(var.declaration); - if(i!=aggregates.end()) - unused_nodes.erase(i->second); - - if(var.declaration && !assignment_target) + BlockVariableMap &block_vars = variables.back(); + /* Previous assignments of all subfields of this variable are used by + this reference. */ + for(BlockVariableMap::iterator i=block_vars.lower_bound(&declaration); (i!=block_vars.end() && i->first.declaration==&declaration); ++i) { - VariableInfo &var_info = variables.back()[var.declaration]; - // Previous assignments are used by this reference. - clear_assignments(var_info, false); - var_info.referenced = true; + clear_assignments(i->second, false); + i->second.referenced = true; } -} -void UnusedVariableRemover::visit(InterfaceBlockReference &iface) -{ - unused_nodes.erase(iface.declaration); + // Always record a reference to the primary declaration, even if it didn't exist before + block_vars[&declaration].referenced = true; } -void UnusedVariableRemover::visit(MemberAccess &memacc) +void UnusedVariableRemover::visit(VariableReference &var) { - if(assignment_target) - r_assign_to_subfield = true; - TraversingVisitor::visit(memacc); - unused_nodes.erase(memacc.declaration); + if(var.declaration && !assignment_target) + reference_used(*var.declaration); } -void UnusedVariableRemover::visit(Swizzle &swizzle) +void UnusedVariableRemover::visit(InterfaceBlockReference &iface) { - if(assignment_target) - r_assign_to_subfield = true; - TraversingVisitor::visit(swizzle); + if(iface.declaration && !assignment_target) + reference_used(*iface.declaration); } void UnusedVariableRemover::visit(UnaryExpression &unary) @@ -782,8 +785,6 @@ void UnusedVariableRemover::visit(BinaryExpression &binary) { if(binary.oper->token[0]=='[') { - if(assignment_target) - r_assign_to_subfield = true; binary.left->visit(*this); SetFlag set(assignment_target, false); binary.right->visit(*this); @@ -811,13 +812,24 @@ void UnusedVariableRemover::visit(FunctionCall &call) r_side_effects = true; } -void UnusedVariableRemover::record_assignment(VariableDeclaration &var, Node &node, bool chained) +void UnusedVariableRemover::record_assignment(const Assignment::Target &target, Node &node, bool chained) { - VariableInfo &var_info = variables.back()[&var]; - /* An assignment which completely replaces the value of the variable causes - any previous unreferenced assignments to be unused. */ - if(!chained) - clear_assignments(var_info, true); + BlockVariableMap &block_vars = variables.back(); + for(BlockVariableMap::iterator i=block_vars.lower_bound(target); (i!=block_vars.end() && i->first.declaration==target.declaration); ++i) + { + bool subfield = (i->first.chain_len>=target.chain_len); + for(unsigned j=0; (subfield && jfirst.chain[j]==target.chain[j]); + if(!subfield) + break; + + /* An assignment to the target causes any previous unreferenced + assignments to the same target or its subfields to be unused. */ + if(!chained) + clear_assignments(i->second, true); + } + + VariableInfo &var_info = variables.back()[target]; var_info.assignments.push_back(&node); var_info.conditionally_assigned = false; } @@ -835,40 +847,45 @@ void UnusedVariableRemover::clear_assignments(VariableInfo &var_info, bool mark_ void UnusedVariableRemover::visit(ExpressionStatement &expr) { r_assignment = 0; - r_assign_to_subfield = false; r_side_effects = false; TraversingVisitor::visit(expr); if(r_assignment && r_assignment->target.declaration) - if(VariableDeclaration *target_var = dynamic_cast(r_assignment->target.declaration)) - record_assignment(*target_var, expr, (r_assignment->self_referencing || r_assign_to_subfield)); + record_assignment(r_assignment->target, expr, r_assignment->self_referencing); if(!r_side_effects) unused_nodes.insert(&expr); } -void UnusedVariableRemover::visit(StructDeclaration &strct) -{ - SetForScope set(aggregate, &strct); - TraversingVisitor::visit(strct); -} - void UnusedVariableRemover::visit(VariableDeclaration &var) { - if(aggregate) - aggregates[&var] = aggregate; + VariableInfo &var_info = variables.back()[&var]; + var_info.local = true; + var_info.interface_block = interface_block; + + /* Mark variables as output if they're used by the next stage or the + graphics API. */ + if(interface_block) + var_info.output = (interface_block->interface=="out" && (interface_block->linked_block || !interface_block->name.compare(0, 3, "gl_"))); else - { - variables.back()[&var].local = true; - if(var.init_expression) - record_assignment(var, *var.init_expression, false); - } + var_info.output = (var.interface=="out" && (stage->type==Stage::FRAGMENT || var.linked_declaration || !var.name.compare(0, 3, "gl_"))); + + if(var.init_expression) + record_assignment(&var, *var.init_expression, false); TraversingVisitor::visit(var); } void UnusedVariableRemover::visit(InterfaceBlock &iface) { - SetForScope set(aggregate, &iface); - unused_nodes.insert(&iface); - iface.struct_declaration->members.visit(*this); + if(iface.instance_name.empty()) + { + SetForScope set_block(interface_block, &iface); + iface.struct_declaration->members.visit(*this); + } + else + { + VariableInfo &var_info = variables.back()[&iface]; + var_info.local = true; + var_info.output = (iface.interface=="out" && (iface.linked_block || !iface.name.compare(0, 3, "gl_"))); + } } void UnusedVariableRemover::visit(FunctionDeclaration &func) @@ -903,8 +920,8 @@ void UnusedVariableRemover::merge_down_variables() { if(i->second.local) { - if(!i->second.referenced) - unused_nodes.insert(i->first); + if(!i->second.referenced && !i->first.chain_len) + unused_nodes.insert(i->first.declaration); /* Any unreferenced assignments when a variable runs out of scope become unused. */ clear_assignments(i->second, true); diff --git a/source/glsl/optimize.h b/source/glsl/optimize.h index 67d064c5..4f3bf8cc 100644 --- a/source/glsl/optimize.h +++ b/source/glsl/optimize.h @@ -197,23 +197,24 @@ class UnusedVariableRemover: private TraversingVisitor private: struct VariableInfo { - bool local; std::vector assignments; + bool local; + bool output; bool conditionally_assigned; bool referenced; + InterfaceBlock *interface_block; VariableInfo(); }; - typedef std::map BlockVariableMap; + typedef std::map BlockVariableMap; + Stage *stage; std::set unused_nodes; - std::map aggregates; - Node *aggregate; std::vector variables; + InterfaceBlock *interface_block; Assignment *r_assignment; bool assignment_target; - bool r_assign_to_subfield; bool r_side_effects; public: @@ -222,18 +223,18 @@ public: bool apply(Stage &); private: + void reference_used(Statement &); virtual void visit(VariableReference &); virtual void visit(InterfaceBlockReference &); - virtual void visit(MemberAccess &); - virtual void visit(Swizzle &); virtual void visit(UnaryExpression &); virtual void visit(BinaryExpression &); virtual void visit(Assignment &); - void record_assignment(VariableDeclaration &, Node &, bool); + void record_assignment(const Assignment::Target &, Node &, bool); void clear_assignments(VariableInfo &, bool); virtual void visit(FunctionCall &); virtual void visit(ExpressionStatement &); - virtual void visit(StructDeclaration &); + // Ignore structs because their members can't be accessed directly. + virtual void visit(StructDeclaration &) { } virtual void visit(VariableDeclaration &); virtual void visit(InterfaceBlock &); virtual void visit(FunctionDeclaration &); -- 2.43.0