]> git.tdb.fi Git - libs/gl.git/blobdiff - source/glsl/optimize.cpp
Remove output variables which are not referenced
[libs/gl.git] / source / glsl / optimize.cpp
index 768cfd5dc761659f504011780e3e0cbc74f90c0d..1e974c9f01f8eee6d3eea5faabc00b20759ffd37 100644 (file)
@@ -532,11 +532,19 @@ bool AggregateDismantler::apply(Stage &stage)
 
                for(const AggregateMember &m: kvp.second.members)
                {
+                       string name;
+                       if(m.declaration)
+                               name = format("%s_%s", kvp.second.declaration->name, m.declaration->name);
+                       else
+                               name = format("%s_%d", kvp.second.declaration->name, m.index);
+
                        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;
+                       var->name = get_unused_variable_name(*kvp.second.decl_scope, name);
+                       /* XXX This is kind of brittle and depends on the array declaration's
+                       textual type not having brackets in it. */
+                       var->type = (m.declaration ? m.declaration : kvp.second.declaration)->type;
                        if(m.initializer)
                                var->init_expression = m.initializer->clone();
 
@@ -570,10 +578,17 @@ 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)
+       if(r_aggregate_ref && r_reference.chain_len==1)
        {
-               r_aggregate_ref->members[r_reference.chain[0]&0x3F].references.push_back(&expr);
-               r_aggregate_ref->members_referenced = true;
+               if((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;
+               }
+               else
+                       /* If the accessed member is not known, mark the entire aggregate as
+                       referenced. */
+                       r_aggregate_ref->referenced = true;
        }
        r_aggregate_ref = 0;
 }
@@ -584,6 +599,8 @@ void AggregateDismantler::visit(VariableReference &var)
                r_reference.declaration = var.declaration;
        else
        {
+               /* If an aggregate variable is referenced as a whole, it should not be
+               dismantled. */
                auto i = aggregates.find(var.declaration);
                if(i!=aggregates.end())
                        i->second.referenced = true;
@@ -624,7 +641,19 @@ void AggregateDismantler::visit(BinaryExpression &binary)
                        visit(binary.right);
                }
 
-               add_to_chain(r_reference, Assignment::Target::ARRAY, 0x3F);
+               unsigned index = 0x3F;
+               if(Literal *literal_subscript = dynamic_cast<Literal *>(binary.right.get()))
+                       if(literal_subscript->value.check_type<int>())
+                               index = literal_subscript->value.value<int>();
+               add_to_chain(r_reference, Assignment::Target::ARRAY, 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;
        }
        else
        {
@@ -638,6 +667,7 @@ 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());
@@ -656,6 +686,7 @@ void AggregateDismantler::visit(VariableDeclaration &var)
                                        {
                                                AggregateMember member;
                                                member.declaration = mem_decl;
+                                               member.index = i;
                                                if(init_call)
                                                        member.initializer = init_call->arguments[i];
                                                aggre.members.push_back(member);
@@ -664,6 +695,31 @@ void AggregateDismantler::visit(VariableDeclaration &var)
                                }
                        }
                }
+               else if(const Literal *literal_size = dynamic_cast<const Literal *>(var.array_size.get()))
+               {
+                       if(literal_size->value.check_type<int>())
+                       {
+                               Aggregate &aggre = aggregates[&var];
+                               aggre.declaration = &var;
+                               aggre.decl_scope = current_block;
+                               aggre.insert_point = insert_point;
+
+                               int size = literal_size->value.value<int>();
+                               for(int i=0; i<size; ++i)
+                               {
+                                       AggregateMember member;
+                                       member.index = i;
+                                       // Array initializers are not supported yet
+                                       aggre.members.push_back(member);
+                               }
+                       }
+               }
+       }
+}
+
+void AggregateDismantler::visit(FunctionDeclaration &func)
+{
+       func.body.visit(*this);
 }
 
 
@@ -1204,23 +1260,15 @@ bool UnusedVariableRemover::apply(Stage &s)
 
        for(const auto &kvp: variables)
        {
-               if(kvp.second.output)
+               if(!kvp.second.referenced)
+                       unused_nodes.insert(kvp.first);
+               else if(kvp.second.output)
                {
                        /* The last visible assignments of output variables are used by the
                        next stage or the API. */
                        for(AssignmentInfo *a: kvp.second.assignments)
                                unused_nodes.erase(a->node);
                }
-
-               if(!kvp.second.output && !kvp.second.referenced)
-               {
-                       // Don't remove variables from inside interface blocks.
-                       if(!kvp.second.interface_block)
-                               unused_nodes.insert(kvp.first);
-               }
-               else if(kvp.second.interface_block)
-                       // Interface blocks are kept if even one member is used.
-                       unused_nodes.erase(kvp.second.interface_block);
        }
 
        NodeRemover().apply(s, unused_nodes);
@@ -1437,14 +1485,14 @@ void UnusedVariableRemover::visit(VariableDeclaration &var)
                return;
 
        VariableInfo &var_info = variables[&var];
-       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->block_name.compare(0, 3, "gl_")));
-       else
-               var_info.output = (var.interface=="out" && (stage->type==Stage::FRAGMENT || var.linked_declaration || !var.name.compare(0, 3, "gl_")));
+       var_info.output = (var.interface=="out" && (stage->type==Stage::FRAGMENT || var.linked_declaration || !var.name.compare(0, 3, "gl_")));
+
+       // Linked outputs are automatically referenced.
+       if(var_info.output && var.linked_declaration)
+               var_info.referenced = true;
 
        if(var.init_expression)
        {