]> git.tdb.fi Git - libs/gl.git/blobdiff - source/glsl/optimize.cpp
Break up struct variables if they're not used as a whole
[libs/gl.git] / source / glsl / optimize.cpp
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)
 {