]> git.tdb.fi Git - libs/gl.git/commitdiff
Break up struct variables if they're not used as a whole
authorMikko Rasa <tdb@tdb.fi>
Sat, 9 Oct 2021 16:44:06 +0000 (19:44 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sat, 9 Oct 2021 17:14:48 +0000 (20:14 +0300)
This lets the optimizer inline or discard individual members depending
on how or if they're used.

source/glsl/compiler.cpp
source/glsl/optimize.cpp
source/glsl/optimize.h

index 506fba1c417c62657ee98292febc5102a5a752cd..4b1d4edf11d0e6e29c8410ab123521b440826128 100644 (file)
@@ -363,6 +363,11 @@ Compiler::OptimizeResult Compiler::optimize(Stage &stage)
                resolve(stage, RESOLVE_TYPES|RESOLVE_VARIABLES|RESOLVE_FUNCTIONS|RESOLVE_EXPRESSIONS);
                any_inlined = true;
        }
+       if(AggregateDismantler().apply(stage))
+       {
+               resolve(stage, RESOLVE_TYPES|RESOLVE_VARIABLES|RESOLVE_FUNCTIONS|RESOLVE_EXPRESSIONS);
+               any_inlined = true;
+       }
        if(ExpressionInliner().apply(stage))
        {
                resolve(stage, RESOLVE_VARIABLES|RESOLVE_FUNCTIONS|RESOLVE_EXPRESSIONS);
index 8c586e7ad886cf433c4c5cadf6315783980804a6..350e2eb746537be79ea9d9c1854f45a6b860b53a 100644 (file)
@@ -520,6 +520,153 @@ void ExpressionInliner::visit(Iteration &iter)
 }
 
 
+bool AggregateDismantler::apply(Stage &stage)
+{
+       stage.content.visit(*this);
+
+       bool any_dismantled = false;
+       for(const auto &kvp: aggregates)
+       {
+               if(kvp.second.referenced || !kvp.second.members_referenced)
+                       continue;
+
+               for(const AggregateMember &m: kvp.second.members)
+               {
+                       VariableDeclaration *var = new VariableDeclaration;
+                       var->source = kvp.first->source;
+                       var->line = kvp.first->line;
+                       var->name = get_unused_variable_name(*kvp.second.decl_scope, format("%s_%s", kvp.second.declaration->name, m.declaration->name));
+                       var->type = m.declaration->type;
+                       if(m.initializer)
+                               var->init_expression = m.initializer->clone();
+
+                       kvp.second.decl_scope->body.insert(kvp.second.insert_point, var);
+
+                       for(RefPtr<Expression> *r: m.references)
+                       {
+                               VariableReference *ref = new VariableReference;
+                               ref->name = var->name;
+                               *r = ref;
+                       }
+
+                       any_dismantled = true;
+               }
+       }
+
+       return any_dismantled;
+}
+
+void AggregateDismantler::visit(Block &block)
+{
+       SetForScope<Block *> set_block(current_block, &block);
+       for(auto i=block.body.begin(); i!=block.body.end(); ++i)
+       {
+               insert_point = i;
+               (*i)->visit(*this);
+       }
+}
+
+void AggregateDismantler::visit(RefPtr<Expression> &expr)
+{
+       r_aggregate_ref = 0;
+       expr->visit(*this);
+       if(r_aggregate_ref && r_reference.chain_len==1 && (r_reference.chain[0]&0x3F)!=0x3F)
+       {
+               r_aggregate_ref->members[r_reference.chain[0]&0x3F].references.push_back(&expr);
+               r_aggregate_ref->members_referenced = true;
+       }
+       r_aggregate_ref = 0;
+}
+
+void AggregateDismantler::visit(VariableReference &var)
+{
+       if(composite_reference)
+               r_reference.declaration = var.declaration;
+       else
+       {
+               auto i = aggregates.find(var.declaration);
+               if(i!=aggregates.end())
+                       i->second.referenced = true;
+       }
+}
+
+void AggregateDismantler::visit_composite(RefPtr<Expression> &expr)
+{
+       if(!composite_reference)
+               r_reference = Assignment::Target();
+
+       SetFlag set_composite(composite_reference);
+       visit(expr);
+}
+
+void AggregateDismantler::visit(MemberAccess &memacc)
+{
+       visit_composite(memacc.left);
+
+       add_to_chain(r_reference, Assignment::Target::MEMBER, memacc.index);
+
+       if(r_reference.declaration && r_reference.chain_len==1)
+       {
+               auto i = aggregates.find(r_reference.declaration);
+               r_aggregate_ref = (i!=aggregates.end() ? &i->second : 0);
+       }
+       else
+               r_aggregate_ref = 0;
+}
+
+void AggregateDismantler::visit(BinaryExpression &binary)
+{
+       if(binary.oper->token[0]=='[')
+       {
+               visit_composite(binary.left);
+               {
+                       SetFlag clear_composite(composite_reference, false);
+                       visit(binary.right);
+               }
+
+               add_to_chain(r_reference, Assignment::Target::ARRAY, 0x3F);
+       }
+       else
+       {
+               SetFlag clear_composite(composite_reference, false);
+               TraversingVisitor::visit(binary);
+       }
+}
+
+void AggregateDismantler::visit(VariableDeclaration &var)
+{
+       TraversingVisitor::visit(var);
+
+       if(var.interface.empty())
+               if(const StructDeclaration *strct = dynamic_cast<const StructDeclaration *>(var.type_declaration))
+               {
+                       const FunctionCall *init_call = dynamic_cast<const FunctionCall *>(var.init_expression.get());
+                       if((init_call && init_call->constructor) || !var.init_expression)
+                       {
+
+                               Aggregate &aggre = aggregates[&var];
+                               aggre.declaration = &var;
+                               aggre.decl_scope = current_block;
+                               aggre.insert_point = insert_point;
+
+                               unsigned i = 0;
+                               for(const RefPtr<Statement> &s: strct->members.body)
+                               {
+                                       if(const VariableDeclaration *mem_decl = dynamic_cast<const VariableDeclaration *>(s.get()))
+                                       {
+                                               AggregateMember member;
+                                               member.declaration = mem_decl;
+                                               if(init_call)
+                                                       member.initializer = init_call->arguments[i];
+                                               aggre.members.push_back(member);
+                                       }
+                                       ++i;
+                               }
+                       }
+               }
+}
+
+
 template<typename T>
 T ConstantFolder::evaluate_logical(char oper, T left, T right)
 {
index ae55e5af10f5590f886906355342327a8ddb87be..1eb0464e7daea97d654576c15792a13e764d8c27 100644 (file)
@@ -151,6 +151,51 @@ private:
        virtual void visit(Iteration &);
 };
 
+/**
+Breaks aggregates up into separate variables if only the individual fields are
+accessed and not the aggregate as a whole.
+*/
+class AggregateDismantler: public TraversingVisitor
+{
+private:
+       struct AggregateMember
+       {
+               const VariableDeclaration *declaration = 0;
+               RefPtr<Expression> initializer;
+               std::vector<RefPtr<Expression> *> references;
+       };
+
+       struct Aggregate
+       {
+               VariableDeclaration *declaration = 0;
+               Block *decl_scope = 0;
+               NodeList<Statement>::iterator insert_point;
+               std::vector<AggregateMember> members;
+               bool referenced = false;
+               bool members_referenced = false;
+       };
+
+       NodeList<Statement>::iterator insert_point;
+       std::map<Statement *, Aggregate> aggregates;
+       bool composite_reference = false;
+       Assignment::Target r_reference;
+       Aggregate *r_aggregate_ref = 0;
+
+public:
+       bool apply(Stage &);
+
+private:
+       virtual void visit(Block &);
+       virtual void visit(RefPtr<Expression> &);
+       virtual void visit(VariableReference &);
+       void visit_composite(RefPtr<Expression> &);
+       virtual void visit(MemberAccess &);
+       virtual void visit(BinaryExpression &);
+       virtual void visit(StructDeclaration &) { }
+       virtual void visit(VariableDeclaration &);
+       virtual void visit(InterfaceBlock &) { }
+};
+
 /** Replaces expressions consisting entirely of literals with the results of
 evaluating the expression.*/
 class ConstantFolder: private TraversingVisitor