if(!u.blocked)
{
*u.reference = e.expression->clone();
+ if(u.containing_expr)
+ u.containing_expr->expression = 0;
any_inlined = true;
}
}
ExpressionUse use;
use.reference = &expr;
use.ref_scope = current_block;
+ use.containing_expr = current_expr;
use.blocked = access_write || r_ref_info->blocked;
if(iteration_body && !r_ref_info->trivial)
SetFlag set_write(access_write);
visit(assign.left);
}
+
+ ExpressionInfo *info = nullptr;
+ auto i = assignments.find(assign.target.declaration);
+ if(i!=assignments.end())
+ {
+ info = &expressions.emplace_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;
+ }
+
r_oper = nullptr;
r_trivial = true;
+ SetForScope<ExpressionInfo *> set_expr(current_expr, info);
visit(assign.right);
- auto i = assignments.find(assign.target.declaration);
- if(i!=assignments.end())
+ if(info)
{
if(iteration_body && i->second && i->second->expression)
{
if(targets_overlap(i->first, assign.target))
i->second->blocked = true;
- ExpressionInfo &info = expressions.emplace_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;
-
- assignments[assign.target] = &info;
+ info->trivial = r_trivial;
+ assignments[assign.target] = info;
}
r_trivial = false;
void ExpressionInliner::visit(VariableDeclaration &var)
{
+ ExpressionInfo *info = nullptr;
+ if(var.interface.empty())
+ {
+ info = &expressions.emplace_back();
+ info->target = &var;
+ /* Assume variables declared in an iteration initialization statement
+ will have their values change throughout the iteration. */
+ if(!iteration_init)
+ info->expression = var.init_expression;
+ info->assign_scope = current_block;
+ }
+
+ SetForScope<ExpressionInfo *> set_expr(current_expr, info);
r_oper = nullptr;
r_trivial = true;
TraversingVisitor::visit(var);
- bool constant = var.constant;
- if(constant && var.layout)
+ if(info)
{
- constant = !any_of(var.layout->qualifiers.begin(), var.layout->qualifiers.end(),
- [](const Layout::Qualifier &q){ return q.name=="constant_id"; });
- }
+ bool constant = var.constant;
+ if(constant && var.layout)
+ {
+ 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
- initializers. Non-constant variables could change in ways which are hard to
- analyze and non-trivial expressions could be expensive to inline. */
- if((current_block->parent || (constant && r_trivial)) && var.interface.empty())
- {
- ExpressionInfo &info = expressions.emplace_back();
- info.target = &var;
- /* Assume variables declared in an iteration initialization statement
- will have their values change throughout the iteration. */
- if(!iteration_init)
- info.expression = var.init_expression;
- info.assign_scope = current_block;
- info.trivial = r_trivial;
+ /* Block global variables from being inlined unless it's a constant with
+ a trivial initializer. Non-constant variables could change in ways which
+ are hard to analyze and non-trivial expressions could be expensive to
+ inline. */
+ if(!current_block->parent && !(constant && r_trivial))
+ info->blocked = true;
- assignments[&var] = &info;
+ info->trivial = r_trivial;
+ assignments[&var] = info;
}
}