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),
290 bool UnusedVariableRemover::apply(Stage &stage)
292 variables.push_back(BlockVariableMap());
293 stage.content.visit(*this);
294 BlockVariableMap &global_variables = variables.back();
295 for(BlockVariableMap::iterator i=global_variables.begin(); i!=global_variables.end(); ++i)
297 if(i->first->interface=="out" && (stage.type==Stage::FRAGMENT || i->first->linked_declaration || !i->first->name.compare(0, 3, "gl_")))
299 if(!i->second.referenced)
301 unused_nodes.insert(i->first);
302 clear_assignments(i->second, true);
305 variables.pop_back();
307 NodeRemover().apply(stage, unused_nodes);
309 return !unused_nodes.empty();
312 void UnusedVariableRemover::visit(VariableReference &var)
314 map<VariableDeclaration *, Node *>::iterator i = aggregates.find(var.declaration);
315 if(i!=aggregates.end())
316 unused_nodes.erase(i->second);
318 if(var.declaration && !assignment_target)
320 VariableInfo &var_info = variables.back()[var.declaration];
321 clear_assignments(var_info, false);
322 var_info.referenced = true;
326 void UnusedVariableRemover::visit(InterfaceBlockReference &iface)
328 unused_nodes.erase(iface.declaration);
331 void UnusedVariableRemover::visit(MemberAccess &memacc)
333 TraversingVisitor::visit(memacc);
334 unused_nodes.erase(memacc.declaration);
337 void UnusedVariableRemover::visit(UnaryExpression &unary)
339 TraversingVisitor::visit(unary);
340 if(unary.oper=="++" || unary.oper=="--")
344 void UnusedVariableRemover::visit(BinaryExpression &binary)
348 if(assignment_target)
349 assign_to_subscript = true;
350 binary.left->visit(*this);
351 SetForScope<bool> set(assignment_target, false);
352 binary.right->visit(*this);
355 TraversingVisitor::visit(binary);
358 void UnusedVariableRemover::visit(Assignment &assign)
361 assign_to_subscript = false;
362 SetForScope<bool> set(assignment_target, !assign.self_referencing);
363 assign.left->visit(*this);
365 assign.right->visit(*this);
366 assignment = &assign;
370 void UnusedVariableRemover::visit(FunctionCall &call)
372 TraversingVisitor::visit(call);
376 void UnusedVariableRemover::record_assignment(VariableDeclaration &var, Node &node, bool chained)
378 VariableInfo &var_info = variables.back()[&var];
380 clear_assignments(var_info, true);
381 var_info.assignments.push_back(&node);
382 var_info.conditionally_assigned = false;
385 void UnusedVariableRemover::clear_assignments(VariableInfo &var_info, bool mark_unused)
389 for(vector<Node *>::iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i)
390 unused_nodes.insert(*i);
392 var_info.assignments.clear();
395 void UnusedVariableRemover::visit(ExpressionStatement &expr)
398 side_effects = false;
399 TraversingVisitor::visit(expr);
400 if(assignment && assignment->target_declaration)
401 record_assignment(*assignment->target_declaration, expr, (assignment->self_referencing || assign_to_subscript));
403 unused_nodes.insert(&expr);
406 void UnusedVariableRemover::visit(StructDeclaration &strct)
408 SetForScope<Node *> set(aggregate, &strct);
409 unused_nodes.insert(&strct);
410 TraversingVisitor::visit(strct);
413 void UnusedVariableRemover::visit(VariableDeclaration &var)
416 aggregates[&var] = aggregate;
419 variables.back()[&var].local = true;
420 if(var.init_expression)
421 record_assignment(var, *var.init_expression, false);
423 unused_nodes.erase(var.type_declaration);
424 TraversingVisitor::visit(var);
427 void UnusedVariableRemover::visit(InterfaceBlock &iface)
429 SetForScope<Node *> set(aggregate, &iface);
430 unused_nodes.insert(&iface);
431 TraversingVisitor::visit(iface);
434 void UnusedVariableRemover::visit(FunctionDeclaration &func)
436 variables.push_back(BlockVariableMap());
438 for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
440 func.body.visit(*this);
442 BlockVariableMap &block_variables = variables.back();
443 for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
444 i->second.conditionally_assigned = true;
445 for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
446 block_variables[i->get()].referenced = true;
447 merge_down_variables();
450 void UnusedVariableRemover::merge_down_variables()
452 BlockVariableMap &parent_variables = variables[variables.size()-2];
453 BlockVariableMap &block_variables = variables.back();
454 for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
458 if(!i->second.referenced)
459 unused_nodes.insert(i->first);
460 clear_assignments(i->second, i->first->interface!="out");
464 BlockVariableMap::iterator j = parent_variables.find(i->first);
465 if(j==parent_variables.end())
466 parent_variables.insert(*i);
469 if(i->second.referenced || !i->second.conditionally_assigned)
470 clear_assignments(j->second, !i->second.referenced);
471 j->second.conditionally_assigned = i->second.conditionally_assigned;
472 j->second.referenced |= i->second.referenced;
473 j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin(), i->second.assignments.end());
476 variables.pop_back();
479 void UnusedVariableRemover::visit(Conditional &cond)
481 cond.condition->visit(*this);
482 variables.push_back(BlockVariableMap());
483 cond.body.visit(*this);
485 BlockVariableMap if_variables;
486 swap(variables.back(), if_variables);
487 cond.else_body.visit(*this);
489 BlockVariableMap &else_variables = variables.back();
490 for(BlockVariableMap::iterator i=else_variables.begin(); i!=else_variables.end(); ++i)
492 BlockVariableMap::iterator j = if_variables.find(i->first);
493 if(j!=if_variables.end())
495 i->second.assignments.insert(i->second.assignments.end(), j->second.assignments.begin(), j->second.assignments.end());
496 i->second.conditionally_assigned |= j->second.conditionally_assigned;
497 if_variables.erase(j);
500 i->second.conditionally_assigned = true;
503 for(BlockVariableMap::iterator i=if_variables.begin(); i!=if_variables.end(); ++i)
505 i->second.conditionally_assigned = true;
506 else_variables.insert(*i);
509 merge_down_variables();
512 void UnusedVariableRemover::visit(Iteration &iter)
514 variables.push_back(BlockVariableMap());
515 TraversingVisitor::visit(iter);
517 BlockVariableMap &block_variables = variables.back();
518 for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
519 if(!i->second.local && i->second.referenced)
520 clear_assignments(i->second, false);
522 merge_down_variables();
526 bool UnusedFunctionRemover::apply(Stage &stage)
528 stage.content.visit(*this);
529 NodeRemover().apply(stage, unused_nodes);
530 return !unused_nodes.empty();
533 void UnusedFunctionRemover::visit(FunctionCall &call)
535 TraversingVisitor::visit(call);
537 unused_nodes.erase(call.declaration);
538 if(call.declaration && call.declaration->definition!=call.declaration)
539 used_definitions.insert(call.declaration->definition);
542 void UnusedFunctionRemover::visit(FunctionDeclaration &func)
544 TraversingVisitor::visit(func);
546 if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func))
547 unused_nodes.insert(&func);