X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fglsl%2Foptimize.cpp;h=0d6f753768ad2bd5fdbf7ff4d3a8f44ff75f1cb9;hb=6f06479b765946bdd3174b2c05e7a1dda24c31c2;hp=593a3222533874b6d8fde6265608efd9642e46e1;hpb=6ce72432215dd686f7c073616a7f3aa34e7d2b8d;p=libs%2Fgl.git diff --git a/source/glsl/optimize.cpp b/source/glsl/optimize.cpp index 593a3222..0d6f7537 100644 --- a/source/glsl/optimize.cpp +++ b/source/glsl/optimize.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -10,10 +11,6 @@ namespace Msp { namespace GL { namespace SL { -ConstantSpecializer::ConstantSpecializer(): - values(0) -{ } - void ConstantSpecializer::apply(Stage &stage, const map &v) { values = &v; @@ -26,20 +23,19 @@ void ConstantSpecializer::visit(VariableDeclaration &var) if(var.layout) { vector &qualifiers = var.layout->qualifiers; - for(vector::iterator i=qualifiers.begin(); (!specializable && i!=qualifiers.end()); ++i) - if(i->name=="constant_id") - { - specializable = true; - qualifiers.erase(i); - } - - if(qualifiers.empty()) - var.layout = 0; + auto i = find_member(qualifiers, string("constant_id"), &Layout::Qualifier::name); + if(i!=qualifiers.end()) + { + specializable = true; + qualifiers.erase(i); + if(qualifiers.empty()) + var.layout = 0; + } } if(specializable) { - map::const_iterator i = values->find(var.name); + auto i = values->find(var.name); if(i!=values->end()) { RefPtr literal = new Literal; @@ -59,11 +55,6 @@ void ConstantSpecializer::visit(VariableDeclaration &var) } -InlineableFunctionLocator::InlineableFunctionLocator(): - current_function(0), - return_count(0) -{ } - void InlineableFunctionLocator::visit(FunctionCall &call) { FunctionDeclaration *def = call.declaration; @@ -85,9 +76,8 @@ void InlineableFunctionLocator::visit(FunctionCall &call) void InlineableFunctionLocator::visit(FunctionDeclaration &func) { - bool has_out_params = false; - for(NodeArray::const_iterator i=func.parameters.begin(); (!has_out_params && i!=func.parameters.end()); ++i) - has_out_params = ((*i)->interface=="out"); + bool has_out_params = any_of(func.parameters.begin(), func.parameters.end(), + [](const RefPtr &p){ return p->interface=="out"; }); unsigned &count = refcounts[func.definition]; if((count<=1 || func.source==BUILTIN_SOURCE) && !has_out_params) @@ -119,11 +109,6 @@ void InlineableFunctionLocator::visit(Return &ret) } -InlineContentInjector::InlineContentInjector(): - source_func(0), - pass(REFERENCED) -{ } - string InlineContentInjector::apply(Stage &stage, FunctionDeclaration &target_func, Block &tgt_blk, const NodeList::iterator &ins_pt, FunctionCall &call) { source_func = call.declaration->definition; @@ -141,9 +126,9 @@ string InlineContentInjector::apply(Stage &stage, FunctionDeclaration &target_fu vector > params; params.reserve(source_func->parameters.size()); - for(NodeArray::iterator i=source_func->parameters.begin(); i!=source_func->parameters.end(); ++i) + for(const RefPtr &p: source_func->parameters) { - RefPtr var = (*i)->clone(); + RefPtr var = p->clone(); var->interface.clear(); SetForScope set_pass(pass, RENAME); @@ -153,12 +138,12 @@ string InlineContentInjector::apply(Stage &stage, FunctionDeclaration &target_fu params.push_back(var); } - for(NodeList::iterator i=source_func->body.body.begin(); i!=source_func->body.body.end(); ++i) + for(const RefPtr &s: source_func->body.body) { r_inlined_statement = 0; - (*i)->visit(*this); + s->visit(*this); if(!r_inlined_statement) - r_inlined_statement = (*i)->clone(); + r_inlined_statement = s->clone(); SetForScope set_pass(pass, RENAME); r_inlined_statement->visit(*this); @@ -194,7 +179,7 @@ void InlineContentInjector::visit(VariableReference &var) { if(pass==RENAME) { - map::const_iterator i = staging_block.variables.find(var.name); + auto i = staging_block.variables.find(var.name); if(i!=staging_block.variables.end()) var.name = i->second->name; } @@ -258,12 +243,6 @@ void InlineContentInjector::visit(Return &ret) } -FunctionInliner::FunctionInliner(): - current_function(0), - r_any_inlined(false), - r_inlined_here(false) -{ } - bool FunctionInliner::apply(Stage &s) { stage = &s; @@ -289,7 +268,7 @@ void FunctionInliner::visit(Block &block) { SetForScope set_block(current_block, &block); SetForScope::iterator> save_insert_point(insert_point, block.body.begin()); - for(NodeList::iterator i=block.body.begin(); (!r_inlined_here && i!=block.body.end()); ++i) + for(auto i=block.body.begin(); (!r_inlined_here && i!=block.body.end()); ++i) { insert_point = i; (*i)->visit(*this); @@ -298,7 +277,7 @@ void FunctionInliner::visit(Block &block) void FunctionInliner::visit(FunctionCall &call) { - for(NodeArray::iterator i=call.arguments.begin(); (!r_inlined_here && i!=call.arguments.end()); ++i) + for(auto i=call.arguments.begin(); (!r_inlined_here && i!=call.arguments.end()); ++i) visit(*i); if(r_inlined_here) @@ -349,28 +328,18 @@ void FunctionInliner::visit(Iteration &iter) } -ExpressionInliner::ExpressionInliner(): - r_ref_info(0), - r_trivial(false), - access_read(true), - access_write(false), - iteration_init(false), - iteration_body(0), - r_oper(0) -{ } - bool ExpressionInliner::apply(Stage &s) { s.content.visit(*this); bool any_inlined = false; - for(list::iterator i=expressions.begin(); i!=expressions.end(); ++i) - if(i->expression && (i->trivial || i->uses.size()==1)) + for(ExpressionInfo &e: expressions) + if(e.expression && (e.trivial || e.uses.size()==1)) { - for(vector::iterator j=i->uses.begin(); j!=i->uses.end(); ++j) - if(!j->blocked) + for(ExpressionUse &u: e.uses) + if(!u.blocked) { - *j->reference = i->expression->clone(); + *u.reference = e.expression->clone(); any_inlined = true; } } @@ -413,7 +382,7 @@ void ExpressionInliner::visit(VariableReference &var) { if(var.declaration && access_read) { - map::iterator i = assignments.find(var.declaration); + auto i = assignments.find(var.declaration); if(i!=assignments.end()) r_ref_info = i->second; } @@ -459,7 +428,7 @@ void ExpressionInliner::visit(Assignment &assign) r_trivial = true; visit(assign.right); - map::iterator i = assignments.find(assign.target); + auto i = assignments.find(assign.target); if(i!=assignments.end()) { if(iteration_body && i->second->expression) @@ -467,9 +436,9 @@ void ExpressionInliner::visit(Assignment &assign) /* Block inlining into previous references within the iteration statement. On iterations after the first they would refer to the assignment within the iteration. */ - for(vector::iterator j=i->second->uses.begin(); j!=i->second->uses.end(); ++j) - for(Block *k=j->ref_scope; (!j->blocked && k); k=k->parent) - j->blocked = (k==iteration_body); + for(ExpressionUse &u: i->second->uses) + for(Block *k=u.ref_scope; (!u.blocked && k); k=k->parent) + u.blocked = (k==iteration_body); } expressions.push_back(ExpressionInfo()); @@ -510,8 +479,8 @@ void ExpressionInliner::visit(VariableDeclaration &var) bool constant = var.constant; if(constant && var.layout) { - for(vector::const_iterator i=var.layout->qualifiers.begin(); (constant && i!=var.layout->qualifiers.end()); ++i) - constant = (i->name!="constant_id"); + constant = !any_of(var.layout->qualifiers.begin(), var.layout->qualifiers.end(), + [](const Layout::Qualifier &q){ return q.name=="constant_id"; }); } /* Only inline global variables if they're constant and have trivial @@ -551,6 +520,209 @@ 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) + { + 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, 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(); + + kvp.second.decl_scope->body.insert(kvp.second.insert_point, var); + + for(RefPtr *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 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 &expr) +{ + r_aggregate_ref = 0; + expr->visit(*this); + if(r_aggregate_ref && r_reference.chain_len==1) + { + 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; +} + +void AggregateDismantler::visit(VariableReference &var) +{ + if(composite_reference) + 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; + } +} + +void AggregateDismantler::visit_composite(RefPtr &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); + } + + unsigned index = 0x3F; + if(Literal *literal_subscript = dynamic_cast(binary.right.get())) + if(literal_subscript->value.check_type()) + index = literal_subscript->value.value(); + 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 + { + 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(var.type_declaration)) + { + const FunctionCall *init_call = dynamic_cast(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 &s: strct->members.body) + { + if(const VariableDeclaration *mem_decl = dynamic_cast(s.get())) + { + AggregateMember member; + member.declaration = mem_decl; + member.index = i; + if(init_call) + member.initializer = init_call->arguments[i]; + aggre.members.push_back(member); + } + ++i; + } + } + } + else if(const Literal *literal_size = dynamic_cast(var.array_size.get())) + { + if(literal_size->value.check_type()) + { + Aggregate &aggre = aggregates[&var]; + aggre.declaration = &var; + aggre.decl_scope = current_block; + aggre.insert_point = insert_point; + + int size = literal_size->value.value(); + for(int i=0; i T ConstantFolder::evaluate_logical(char oper, T left, T right) { @@ -894,7 +1066,7 @@ ConstantConditionEliminator::ConstantStatus ConstantConditionEliminator::check_c void ConstantConditionEliminator::visit(Block &block) { SetForScope set_block(current_block, &block); - for(NodeList::iterator i=block.body.begin(); i!=block.body.end(); ++i) + for(auto i=block.body.begin(); i!=block.body.end(); ++i) { insert_point = i; (*i)->visit(*this); @@ -910,6 +1082,27 @@ void ConstantConditionEliminator::visit(RefPtr &expr) r_ternary_result = 0; } +void ConstantConditionEliminator::visit(UnaryExpression &unary) +{ + if(unary.oper->token[1]=='+' || unary.oper->token[1]=='-') + if(const VariableReference *var = dynamic_cast(unary.expression.get())) + { + auto i = current_block->variables.find(var->name); + r_external_side_effects = (i==current_block->variables.end() || i->second!=var->declaration); + return; + } + + TraversingVisitor::visit(unary); +} + +void ConstantConditionEliminator::visit(Assignment &assign) +{ + auto i = find_if(current_block->variables, [&assign](const pair &kvp){ return kvp.second==assign.target.declaration; }); + if(i==current_block->variables.end()) + r_external_side_effects = true; + TraversingVisitor::visit(assign); +} + void ConstantConditionEliminator::visit(TernaryExpression &ternary) { ConstantStatus result = check_constant_condition(*ternary.condition); @@ -919,6 +1112,12 @@ void ConstantConditionEliminator::visit(TernaryExpression &ternary) r_ternary_result = 0; } +void ConstantConditionEliminator::visit(FunctionCall &call) +{ + r_external_side_effects = true; + TraversingVisitor::visit(call); +} + void ConstantConditionEliminator::visit(Conditional &cond) { ConstantStatus result = check_constant_condition(*cond.condition); @@ -931,7 +1130,11 @@ void ConstantConditionEliminator::visit(Conditional &cond) return; } + r_external_side_effects = false; TraversingVisitor::visit(cond); + + if(cond.body.body.empty() && cond.else_body.body.empty() && !r_external_side_effects) + nodes_to_remove.insert(&cond); } void ConstantConditionEliminator::visit(Iteration &iter) @@ -946,14 +1149,13 @@ void ConstantConditionEliminator::visit(Iteration &iter) } } + r_external_side_effects = false; TraversingVisitor::visit(iter); + if(iter.body.body.empty() && !r_external_side_effects) + nodes_to_remove.insert(&iter); } -UnreachableCodeRemover::UnreachableCodeRemover(): - reachable(true) -{ } - bool UnreachableCodeRemover::apply(Stage &stage) { stage.content.visit(*this); @@ -963,7 +1165,7 @@ bool UnreachableCodeRemover::apply(Stage &stage) void UnreachableCodeRemover::visit(Block &block) { - NodeList::iterator i = block.body.begin(); + auto i = block.body.begin(); for(; (reachable && i!=block.body.end()); ++i) (*i)->visit(*this); for(; i!=block.body.end(); ++i) @@ -1047,45 +1249,34 @@ void UnusedTypeRemover::visit(FunctionDeclaration &func) } -UnusedVariableRemover::UnusedVariableRemover(): - stage(0), - interface_block(0), - r_assignment(0), - assignment_target(false), - r_side_effects(false), - in_struct(false), - composite_reference(false), - in_loop(0) -{ } - bool UnusedVariableRemover::apply(Stage &s) { stage = &s; s.content.visit(*this); - for(list::const_iterator i=assignments.begin(); i!=assignments.end(); ++i) - if(i->used_by.empty()) - unused_nodes.insert(i->node); + for(const AssignmentInfo &a: assignments) + if(a.used_by.empty()) + unused_nodes.insert(a.node); - for(BlockVariableMap::const_iterator i=variables.begin(); i!=variables.end(); ++i) + for(const auto &kvp: variables) { - if(i->second.output) + if(kvp.second.output) { /* The last visible assignments of output variables are used by the next stage or the API. */ - for(vector::const_iterator j=i->second.assignments.begin(); j!=i->second.assignments.end(); ++j) - unused_nodes.erase((*j)->node); + for(AssignmentInfo *a: kvp.second.assignments) + unused_nodes.erase(a->node); } - if(!i->second.output && !i->second.referenced) + if(!kvp.second.output && !kvp.second.referenced) { // Don't remove variables from inside interface blocks. - if(!i->second.interface_block) - unused_nodes.insert(i->first); + if(!kvp.second.interface_block) + unused_nodes.insert(kvp.first); } - else if(i->second.interface_block) + else if(kvp.second.interface_block) // Interface blocks are kept if even one member is used. - unused_nodes.erase(i->second.interface_block); + unused_nodes.erase(kvp.second.interface_block); } NodeRemover().apply(s, unused_nodes); @@ -1100,17 +1291,17 @@ void UnusedVariableRemover::referenced(const Assignment::Target &target, Node &n if(!assignment_target) { bool loop_external = false; - for(vector::const_iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i) + for(AssignmentInfo *a: var_info.assignments) { bool covered = true; - for(unsigned j=0; (covered && j<(*i)->target.chain_len && jtarget.chain_len && j((*i)->target.chain[j]&0xC0); + Assignment::Target::ChainType type1 = static_cast(a->target.chain[j]&0xC0); Assignment::Target::ChainType type2 = static_cast(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 = (*i)->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) @@ -1121,13 +1312,13 @@ void UnusedVariableRemover::referenced(const Assignment::Target &target, Node &n covered as true */ } else - covered = ((*i)->target.chain[j]==target.chain[j]); + covered = (type1==type2 && (index1==index2 || index1==0x3F || index2==0x3F)); } if(covered) { - (*i)->used_by.push_back(&node); - if((*i)->in_loopused_by.push_back(&node); + if(a->in_looptype==Stage::GEOMETRY && call.name=="EmitVertex") { - for(map::const_iterator i=variables.begin(); i!=variables.end(); ++i) - if(i->second.output) - referenced(i->first, call); + for(const auto &kvp: variables) + if(kvp.second.output) + referenced(kvp.first, call); } } @@ -1326,24 +1517,24 @@ void UnusedVariableRemover::visit(InterfaceBlock &iface) void UnusedVariableRemover::merge_variables(const BlockVariableMap &other_vars) { - for(BlockVariableMap::const_iterator i=other_vars.begin(); i!=other_vars.end(); ++i) + for(const auto &kvp: other_vars) { - BlockVariableMap::iterator j = variables.find(i->first); + auto j = variables.find(kvp.first); if(j!=variables.end()) { /* The merged blocks started as copies of each other so any common assignments must be in the beginning. */ unsigned k = 0; - for(; (ksecond.assignments.size() && ksecond.assignments.size()); ++k) - if(i->second.assignments[k]!=j->second.assignments[k]) + for(; (ksecond.assignments.size()); ++k) + if(kvp.second.assignments[k]!=j->second.assignments[k]) break; // Remaining assignments are unique to each block; merge them. - j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin()+k, i->second.assignments.end()); - j->second.referenced |= i->second.referenced; + j->second.assignments.insert(j->second.assignments.end(), kvp.second.assignments.begin()+k, kvp.second.assignments.end()); + j->second.referenced |= kvp.second.referenced; } else - variables.insert(*i); + variables.insert(kvp); } } @@ -1354,17 +1545,17 @@ void UnusedVariableRemover::visit(FunctionDeclaration &func) BlockVariableMap saved_vars = variables; // Assignments from other functions should not be visible. - for(BlockVariableMap::iterator i=variables.begin(); i!=variables.end(); ++i) - i->second.assignments.resize(i->second.initialized); + for(auto &kvp: variables) + kvp.second.assignments.resize(kvp.second.initialized); TraversingVisitor::visit(func); swap(variables, saved_vars); merge_variables(saved_vars); /* Always treat function parameters as referenced. Removing unused parameters is not currently supported. */ - for(NodeArray::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i) + for(const RefPtr &p: func.parameters) { - BlockVariableMap::iterator j = variables.find(i->get()); + auto j = variables.find(p.get()); if(j!=variables.end()) j->second.referenced = true; } @@ -1397,8 +1588,8 @@ void UnusedVariableRemover::visit(Iteration &iter) /* Visit the external references of the loop again to record assignments done in the loop as used. */ - for(vector::const_iterator i=saved_refs.begin(); i!=saved_refs.end(); ++i) - (*i)->visit(*this); + for(Node *n: saved_refs) + n->visit(*this); /* Merge assignments from the iteration, without clearing previous state. Further analysis is needed to determine which parts of the iteration body