1 #include <msp/core/raii.h>
10 InlineableFunctionLocator::InlineableFunctionLocator():
14 void InlineableFunctionLocator::visit(FunctionCall &call)
16 FunctionDeclaration *def = call.declaration;
17 if(def && def->definition!=def)
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 FunctionInliner::FunctionInliner():
46 FunctionInliner::FunctionInliner(const set<FunctionDeclaration *> &in):
51 void FunctionInliner::visit_and_inline(RefPtr<Expression> &ptr)
59 void FunctionInliner::visit(Block &block)
64 for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
72 void FunctionInliner::visit(UnaryExpression &unary)
74 visit_and_inline(unary.expression);
78 void FunctionInliner::visit(BinaryExpression &binary)
80 visit_and_inline(binary.left);
81 visit_and_inline(binary.right);
85 void FunctionInliner::visit(MemberAccess &memacc)
87 visit_and_inline(memacc.left);
91 void FunctionInliner::visit(FunctionCall &call)
93 for(NodeArray<Expression>::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
96 FunctionDeclaration *def = call.declaration;
97 if(def && def->definition!=def)
98 def = def->definition;
100 if(def && inlineable.count(def))
109 void FunctionInliner::visit(VariableDeclaration &var)
111 if(var.init_expression)
112 visit_and_inline(var.init_expression);
116 void FunctionInliner::visit(Return &ret)
118 TraversingVisitor::visit(ret);
121 inline_result = ret.expression->clone();
125 ConstantConditionEliminator::ConstantConditionEliminator():
130 void ConstantConditionEliminator::visit(Block &block)
132 SetForScope<unsigned> set(scope_level, scope_level+1);
133 BlockModifier::visit(block);
135 for(map<string, VariableDeclaration *>::const_iterator i=block.variables.begin(); i!=block.variables.end(); ++i)
136 variable_values.erase(i->second);
139 void ConstantConditionEliminator::visit(UnaryExpression &unary)
141 if(VariableReference *var = dynamic_cast<VariableReference *>(unary.expression.get()))
142 if(unary.oper=="++" || unary.oper=="--")
143 variable_values.erase(var->declaration);
146 void ConstantConditionEliminator::visit(Assignment &assign)
148 variable_values.erase(assign.target_declaration);
151 void ConstantConditionEliminator::visit(VariableDeclaration &var)
153 if(var.constant || scope_level>1)
154 variable_values[&var] = var.init_expression.get();
157 void ConstantConditionEliminator::visit(Conditional &cond)
161 ExpressionEvaluator eval(variable_values);
162 cond.condition->visit(eval);
163 if(eval.is_result_valid())
165 flatten_block(eval.get_result() ? cond.body : cond.else_body);
170 TraversingVisitor::visit(cond);
173 void ConstantConditionEliminator::visit(Iteration &iter)
179 /* If the loop condition is always false on the first iteration, the
180 entire loop can be removed */
181 if(iter.init_statement)
182 iter.init_statement->visit(*this);
183 ExpressionEvaluator eval(variable_values);
184 iter.condition->visit(eval);
185 if(eval.is_result_valid() && !eval.get_result())
192 /* Record all assignments that occur inside the loop body so those
193 variables won't be considered as constant */
194 SetFlag set_record(record_only);
195 TraversingVisitor::visit(iter);
198 TraversingVisitor::visit(iter);
200 if(VariableDeclaration *init_decl = dynamic_cast<VariableDeclaration *>(iter.init_statement.get()))
201 variable_values.erase(init_decl);
205 UnusedVariableLocator::VariableInfo::VariableInfo():
207 conditionally_assigned(false),
212 UnusedVariableLocator::UnusedVariableLocator():
215 assignment_target(false),
216 assign_to_subscript(false),
220 void UnusedVariableLocator::apply(Stage &s)
222 variables.push_back(BlockVariableMap());
223 StageVisitor::apply(s);
224 BlockVariableMap &global_variables = variables.back();
225 for(BlockVariableMap::iterator i=global_variables.begin(); i!=global_variables.end(); ++i)
227 if(i->first->interface=="out" && (s.type==Stage::FRAGMENT || i->first->linked_declaration || !i->first->name.compare(0, 3, "gl_")))
229 if(!i->second.referenced)
231 unused_nodes.insert(i->first);
232 clear_assignments(i->second, true);
235 variables.pop_back();
238 void UnusedVariableLocator::visit(VariableReference &var)
240 map<VariableDeclaration *, Node *>::iterator i = aggregates.find(var.declaration);
241 if(i!=aggregates.end())
242 unused_nodes.erase(i->second);
244 if(var.declaration && !assignment_target)
246 VariableInfo &var_info = variables.back()[var.declaration];
247 var_info.assignments.clear();
248 var_info.referenced = true;
252 void UnusedVariableLocator::visit(MemberAccess &memacc)
254 TraversingVisitor::visit(memacc);
255 unused_nodes.erase(memacc.declaration);
258 void UnusedVariableLocator::visit(BinaryExpression &binary)
262 if(assignment_target)
263 assign_to_subscript = true;
264 binary.left->visit(*this);
265 SetForScope<bool> set(assignment_target, false);
266 binary.right->visit(*this);
269 TraversingVisitor::visit(binary);
272 void UnusedVariableLocator::visit(Assignment &assign)
275 assign_to_subscript = false;
276 SetForScope<bool> set(assignment_target, !assign.self_referencing);
277 assign.left->visit(*this);
279 assign.right->visit(*this);
280 assignment = &assign;
283 void UnusedVariableLocator::record_assignment(VariableDeclaration &var, Node &node, bool chained)
285 VariableInfo &var_info = variables.back()[&var];
287 clear_assignments(var_info, true);
288 var_info.assignments.push_back(&node);
289 var_info.conditionally_assigned = false;
292 void UnusedVariableLocator::clear_assignments(VariableInfo &var_info, bool mark_unused)
296 for(vector<Node *>::iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i)
297 unused_nodes.insert(*i);
299 var_info.assignments.clear();
302 void UnusedVariableLocator::visit(ExpressionStatement &expr)
305 TraversingVisitor::visit(expr);
306 if(assignment && assignment->target_declaration)
307 record_assignment(*assignment->target_declaration, expr, (assignment->self_referencing || assign_to_subscript));
310 void UnusedVariableLocator::visit(StructDeclaration &strct)
312 SetForScope<Node *> set(aggregate, &strct);
313 unused_nodes.insert(&strct);
314 TraversingVisitor::visit(strct);
317 void UnusedVariableLocator::visit(VariableDeclaration &var)
320 aggregates[&var] = aggregate;
323 variables.back()[&var].local = true;
324 if(var.init_expression)
325 record_assignment(var, *var.init_expression, false);
327 unused_nodes.erase(var.type_declaration);
328 TraversingVisitor::visit(var);
331 void UnusedVariableLocator::visit(InterfaceBlock &iface)
333 SetForScope<Node *> set(aggregate, &iface);
334 unused_nodes.insert(&iface);
335 TraversingVisitor::visit(iface);
338 void UnusedVariableLocator::visit(FunctionDeclaration &func)
340 variables.push_back(BlockVariableMap());
343 SetForScope<bool> set(global_scope, false);
344 for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
346 func.body.visit(*this);
349 BlockVariableMap &block_variables = variables.back();
350 for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
351 i->second.conditionally_assigned = true;
352 for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
353 block_variables[i->get()].referenced = true;
354 merge_down_variables();
357 void UnusedVariableLocator::merge_down_variables()
359 BlockVariableMap &parent_variables = variables[variables.size()-2];
360 BlockVariableMap &block_variables = variables.back();
361 for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
365 if(!i->second.referenced)
366 unused_nodes.insert(i->first);
367 clear_assignments(i->second, i->first->interface!="out");
371 BlockVariableMap::iterator j = parent_variables.find(i->first);
372 if(j==parent_variables.end())
373 parent_variables.insert(*i);
376 if(i->second.referenced || !i->second.conditionally_assigned)
377 clear_assignments(j->second, !i->second.referenced);
378 j->second.conditionally_assigned = i->second.conditionally_assigned;
379 j->second.referenced |= i->second.referenced;
380 j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin(), i->second.assignments.end());
383 variables.pop_back();
386 void UnusedVariableLocator::visit(Conditional &cond)
388 cond.condition->visit(*this);
389 variables.push_back(BlockVariableMap());
390 cond.body.visit(*this);
392 BlockVariableMap if_variables;
393 swap(variables.back(), if_variables);
394 cond.else_body.visit(*this);
396 BlockVariableMap &else_variables = variables.back();
397 for(BlockVariableMap::iterator i=else_variables.begin(); i!=else_variables.end(); ++i)
399 BlockVariableMap::iterator j = if_variables.find(i->first);
400 if(j!=if_variables.end())
402 i->second.assignments.insert(i->second.assignments.end(), j->second.assignments.begin(), j->second.assignments.end());
403 i->second.conditionally_assigned |= j->second.conditionally_assigned;
404 if_variables.erase(j);
407 i->second.conditionally_assigned = true;
410 for(BlockVariableMap::iterator i=if_variables.begin(); i!=if_variables.end(); ++i)
412 i->second.conditionally_assigned = true;
413 else_variables.insert(*i);
416 merge_down_variables();
419 void UnusedVariableLocator::visit(Iteration &iter)
421 variables.push_back(BlockVariableMap());
422 TraversingVisitor::visit(iter);
424 BlockVariableMap &block_variables = variables.back();
425 for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
426 if(!i->second.local && i->second.referenced)
427 i->second.assignments.clear();
429 merge_down_variables();
433 void UnusedFunctionLocator::visit(FunctionCall &call)
435 TraversingVisitor::visit(call);
437 unused_nodes.erase(call.declaration);
438 if(call.declaration && call.declaration->definition!=call.declaration)
439 used_definitions.insert(call.declaration->definition);
442 void UnusedFunctionLocator::visit(FunctionDeclaration &func)
444 TraversingVisitor::visit(func);
446 if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func))
447 unused_nodes.insert(&func);