1 #include <msp/core/raii.h>
10 InlineableFunctionLocator::InlineableFunctionLocator():
14 void InlineableFunctionLocator::visit(FunctionCall &call)
16 FunctionDeclaration *def = call.declaration;
18 def = def->definition;
22 unsigned &count = refcounts[def];
24 if(count>1 || def==in_function)
25 inlineable.erase(def);
28 TraversingVisitor::visit(call);
31 void InlineableFunctionLocator::visit(FunctionDeclaration &func)
33 unsigned &count = refcounts[func.definition];
34 if(!count && func.parameters.empty())
35 inlineable.insert(func.definition);
37 SetForScope<FunctionDeclaration *> set(in_function, &func);
38 TraversingVisitor::visit(func);
42 void InlineDependencyCollector::visit(VariableReference &var)
46 dependencies.insert(var.declaration);
47 var.declaration->visit(*this);
51 void InlineDependencyCollector::visit(InterfaceBlockReference &iface)
55 dependencies.insert(iface.declaration);
56 iface.declaration->visit(*this);
60 void InlineDependencyCollector::visit(FunctionCall &call)
63 dependencies.insert(call.declaration);
64 TraversingVisitor::visit(call);
67 void InlineDependencyCollector::visit(VariableDeclaration &var)
69 if(var.type_declaration)
71 dependencies.insert(var.type_declaration);
72 var.type_declaration->visit(*this);
77 FunctionInliner::FunctionInliner():
83 bool FunctionInliner::apply(Stage &s)
86 inlineable = InlineableFunctionLocator().apply(s);
88 s.content.visit(*this);
92 void FunctionInliner::visit_and_inline(RefPtr<Expression> &ptr)
103 void FunctionInliner::visit(Block &block)
108 for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
116 void FunctionInliner::visit(UnaryExpression &unary)
118 visit_and_inline(unary.expression);
122 void FunctionInliner::visit(BinaryExpression &binary)
124 visit_and_inline(binary.left);
125 visit_and_inline(binary.right);
129 void FunctionInliner::visit(MemberAccess &memacc)
131 visit_and_inline(memacc.left);
135 void FunctionInliner::visit(FunctionCall &call)
137 for(NodeArray<Expression>::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
138 visit_and_inline(*i);
140 FunctionDeclaration *def = call.declaration;
142 def = def->definition;
144 if(def && inlineable.count(def))
150 NodeReorderer().apply(*stage, *current_function, InlineDependencyCollector().apply(*def));
156 void FunctionInliner::visit(VariableDeclaration &var)
158 if(var.init_expression)
159 visit_and_inline(var.init_expression);
163 void FunctionInliner::visit(FunctionDeclaration &func)
165 SetForScope<FunctionDeclaration *> set_func(current_function, &func);
166 TraversingVisitor::visit(func);
169 void FunctionInliner::visit(Return &ret)
171 TraversingVisitor::visit(ret);
174 inline_result = ret.expression->clone();
178 ConstantConditionEliminator::ConstantConditionEliminator():
182 void ConstantConditionEliminator::apply(Stage &stage)
184 stage.content.visit(*this);
185 NodeRemover().apply(stage, nodes_to_remove);
188 void ConstantConditionEliminator::visit(Block &block)
190 SetForScope<Block *> set_block(current_block, &block);
191 for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
197 for(map<string, VariableDeclaration *>::const_iterator i=block.variables.begin(); i!=block.variables.end(); ++i)
198 variable_values.erase(i->second);
201 void ConstantConditionEliminator::visit(UnaryExpression &unary)
203 if(VariableReference *var = dynamic_cast<VariableReference *>(unary.expression.get()))
204 if(unary.oper=="++" || unary.oper=="--")
205 variable_values.erase(var->declaration);
208 void ConstantConditionEliminator::visit(Assignment &assign)
210 variable_values.erase(assign.target_declaration);
213 void ConstantConditionEliminator::visit(VariableDeclaration &var)
215 bool constant = var.constant;
216 if(constant && var.layout)
218 for(vector<Layout::Qualifier>::const_iterator i=var.layout->qualifiers.begin(); (constant && i!=var.layout->qualifiers.end()); ++i)
219 constant = (i->name!="constant_id");
221 if((constant || current_block->parent) && var.init_expression)
222 variable_values[&var] = var.init_expression.get();
225 void ConstantConditionEliminator::visit(Conditional &cond)
229 ExpressionEvaluator eval(variable_values);
230 cond.condition->visit(eval);
231 if(eval.is_result_valid())
233 Block &block = (eval.get_result() ? cond.body : cond.else_body);
234 current_block->body.splice(insert_point, block.body);
235 nodes_to_remove.insert(&cond);
240 TraversingVisitor::visit(cond);
243 void ConstantConditionEliminator::visit(Iteration &iter)
249 /* If the loop condition is always false on the first iteration, the
250 entire loop can be removed */
251 if(iter.init_statement)
252 iter.init_statement->visit(*this);
253 ExpressionEvaluator eval(variable_values);
254 iter.condition->visit(eval);
255 if(eval.is_result_valid() && !eval.get_result())
257 nodes_to_remove.insert(&iter);
262 /* Record all assignments that occur inside the loop body so those
263 variables won't be considered as constant */
264 SetFlag set_record(record_only);
265 TraversingVisitor::visit(iter);
268 TraversingVisitor::visit(iter);
270 if(VariableDeclaration *init_decl = dynamic_cast<VariableDeclaration *>(iter.init_statement.get()))
271 variable_values.erase(init_decl);
275 UnusedVariableRemover::VariableInfo::VariableInfo():
277 conditionally_assigned(false),
282 UnusedVariableRemover::UnusedVariableRemover():
285 assignment_target(false),
286 assign_to_subscript(false)
289 bool UnusedVariableRemover::apply(Stage &stage)
291 variables.push_back(BlockVariableMap());
292 stage.content.visit(*this);
293 BlockVariableMap &global_variables = variables.back();
294 for(BlockVariableMap::iterator i=global_variables.begin(); i!=global_variables.end(); ++i)
296 if(i->first->interface=="out" && (stage.type==Stage::FRAGMENT || i->first->linked_declaration || !i->first->name.compare(0, 3, "gl_")))
298 if(!i->second.referenced)
300 unused_nodes.insert(i->first);
301 clear_assignments(i->second, true);
304 variables.pop_back();
306 NodeRemover().apply(stage, unused_nodes);
308 return !unused_nodes.empty();
311 void UnusedVariableRemover::visit(VariableReference &var)
313 map<VariableDeclaration *, Node *>::iterator i = aggregates.find(var.declaration);
314 if(i!=aggregates.end())
315 unused_nodes.erase(i->second);
317 if(var.declaration && !assignment_target)
319 VariableInfo &var_info = variables.back()[var.declaration];
320 clear_assignments(var_info, false);
321 var_info.referenced = true;
325 void UnusedVariableRemover::visit(InterfaceBlockReference &iface)
327 unused_nodes.erase(iface.declaration);
330 void UnusedVariableRemover::visit(MemberAccess &memacc)
332 TraversingVisitor::visit(memacc);
333 unused_nodes.erase(memacc.declaration);
336 void UnusedVariableRemover::visit(BinaryExpression &binary)
340 if(assignment_target)
341 assign_to_subscript = true;
342 binary.left->visit(*this);
343 SetForScope<bool> set(assignment_target, false);
344 binary.right->visit(*this);
347 TraversingVisitor::visit(binary);
350 void UnusedVariableRemover::visit(Assignment &assign)
353 assign_to_subscript = false;
354 SetForScope<bool> set(assignment_target, !assign.self_referencing);
355 assign.left->visit(*this);
357 assign.right->visit(*this);
358 assignment = &assign;
361 void UnusedVariableRemover::record_assignment(VariableDeclaration &var, Node &node, bool chained)
363 VariableInfo &var_info = variables.back()[&var];
365 clear_assignments(var_info, true);
366 var_info.assignments.push_back(&node);
367 var_info.conditionally_assigned = false;
370 void UnusedVariableRemover::clear_assignments(VariableInfo &var_info, bool mark_unused)
374 for(vector<Node *>::iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i)
375 unused_nodes.insert(*i);
377 var_info.assignments.clear();
380 void UnusedVariableRemover::visit(ExpressionStatement &expr)
383 TraversingVisitor::visit(expr);
384 if(assignment && assignment->target_declaration)
385 record_assignment(*assignment->target_declaration, expr, (assignment->self_referencing || assign_to_subscript));
388 void UnusedVariableRemover::visit(StructDeclaration &strct)
390 SetForScope<Node *> set(aggregate, &strct);
391 unused_nodes.insert(&strct);
392 TraversingVisitor::visit(strct);
395 void UnusedVariableRemover::visit(VariableDeclaration &var)
398 aggregates[&var] = aggregate;
401 variables.back()[&var].local = true;
402 if(var.init_expression)
403 record_assignment(var, *var.init_expression, false);
405 unused_nodes.erase(var.type_declaration);
406 TraversingVisitor::visit(var);
409 void UnusedVariableRemover::visit(InterfaceBlock &iface)
411 SetForScope<Node *> set(aggregate, &iface);
412 unused_nodes.insert(&iface);
413 TraversingVisitor::visit(iface);
416 void UnusedVariableRemover::visit(FunctionDeclaration &func)
418 variables.push_back(BlockVariableMap());
420 for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
422 func.body.visit(*this);
424 BlockVariableMap &block_variables = variables.back();
425 for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
426 i->second.conditionally_assigned = true;
427 for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
428 block_variables[i->get()].referenced = true;
429 merge_down_variables();
432 void UnusedVariableRemover::merge_down_variables()
434 BlockVariableMap &parent_variables = variables[variables.size()-2];
435 BlockVariableMap &block_variables = variables.back();
436 for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
440 if(!i->second.referenced)
441 unused_nodes.insert(i->first);
442 clear_assignments(i->second, i->first->interface!="out");
446 BlockVariableMap::iterator j = parent_variables.find(i->first);
447 if(j==parent_variables.end())
448 parent_variables.insert(*i);
451 if(i->second.referenced || !i->second.conditionally_assigned)
452 clear_assignments(j->second, !i->second.referenced);
453 j->second.conditionally_assigned = i->second.conditionally_assigned;
454 j->second.referenced |= i->second.referenced;
455 j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin(), i->second.assignments.end());
458 variables.pop_back();
461 void UnusedVariableRemover::visit(Conditional &cond)
463 cond.condition->visit(*this);
464 variables.push_back(BlockVariableMap());
465 cond.body.visit(*this);
467 BlockVariableMap if_variables;
468 swap(variables.back(), if_variables);
469 cond.else_body.visit(*this);
471 BlockVariableMap &else_variables = variables.back();
472 for(BlockVariableMap::iterator i=else_variables.begin(); i!=else_variables.end(); ++i)
474 BlockVariableMap::iterator j = if_variables.find(i->first);
475 if(j!=if_variables.end())
477 i->second.assignments.insert(i->second.assignments.end(), j->second.assignments.begin(), j->second.assignments.end());
478 i->second.conditionally_assigned |= j->second.conditionally_assigned;
479 if_variables.erase(j);
482 i->second.conditionally_assigned = true;
485 for(BlockVariableMap::iterator i=if_variables.begin(); i!=if_variables.end(); ++i)
487 i->second.conditionally_assigned = true;
488 else_variables.insert(*i);
491 merge_down_variables();
494 void UnusedVariableRemover::visit(Iteration &iter)
496 variables.push_back(BlockVariableMap());
497 TraversingVisitor::visit(iter);
499 BlockVariableMap &block_variables = variables.back();
500 for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
501 if(!i->second.local && i->second.referenced)
502 clear_assignments(i->second, false);
504 merge_down_variables();
508 bool UnusedFunctionRemover::apply(Stage &stage)
510 stage.content.visit(*this);
511 NodeRemover().apply(stage, unused_nodes);
512 return !unused_nodes.empty();
515 void UnusedFunctionRemover::visit(FunctionCall &call)
517 TraversingVisitor::visit(call);
519 unused_nodes.erase(call.declaration);
520 if(call.declaration && call.declaration->definition!=call.declaration)
521 used_definitions.insert(call.declaration->definition);
524 void UnusedFunctionRemover::visit(FunctionDeclaration &func)
526 TraversingVisitor::visit(func);
528 if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func))
529 unused_nodes.insert(&func);