]> git.tdb.fi Git - libs/gl.git/blobdiff - source/glsl/optimize.cpp
Recognize unknown index as matching any index
[libs/gl.git] / source / glsl / optimize.cpp
index 8c586e7ad886cf433c4c5cadf6315783980804a6..768cfd5dc761659f504011780e3e0cbc74f90c0d 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)
 {
@@ -1095,10 +1242,10 @@ void UnusedVariableRemover::referenced(const Assignment::Target &target, Node &n
                        {
                                Assignment::Target::ChainType type1 = static_cast<Assignment::Target::ChainType>(a->target.chain[j]&0xC0);
                                Assignment::Target::ChainType type2 = static_cast<Assignment::Target::ChainType>(target.chain[j]&0xC0);
+                               unsigned index1 = a->target.chain[j]&0x3F;
+                               unsigned index2 = target.chain[j]&0x3F;
                                if(type1==Assignment::Target::SWIZZLE || type2==Assignment::Target::SWIZZLE)
                                {
-                                       unsigned index1 = a->target.chain[j]&0x3F;
-                                       unsigned index2 = target.chain[j]&0x3F;
                                        if(type1==Assignment::Target::SWIZZLE && type2==Assignment::Target::SWIZZLE)
                                                covered = index1&index2;
                                        else if(type1==Assignment::Target::ARRAY && index1<4)
@@ -1109,7 +1256,7 @@ void UnusedVariableRemover::referenced(const Assignment::Target &target, Node &n
                                        covered as true */
                                }
                                else
-                                       covered = (a->target.chain[j]==target.chain[j]);
+                                       covered = (type1==type2 && (index1==index2 || index1==0x3F || index2==0x3F));
                        }
 
                        if(covered)