]> git.tdb.fi Git - libs/gl.git/blobdiff - source/glsl/optimize.cpp
Use default member initializers for simple types
[libs/gl.git] / source / glsl / optimize.cpp
index b1201e9fb84cec84c8a7236121963f982cfa43cb..8c586e7ad886cf433c4c5cadf6315783980804a6 100644 (file)
@@ -1,3 +1,4 @@
+#include <msp/core/algorithm.h>
 #include <msp/core/raii.h>
 #include <msp/strings/format.h>
 #include <msp/strings/utils.h>
@@ -10,10 +11,6 @@ namespace Msp {
 namespace GL {
 namespace SL {
 
-ConstantSpecializer::ConstantSpecializer():
-       values(0)
-{ }
-
 void ConstantSpecializer::apply(Stage &stage, const map<string, int> &v)
 {
        values = &v;
@@ -26,20 +23,19 @@ void ConstantSpecializer::visit(VariableDeclaration &var)
        if(var.layout)
        {
                vector<Layout::Qualifier> &qualifiers = var.layout->qualifiers;
-               for(vector<Layout::Qualifier>::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<string, int>::const_iterator i = values->find(var.name);
+               auto i = values->find(var.name);
                if(i!=values->end())
                {
                        RefPtr<Literal> 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<VariableDeclaration>::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<VariableDeclaration> &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<Statement>::iterator &ins_pt, FunctionCall &call)
 {
        source_func = call.declaration->definition;
@@ -141,9 +126,9 @@ string InlineContentInjector::apply(Stage &stage, FunctionDeclaration &target_fu
 
        vector<RefPtr<VariableDeclaration> > params;
        params.reserve(source_func->parameters.size());
-       for(NodeArray<VariableDeclaration>::iterator i=source_func->parameters.begin(); i!=source_func->parameters.end(); ++i)
+       for(const RefPtr<VariableDeclaration> &p: source_func->parameters)
        {
-               RefPtr<VariableDeclaration> var = (*i)->clone();
+               RefPtr<VariableDeclaration> var = p->clone();
                var->interface.clear();
 
                SetForScope<Pass> set_pass(pass, RENAME);
@@ -153,12 +138,12 @@ string InlineContentInjector::apply(Stage &stage, FunctionDeclaration &target_fu
                params.push_back(var);
        }
 
-       for(NodeList<Statement>::iterator i=source_func->body.body.begin(); i!=source_func->body.body.end(); ++i)
+       for(const RefPtr<Statement> &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<Pass> set_pass(pass, RENAME);
                r_inlined_statement->visit(*this);
@@ -194,7 +179,7 @@ void InlineContentInjector::visit(VariableReference &var)
 {
        if(pass==RENAME)
        {
-               map<string, VariableDeclaration *>::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<Block *> set_block(current_block, &block);
        SetForScope<NodeList<Statement>::iterator> save_insert_point(insert_point, block.body.begin());
-       for(NodeList<Statement>::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<Expression>::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,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<Expression> &ptr)
-{
-       ptr = expr.clone();
-       r_any_inlined = true;
-}
-
-void ExpressionInliner::visit(Block &block)
-{
-       TraversingVisitor::visit(block);
 
-       for(map<string, VariableDeclaration *>::iterator i=block.variables.begin(); i!=block.variables.end(); ++i)
-       {
-               map<Assignment::Target, ExpressionInfo>::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<Assignment::Target, ExpressionInfo>::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<Expression> &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;
@@ -425,21 +380,11 @@ void ExpressionInliner::visit(RefPtr<Expression> &expr)
 
 void ExpressionInliner::visit(VariableReference &var)
 {
-       if(var.declaration)
+       if(var.declaration && access_read)
        {
-               map<Assignment::Target, ExpressionInfo>::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;
        }
 }
 
@@ -457,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;
 }
@@ -466,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;
@@ -475,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<Assignment::Target, ExpressionInfo>::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;
@@ -518,8 +479,8 @@ void ExpressionInliner::visit(VariableDeclaration &var)
        bool constant = var.constant;
        if(constant && var.layout)
        {
-               for(vector<Layout::Qualifier>::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
@@ -527,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;
        }
 }
 
@@ -646,8 +612,8 @@ void ConstantFolder::visit(RefPtr<Expression> &expr)
                literal->token = lexical_cast<string>(r_constant_value.value<unsigned>())+"u";
        else if(r_constant_value.check_type<float>())
        {
-               literal->token = lexical_cast<string>(r_constant_value.value<float>());
-               if(isnumrc(literal->token))
+               literal->token = lexical_cast<string>(r_constant_value.value<float>(), Fmt().precision(8));
+               if(literal->token.find('.')==string::npos && literal->token.find('e')==string::npos)
                        literal->token += ".0";
        }
        else
@@ -657,6 +623,7 @@ void ConstantFolder::visit(RefPtr<Expression> &expr)
        }
        literal->value = r_constant_value;
        expr = literal;
+       r_any_folded = true;
 }
 
 void ConstantFolder::visit(Literal &literal)
@@ -806,7 +773,7 @@ void ConstantFolder::visit(FunctionCall &call)
                const BasicTypeDeclaration *basic = dynamic_cast<const BasicTypeDeclaration *>(call.type);
                if(basic)
                {
-                       call.arguments[0]->visit(*this);
+                       visit(call.arguments[0]);
                        bool can_fold = r_constant;
                        r_constant = false;
                        if(!can_fold)
@@ -896,7 +863,7 @@ ConstantConditionEliminator::ConstantStatus ConstantConditionEliminator::check_c
 void ConstantConditionEliminator::visit(Block &block)
 {
        SetForScope<Block *> set_block(current_block, &block);
-       for(NodeList<Statement>::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);
@@ -912,6 +879,27 @@ void ConstantConditionEliminator::visit(RefPtr<Expression> &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<const VariableReference *>(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<string, VariableDeclaration *> &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);
@@ -921,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);
@@ -933,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)
@@ -948,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);
@@ -965,7 +962,7 @@ bool UnreachableCodeRemover::apply(Stage &stage)
 
 void UnreachableCodeRemover::visit(Block &block)
 {
-       NodeList<Statement>::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)
@@ -1049,45 +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),
-       in_loop(0)
-{ }
-
 bool UnusedVariableRemover::apply(Stage &s)
 {
        stage = &s;
        s.content.visit(*this);
 
-       for(list<AssignmentInfo>::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<AssignmentInfo *>::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);
@@ -1102,16 +1088,16 @@ void UnusedVariableRemover::referenced(const Assignment::Target &target, Node &n
        if(!assignment_target)
        {
                bool loop_external = false;
-               for(vector<AssignmentInfo *>::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 && j<target.chain_len); ++j)
+                       for(unsigned j=0; (covered && j<a->target.chain_len && j<target.chain_len); ++j)
                        {
-                               Assignment::Target::ChainType type1 = static_cast<Assignment::Target::ChainType>((*i)->target.chain[j]&0xC0);
+                               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);
                                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;
@@ -1123,13 +1109,13 @@ 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);
-                               if((*i)->in_loop<in_loop)
+                               a->used_by.push_back(&node);
+                               if(a->in_loop<in_loop)
                                        loop_external = true;
                        }
                }
@@ -1245,9 +1231,9 @@ void UnusedVariableRemover::visit(FunctionCall &call)
 
        if(stage->type==Stage::GEOMETRY && call.name=="EmitVertex")
        {
-               for(map<Statement *, VariableInfo>::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);
        }
 }
 
@@ -1262,7 +1248,7 @@ void UnusedVariableRemover::record_assignment(const Assignment::Target &target,
        /* 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; i<var_info.assignments.size(); ++i)
+       for(unsigned i=0; i<var_info.assignments.size(); )
        {
                const Assignment::Target &t = var_info.assignments[i]->target;
 
@@ -1328,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(; (k<i->second.assignments.size() && k<j->second.assignments.size()); ++k)
-                               if(i->second.assignments[k]!=j->second.assignments[k])
+                       for(; (k<kvp.second.assignments.size() && k<j->second.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);
        }
 }
 
@@ -1356,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<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
+       for(const RefPtr<VariableDeclaration> &p: func.parameters)
        {
-               BlockVariableMap::iterator j = variables.find(i->get());
+               auto j = variables.find(p.get());
                if(j!=variables.end())
                        j->second.referenced = true;
        }
@@ -1399,8 +1385,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<Node *>::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