X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fglsl%2Foptimize.cpp;h=8c586e7ad886cf433c4c5cadf6315783980804a6;hp=bdaced5c46029299e531b8f3cdbd5055651bc539;hb=38712d8ecc57d043a2419ffbaeeb57f7a6586f14;hpb=72a02f2f3f1c454aa670b256262d7bc0541222e3 diff --git a/source/glsl/optimize.cpp b/source/glsl/optimize.cpp index bdaced5c..8c586e7a 100644 --- a/source/glsl/optimize.cpp +++ b/source/glsl/optimize.cpp @@ -1,5 +1,7 @@ +#include #include #include +#include #include "optimize.h" #include "reflect.h" @@ -9,10 +11,6 @@ namespace Msp { namespace GL { namespace SL { -ConstantSpecializer::ConstantSpecializer(): - values(0) -{ } - void ConstantSpecializer::apply(Stage &stage, const map &v) { values = &v; @@ -25,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; @@ -58,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; @@ -84,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) @@ -118,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; @@ -140,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); @@ -152,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); @@ -193,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; } @@ -257,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; @@ -288,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); @@ -297,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) @@ -348,75 +328,51 @@ void FunctionInliner::visit(Iteration &iter) } -ExpressionInliner::ExpressionInliner(): - r_ref_info(0), - r_any_inlined(false), - r_trivial(false), - mutating(false), - iteration_init(false), - iteration_body(0), - r_oper(0) -{ } - bool ExpressionInliner::apply(Stage &s) { s.content.visit(*this); - return r_any_inlined; -} - -void ExpressionInliner::inline_expression(Expression &expr, RefPtr &ptr) -{ - ptr = expr.clone(); - r_any_inlined = true; -} - -void ExpressionInliner::visit(Block &block) -{ - TraversingVisitor::visit(block); - for(map::iterator i=block.variables.begin(); i!=block.variables.end(); ++i) - { - map::iterator j = expressions.lower_bound(i->second); - for(; (j!=expressions.end() && j->first.declaration==i->second); ) + bool any_inlined = false; + for(ExpressionInfo &e: expressions) + if(e.expression && (e.trivial || e.uses.size()==1)) { - if(j->second.expression && j->second.inline_point) - inline_expression(*j->second.expression, *j->second.inline_point); - - expressions.erase(j++); + for(ExpressionUse &u: e.uses) + if(!u.blocked) + { + *u.reference = e.expression->clone(); + any_inlined = true; + } } - } - /* Expressions assigned in this block may depend on local variables of the - block. If this is a conditionally executed block, the assignments might not - always happen. Mark the expressions as not available to any outer blocks. */ - for(map::iterator i=expressions.begin(); i!=expressions.end(); ++i) - if(i->second.assign_scope==&block) - i->second.available = false; + return any_inlined; } void ExpressionInliner::visit(RefPtr &expr) { r_ref_info = 0; expr->visit(*this); - if(r_ref_info && r_ref_info->expression && r_ref_info->available) + if(r_ref_info && r_ref_info->expression) { + ExpressionUse use; + use.reference = &expr; + use.ref_scope = current_block; + use.blocked = access_write; + if(iteration_body && !r_ref_info->trivial) { - /* Don't inline non-trivial expressions which were assigned outside - an iteration statement. The iteration may run multiple times, which + /* Block inlining of non-trivial expressions assigned outside an + iteration statement. The iteration may run multiple times, which would cause the expression to also be evaluated multiple times. */ - Block *i = r_ref_info->assign_scope; - for(; (i && i!=iteration_body); i=i->parent) ; - if(!i) - return; + for(Block *i=iteration_body->parent; (!use.blocked && i); i=i->parent) + use.blocked = (i==r_ref_info->assign_scope); } - if(r_ref_info->trivial) - inline_expression(*r_ref_info->expression, expr); - else - /* Record the inline point for a non-trivial expression but don't - inline it yet. It might turn out it shouldn't be inlined after all. */ - r_ref_info->inline_point = &expr; + /* Block inlining assignments from from inner scopes. The assignment may + depend on local variables of that scope or may not always be executed. */ + for(Block *i=r_ref_info->assign_scope->parent; (!use.blocked && i); i=i->parent) + use.blocked = (i==current_block); + + r_ref_info->uses.push_back(use); } r_oper = expr->oper; r_ref_info = 0; @@ -424,21 +380,11 @@ void ExpressionInliner::visit(RefPtr &expr) void ExpressionInliner::visit(VariableReference &var) { - if(var.declaration) + if(var.declaration && access_read) { - map::iterator i = expressions.find(var.declaration); - if(i!=expressions.end()) - { - /* If a non-trivial expression is referenced multiple times, don't - inline it. */ - if(i->second.inline_point && !i->second.trivial) - i->second.expression = 0; - /* Mutating expressions are analogous to self-referencing assignments - and prevent inlining. */ - if(mutating) - i->second.expression = 0; - r_ref_info = &i->second; - } + auto i = assignments.find(var.declaration); + if(i!=assignments.end()) + r_ref_info = i->second; } } @@ -456,7 +402,7 @@ void ExpressionInliner::visit(Swizzle &swizzle) void ExpressionInliner::visit(UnaryExpression &unary) { - SetFlag set_target(mutating, mutating || unary.oper->token[1]=='+' || unary.oper->token[1]=='-'); + SetFlag set_write(access_write, access_write || unary.oper->token[1]=='+' || unary.oper->token[1]=='-'); visit(unary.expression); r_trivial = false; } @@ -465,7 +411,7 @@ void ExpressionInliner::visit(BinaryExpression &binary) { visit(binary.left); { - SetFlag clear_target(mutating, false); + SetFlag clear_write(access_write, false); visit(binary.right); } r_trivial = false; @@ -474,21 +420,37 @@ void ExpressionInliner::visit(BinaryExpression &binary) void ExpressionInliner::visit(Assignment &assign) { { - SetFlag set_target(mutating); + SetFlag set_read(access_read, assign.oper->token[0]!='='); + SetFlag set_write(access_write); visit(assign.left); } r_oper = 0; + r_trivial = true; visit(assign.right); - map::iterator i = expressions.find(assign.target); - if(i!=expressions.end()) + auto i = assignments.find(assign.target); + if(i!=assignments.end()) { - /* Self-referencing assignments can't be inlined without additional - work. Just clear any previous expression. */ - i->second.expression = (assign.self_referencing ? 0 : assign.right.get()); - i->second.assign_scope = current_block; - i->second.inline_point = 0; - i->second.available = true; + if(iteration_body && i->second->expression) + { + /* Block inlining into previous references within the iteration + statement. On iterations after the first they would refer to the + assignment within the iteration. */ + 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()); + ExpressionInfo &info = expressions.back(); + info.target = assign.target; + // Self-referencing assignments can't be inlined without additional work. + if(!assign.self_referencing) + info.expression = assign.right; + info.assign_scope = current_block; + info.trivial = r_trivial; + + i->second = &info; } r_trivial = false; @@ -517,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 @@ -526,12 +488,17 @@ void ExpressionInliner::visit(VariableDeclaration &var) analyze and non-trivial expressions could be expensive to inline. */ if((current_block->parent || (constant && r_trivial)) && var.interface.empty()) { - ExpressionInfo &info = expressions[&var]; + expressions.push_back(ExpressionInfo()); + ExpressionInfo &info = expressions.back(); + info.target = &var; /* Assume variables declared in an iteration initialization statement will have their values change throughout the iteration. */ - info.expression = (iteration_init ? 0 : var.init_expression.get()); + if(!iteration_init) + info.expression = var.init_expression; info.assign_scope = current_block; info.trivial = r_trivial; + + assignments[&var] = &info; } } @@ -553,18 +520,6 @@ void ExpressionInliner::visit(Iteration &iter) } -BasicTypeDeclaration::Kind ConstantFolder::get_value_kind(const Variant &value) -{ - if(value.check_type()) - return BasicTypeDeclaration::BOOL; - else if(value.check_type()) - return BasicTypeDeclaration::INT; - else if(value.check_type()) - return BasicTypeDeclaration::FLOAT; - else - return BasicTypeDeclaration::VOID; -} - template T ConstantFolder::evaluate_logical(char oper, T left, T right) { @@ -603,6 +558,31 @@ T ConstantFolder::evaluate_arithmetic(char oper, T left, T right) } } +template +T ConstantFolder::evaluate_int_special_op(char oper, T left, T right) +{ + switch(oper) + { + case '%': return left%right; + case '<': return left<': return left>>right; + default: return T(); + } +} + +template +void ConstantFolder::convert_to_result(const Variant &value) +{ + if(value.check_type()) + set_result(static_cast(value.value())); + else if(value.check_type()) + set_result(static_cast(value.value())); + else if(value.check_type()) + set_result(static_cast(value.value())); + else if(value.check_type()) + set_result(static_cast(value.value())); +} + void ConstantFolder::set_result(const Variant &value, bool literal) { r_constant_value = value; @@ -623,22 +603,27 @@ void ConstantFolder::visit(RefPtr &expr) if(!r_constant || r_literal || r_uses_iter_var) return; - BasicTypeDeclaration::Kind kind = get_value_kind(r_constant_value); - if(kind==BasicTypeDeclaration::VOID) + RefPtr literal = new Literal; + if(r_constant_value.check_type()) + literal->token = (r_constant_value.value() ? "true" : "false"); + else if(r_constant_value.check_type()) + literal->token = lexical_cast(r_constant_value.value()); + else if(r_constant_value.check_type()) + literal->token = lexical_cast(r_constant_value.value())+"u"; + else if(r_constant_value.check_type()) + { + literal->token = lexical_cast(r_constant_value.value(), Fmt().precision(8)); + if(literal->token.find('.')==string::npos && literal->token.find('e')==string::npos) + literal->token += ".0"; + } + else { r_constant = false; return; } - - RefPtr literal = new Literal; - if(kind==BasicTypeDeclaration::BOOL) - literal->token = (r_constant_value.value() ? "true" : "false"); - else if(kind==BasicTypeDeclaration::INT) - literal->token = lexical_cast(r_constant_value.value()); - else if(kind==BasicTypeDeclaration::FLOAT) - literal->token = lexical_cast(r_constant_value.value()); literal->value = r_constant_value; expr = literal; + r_any_folded = true; } void ConstantFolder::visit(Literal &literal) @@ -678,25 +663,27 @@ void ConstantFolder::visit(UnaryExpression &unary) if(!can_fold) return; - BasicTypeDeclaration::Kind kind = get_value_kind(r_constant_value); - char oper = unary.oper->token[0]; char oper2 = unary.oper->token[1]; if(oper=='!') { - if(kind==BasicTypeDeclaration::BOOL) + if(r_constant_value.check_type()) set_result(!r_constant_value.value()); } else if(oper=='~') { - if(kind==BasicTypeDeclaration::INT) + if(r_constant_value.check_type()) set_result(~r_constant_value.value()); + else if(r_constant_value.check_type()) + set_result(~r_constant_value.value()); } else if(oper=='-' && !oper2) { - if(kind==BasicTypeDeclaration::INT) + if(r_constant_value.check_type()) set_result(-r_constant_value.value()); - else if(kind==BasicTypeDeclaration::FLOAT) + else if(r_constant_value.check_type()) + set_result(-r_constant_value.value()); + else if(r_constant_value.check_type()) set_result(-r_constant_value.value()); } } @@ -716,53 +703,54 @@ void ConstantFolder::visit(BinaryExpression &binary) if(!can_fold) return; - BasicTypeDeclaration::Kind left_kind = get_value_kind(left_value); - BasicTypeDeclaration::Kind right_kind = get_value_kind(r_constant_value); // Currently only expressions with both sides of equal types are handled. - if(left_kind!=right_kind) + if(!left_value.check_same_type(r_constant_value)) return; char oper = binary.oper->token[0]; char oper2 = binary.oper->token[1]; if(oper=='&' || oper=='|' || oper=='^') { - if(oper2==oper && left_kind==BasicTypeDeclaration::BOOL) + if(oper2==oper && left_value.check_type()) set_result(evaluate_logical(oper, left_value.value(), r_constant_value.value())); - else if(!oper2 && left_kind==BasicTypeDeclaration::INT) + else if(!oper2 && left_value.check_type()) set_result(evaluate_logical(oper, left_value.value(), r_constant_value.value())); + else if(!oper2 && left_value.check_type()) + set_result(evaluate_logical(oper, left_value.value(), r_constant_value.value())); } else if((oper=='<' || oper=='>') && oper2!=oper) { - if(left_kind==BasicTypeDeclaration::INT) + if(left_value.check_type()) set_result(evaluate_relation(binary.oper->token, left_value.value(), r_constant_value.value())); - else if(left_kind==BasicTypeDeclaration::FLOAT) + else if(left_value.check_type()) + set_result(evaluate_relation(binary.oper->token, left_value.value(), r_constant_value.value())); + else if(left_value.check_type()) set_result(evaluate_relation(binary.oper->token, left_value.value(), r_constant_value.value())); } else if((oper=='=' || oper=='!') && oper2=='=') { - if(left_kind==BasicTypeDeclaration::INT) + if(left_value.check_type()) set_result((left_value.value()==r_constant_value.value()) == (oper=='=')); - if(left_kind==BasicTypeDeclaration::FLOAT) + else if(left_value.check_type()) + set_result((left_value.value()==r_constant_value.value()) == (oper=='=')); + else if(left_value.check_type()) set_result((left_value.value()==r_constant_value.value()) == (oper=='=')); } else if(oper=='+' || oper=='-' || oper=='*' || oper=='/') { - if(left_kind==BasicTypeDeclaration::INT) + if(left_value.check_type()) set_result(evaluate_arithmetic(oper, left_value.value(), r_constant_value.value())); - else if(left_kind==BasicTypeDeclaration::FLOAT) + else if(left_value.check_type()) + set_result(evaluate_arithmetic(oper, left_value.value(), r_constant_value.value())); + else if(left_value.check_type()) set_result(evaluate_arithmetic(oper, left_value.value(), r_constant_value.value())); } else if(oper=='%' || ((oper=='<' || oper=='>') && oper2==oper)) { - if(left_kind!=BasicTypeDeclaration::INT) - return; - - if(oper=='%') - set_result(left_value.value()%r_constant_value.value()); - else if(oper=='<') - set_result(left_value.value()<()); - else if(oper=='>') - set_result(left_value.value()>>r_constant_value.value()); + if(left_value.check_type()) + set_result(evaluate_int_special_op(oper, left_value.value(), r_constant_value.value())); + else if(left_value.check_type()) + set_result(evaluate_int_special_op(oper, left_value.value(), r_constant_value.value())); } } @@ -780,6 +768,30 @@ void ConstantFolder::visit(TernaryExpression &ternary) void ConstantFolder::visit(FunctionCall &call) { + if(call.constructor && call.type && call.arguments.size()==1) + { + const BasicTypeDeclaration *basic = dynamic_cast(call.type); + if(basic) + { + visit(call.arguments[0]); + bool can_fold = r_constant; + r_constant = false; + if(!can_fold) + return; + + if(basic->kind==BasicTypeDeclaration::BOOL) + convert_to_result(r_constant_value); + else if(basic->kind==BasicTypeDeclaration::INT && basic->size==32 && basic->sign) + convert_to_result(r_constant_value); + else if(basic->kind==BasicTypeDeclaration::INT && basic->size==32 && !basic->sign) + convert_to_result(r_constant_value); + else if(basic->kind==BasicTypeDeclaration::FLOAT && basic->size==32) + convert_to_result(r_constant_value); + + return; + } + } + TraversingVisitor::visit(call); r_constant = false; } @@ -851,7 +863,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); @@ -867,6 +879,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); @@ -876,6 +909,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); @@ -888,7 +927,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) @@ -903,14 +946,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); @@ -920,7 +962,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) @@ -1004,44 +1046,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) -{ } - 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); @@ -1055,16 +1087,17 @@ void UnusedVariableRemover::referenced(const Assignment::Target &target, Node &n var_info.referenced = true; if(!assignment_target) { - for(vector::const_iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i) + bool loop_external = false; + 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); if(type1==Assignment::Target::SWIZZLE || type2==Assignment::Target::SWIZZLE) { - unsigned index1 = (*i)->target.chain[j]&0x3F; + 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; @@ -1076,11 +1109,19 @@ void UnusedVariableRemover::referenced(const Assignment::Target &target, Node &n covered as true */ } else - covered = ((*i)->target.chain[j]==target.chain[j]); + covered = (a->target.chain[j]==target.chain[j]); } + if(covered) - (*i)->used_by.push_back(&node); + { + a->used_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); } } @@ -1202,11 +1243,12 @@ void UnusedVariableRemover::record_assignment(const Assignment::Target &target, AssignmentInfo &assign_info = assignments.back(); assign_info.node = &node; assign_info.target = target; + assign_info.in_loop = in_loop; /* An assignment to the target hides any assignments to the same target or its subfields. */ VariableInfo &var_info = variables[target.declaration]; - for(unsigned i=0; itarget; @@ -1272,24 +1314,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); } } @@ -1300,17 +1342,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; } @@ -1333,7 +1375,18 @@ void UnusedVariableRemover::visit(Conditional &cond) void UnusedVariableRemover::visit(Iteration &iter) { BlockVariableMap saved_vars = variables; - TraversingVisitor::visit(iter); + vector saved_refs; + swap(loop_ext_refs, saved_refs); + { + SetForScope set_loop(in_loop, in_loop+1); + TraversingVisitor::visit(iter); + } + swap(loop_ext_refs, saved_refs); + + /* Visit the external references of the loop again to record assignments + done in the loop as used. */ + 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