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 const set<Node *> &UnusedVariableLocator::apply(Stage &s)
222 variables.push_back(BlockVariableMap());
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();
240 void UnusedVariableLocator::visit(VariableReference &var)
242 map<VariableDeclaration *, Node *>::iterator i = aggregates.find(var.declaration);
243 if(i!=aggregates.end())
244 unused_nodes.erase(i->second);
246 if(var.declaration && !assignment_target)
248 VariableInfo &var_info = variables.back()[var.declaration];
249 var_info.assignments.clear();
250 var_info.referenced = true;
254 void UnusedVariableLocator::visit(MemberAccess &memacc)
256 TraversingVisitor::visit(memacc);
257 unused_nodes.erase(memacc.declaration);
260 void UnusedVariableLocator::visit(BinaryExpression &binary)
264 if(assignment_target)
265 assign_to_subscript = true;
266 binary.left->visit(*this);
267 SetForScope<bool> set(assignment_target, false);
268 binary.right->visit(*this);
271 TraversingVisitor::visit(binary);
274 void UnusedVariableLocator::visit(Assignment &assign)
277 assign_to_subscript = false;
278 SetForScope<bool> set(assignment_target, !assign.self_referencing);
279 assign.left->visit(*this);
281 assign.right->visit(*this);
282 assignment = &assign;
285 void UnusedVariableLocator::record_assignment(VariableDeclaration &var, Node &node, bool chained)
287 VariableInfo &var_info = variables.back()[&var];
289 clear_assignments(var_info, true);
290 var_info.assignments.push_back(&node);
291 var_info.conditionally_assigned = false;
294 void UnusedVariableLocator::clear_assignments(VariableInfo &var_info, bool mark_unused)
298 for(vector<Node *>::iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i)
299 unused_nodes.insert(*i);
301 var_info.assignments.clear();
304 void UnusedVariableLocator::visit(ExpressionStatement &expr)
307 TraversingVisitor::visit(expr);
308 if(assignment && assignment->target_declaration)
309 record_assignment(*assignment->target_declaration, expr, (assignment->self_referencing || assign_to_subscript));
312 void UnusedVariableLocator::visit(StructDeclaration &strct)
314 SetForScope<Node *> set(aggregate, &strct);
315 unused_nodes.insert(&strct);
316 TraversingVisitor::visit(strct);
319 void UnusedVariableLocator::visit(VariableDeclaration &var)
322 aggregates[&var] = aggregate;
325 variables.back()[&var].local = true;
326 if(var.init_expression)
327 record_assignment(var, *var.init_expression, false);
329 unused_nodes.erase(var.type_declaration);
330 TraversingVisitor::visit(var);
333 void UnusedVariableLocator::visit(InterfaceBlock &iface)
335 SetForScope<Node *> set(aggregate, &iface);
336 unused_nodes.insert(&iface);
337 TraversingVisitor::visit(iface);
340 void UnusedVariableLocator::visit(FunctionDeclaration &func)
342 variables.push_back(BlockVariableMap());
345 SetForScope<bool> set(global_scope, false);
346 for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
348 func.body.visit(*this);
351 BlockVariableMap &block_variables = variables.back();
352 for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
353 i->second.conditionally_assigned = true;
354 for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
355 block_variables[i->get()].referenced = true;
356 merge_down_variables();
359 void UnusedVariableLocator::merge_down_variables()
361 BlockVariableMap &parent_variables = variables[variables.size()-2];
362 BlockVariableMap &block_variables = variables.back();
363 for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
367 if(!i->second.referenced)
368 unused_nodes.insert(i->first);
369 clear_assignments(i->second, i->first->interface!="out");
373 BlockVariableMap::iterator j = parent_variables.find(i->first);
374 if(j==parent_variables.end())
375 parent_variables.insert(*i);
378 if(i->second.referenced || !i->second.conditionally_assigned)
379 clear_assignments(j->second, !i->second.referenced);
380 j->second.conditionally_assigned = i->second.conditionally_assigned;
381 j->second.referenced |= i->second.referenced;
382 j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin(), i->second.assignments.end());
385 variables.pop_back();
388 void UnusedVariableLocator::visit(Conditional &cond)
390 cond.condition->visit(*this);
391 variables.push_back(BlockVariableMap());
392 cond.body.visit(*this);
394 BlockVariableMap if_variables;
395 swap(variables.back(), if_variables);
396 cond.else_body.visit(*this);
398 BlockVariableMap &else_variables = variables.back();
399 for(BlockVariableMap::iterator i=else_variables.begin(); i!=else_variables.end(); ++i)
401 BlockVariableMap::iterator j = if_variables.find(i->first);
402 if(j!=if_variables.end())
404 i->second.assignments.insert(i->second.assignments.end(), j->second.assignments.begin(), j->second.assignments.end());
405 i->second.conditionally_assigned |= j->second.conditionally_assigned;
406 if_variables.erase(j);
409 i->second.conditionally_assigned = true;
412 for(BlockVariableMap::iterator i=if_variables.begin(); i!=if_variables.end(); ++i)
414 i->second.conditionally_assigned = true;
415 else_variables.insert(*i);
418 merge_down_variables();
421 void UnusedVariableLocator::visit(Iteration &iter)
423 variables.push_back(BlockVariableMap());
424 TraversingVisitor::visit(iter);
426 BlockVariableMap &block_variables = variables.back();
427 for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
428 if(!i->second.local && i->second.referenced)
429 i->second.assignments.clear();
431 merge_down_variables();
435 void UnusedFunctionLocator::visit(FunctionCall &call)
437 TraversingVisitor::visit(call);
439 unused_nodes.erase(call.declaration);
440 if(call.declaration && call.declaration->definition!=call.declaration)
441 used_definitions.insert(call.declaration->definition);
444 void UnusedFunctionLocator::visit(FunctionDeclaration &func)
446 TraversingVisitor::visit(func);
448 if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func))
449 unused_nodes.insert(&func);