1 #include <msp/core/raii.h>
2 #include <msp/strings/format.h>
11 InlineableFunctionLocator::InlineableFunctionLocator():
16 void InlineableFunctionLocator::visit(FunctionCall &call)
18 FunctionDeclaration *def = call.declaration;
20 def = def->definition;
24 unsigned &count = refcounts[def];
26 /* Don't inline functions which are called more than once or are called
28 if(count>1 || def==current_function)
29 inlineable.erase(def);
32 TraversingVisitor::visit(call);
35 void InlineableFunctionLocator::visit(FunctionDeclaration &func)
37 bool has_out_params = false;
38 for(NodeArray<VariableDeclaration>::const_iterator i=func.parameters.begin(); (!has_out_params && i!=func.parameters.end()); ++i)
39 has_out_params = ((*i)->interface=="out");
41 unsigned &count = refcounts[func.definition];
42 if(count<=1 && !has_out_params)
43 inlineable.insert(func.definition);
45 SetForScope<FunctionDeclaration *> set(current_function, &func);
47 TraversingVisitor::visit(func);
50 void InlineableFunctionLocator::visit(Conditional &cond)
52 TraversingVisitor::visit(cond);
53 inlineable.erase(current_function);
56 void InlineableFunctionLocator::visit(Iteration &iter)
58 TraversingVisitor::visit(iter);
59 inlineable.erase(current_function);
62 void InlineableFunctionLocator::visit(Return &ret)
64 TraversingVisitor::visit(ret);
66 inlineable.erase(current_function);
71 InlineContentInjector::InlineContentInjector():
76 const string &InlineContentInjector::apply(Stage &stage, FunctionDeclaration &target_func, Block &tgt_blk, const NodeList<Statement>::iterator &ins_pt, FunctionCall &call)
78 source_func = call.declaration->definition;
80 // Collect all declarations the inlined function depends on.
82 source_func->visit(*this);
84 /* Populate referenced_names from the target function so we can rename
85 variables from the inlined function that would conflict. */
87 target_func.visit(*this);
89 /* Inline and rename passes must be interleaved so used variable names are
90 known when inlining the return statement. */
92 staging_block.parent = &tgt_blk;
93 staging_block.variables.clear();
95 std::vector<RefPtr<VariableDeclaration> > params;
96 params.reserve(source_func->parameters.size());
97 for(NodeArray<VariableDeclaration>::iterator i=source_func->parameters.begin(); i!=source_func->parameters.end(); ++i)
99 RefPtr<VariableDeclaration> var = (*i)->clone();
100 var->interface.clear();
102 SetForScope<Pass> set_pass(pass, RENAME);
105 staging_block.body.push_back_nocopy(var);
106 params.push_back(var);
109 for(NodeList<Statement>::iterator i=source_func->body.body.begin(); i!=source_func->body.body.end(); ++i)
111 r_inlined_statement = 0;
113 if(!r_inlined_statement)
114 r_inlined_statement = (*i)->clone();
116 SetForScope<Pass> set_pass(pass, RENAME);
117 r_inlined_statement->visit(*this);
119 staging_block.body.push_back_nocopy(r_inlined_statement);
122 /* Now collect names from the staging block. Local variables that would
123 have conflicted with the target function were renamed earlier. */
125 referenced_names.clear();
126 staging_block.variables.clear();
127 staging_block.visit(*this);
129 /* Rename variables in the target function so they don't interfere with
130 global identifiers used by the source function. */
132 staging_block.parent = source_func->body.parent;
133 target_func.visit(*this);
135 // Put the argument expressions in place after all renaming has been done.
136 for(unsigned i=0; i<source_func->parameters.size(); ++i)
137 params[i]->init_expression = call.arguments[i]->clone();
139 tgt_blk.body.splice(ins_pt, staging_block.body);
141 NodeReorderer().apply(stage, target_func, dependencies);
143 return r_result_name;
146 void InlineContentInjector::visit(VariableReference &var)
150 map<string, VariableDeclaration *>::const_iterator i = staging_block.variables.find(var.name);
151 if(i!=staging_block.variables.end())
152 var.name = i->second->name;
154 else if(pass==DEPENDS && var.declaration)
156 dependencies.insert(var.declaration);
157 var.declaration->visit(*this);
159 else if(pass==REFERENCED)
160 referenced_names.insert(var.name);
163 void InlineContentInjector::visit(InterfaceBlockReference &iface)
165 if(pass==DEPENDS && iface.declaration)
167 dependencies.insert(iface.declaration);
168 iface.declaration->visit(*this);
170 else if(pass==REFERENCED)
171 referenced_names.insert(iface.name);
174 void InlineContentInjector::visit(FunctionCall &call)
176 if(pass==DEPENDS && call.declaration)
177 dependencies.insert(call.declaration);
178 else if(pass==REFERENCED)
179 referenced_names.insert(call.name);
180 TraversingVisitor::visit(call);
183 void InlineContentInjector::visit(VariableDeclaration &var)
185 TraversingVisitor::visit(var);
189 staging_block.variables[var.name] = &var;
190 if(referenced_names.count(var.name))
192 string mapped_name = get_unused_variable_name(staging_block, var.name);
193 if(mapped_name!=var.name)
195 staging_block.variables[mapped_name] = &var;
196 var.name = mapped_name;
200 else if(pass==DEPENDS && var.type_declaration)
202 dependencies.insert(var.type_declaration);
203 var.type_declaration->visit(*this);
205 else if(pass==REFERENCED)
206 referenced_names.insert(var.type);
209 void InlineContentInjector::visit(Return &ret)
211 TraversingVisitor::visit(ret);
213 if(pass==INLINE && ret.expression)
215 // Create a new variable to hold the return value of the inlined function.
216 r_result_name = get_unused_variable_name(staging_block, "_return");
217 RefPtr<VariableDeclaration> var = new VariableDeclaration;
218 var->source = ret.source;
219 var->line = ret.line;
220 var->type = source_func->return_type;
221 var->name = r_result_name;
222 var->init_expression = ret.expression->clone();
223 r_inlined_statement = var;
228 FunctionInliner::FunctionInliner():
230 r_any_inlined(false),
231 r_inlined_here(false)
234 bool FunctionInliner::apply(Stage &s)
237 inlineable = InlineableFunctionLocator().apply(s);
238 r_any_inlined = false;
239 s.content.visit(*this);
240 return r_any_inlined;
243 void FunctionInliner::visit(RefPtr<Expression> &ptr)
249 ptr = r_inline_result;
250 r_any_inlined = true;
255 void FunctionInliner::visit(Block &block)
257 SetForScope<Block *> set_block(current_block, &block);
258 SetForScope<NodeList<Statement>::iterator> save_insert_point(insert_point, block.body.begin());
259 for(NodeList<Statement>::iterator i=block.body.begin(); (!r_inlined_here && i!=block.body.end()); ++i)
266 void FunctionInliner::visit(FunctionCall &call)
271 for(NodeArray<Expression>::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
274 FunctionDeclaration *def = call.declaration;
276 def = def->definition;
278 if(def && inlineable.count(def))
280 string result_name = InlineContentInjector().apply(*stage, *current_function, *current_block, insert_point, call);
282 // This will later get removed by UnusedVariableRemover.
283 if(result_name.empty())
284 result_name = "_msp_unused_from_inline";
286 RefPtr<VariableReference> ref = new VariableReference;
287 ref->name = result_name;
288 r_inline_result = ref;
290 /* Inlined variables need to be resolved before this function can be
292 inlineable.erase(current_function);
293 r_inlined_here = true;
297 void FunctionInliner::visit(FunctionDeclaration &func)
299 SetForScope<FunctionDeclaration *> set_func(current_function, &func);
300 TraversingVisitor::visit(func);
301 r_inlined_here = false;
304 void FunctionInliner::visit(Iteration &iter)
306 /* Visit the initialization statement before entering the loop body so the
307 inlined statements get inserted outside. */
308 if(iter.init_statement)
309 iter.init_statement->visit(*this);
311 SetForScope<Block *> set_block(current_block, &iter.body);
312 /* Skip the condition and loop expression parts because they're not properly
313 inside the body block. Inlining anything into them will require a more
314 comprehensive transformation. */
315 iter.body.visit(*this);
319 ExpressionInliner::ExpressionInfo::ExpressionInfo():
328 ExpressionInliner::ExpressionInliner():
330 r_any_inlined(false),
333 iteration_init(false),
338 bool ExpressionInliner::apply(Stage &s)
340 s.content.visit(*this);
341 return r_any_inlined;
344 void ExpressionInliner::inline_expression(Expression &expr, RefPtr<Expression> &ptr)
347 r_any_inlined = true;
350 void ExpressionInliner::visit(Block &block)
352 TraversingVisitor::visit(block);
354 for(map<string, VariableDeclaration *>::iterator i=block.variables.begin(); i!=block.variables.end(); ++i)
356 map<Assignment::Target, ExpressionInfo>::iterator j = expressions.lower_bound(i->second);
357 for(; (j!=expressions.end() && j->first.declaration==i->second); )
359 if(j->second.expression && j->second.inline_point)
360 inline_expression(*j->second.expression, *j->second.inline_point);
362 expressions.erase(j++);
366 /* Expressions assigned in this block may depend on local variables of the
367 block. If this is a conditionally executed block, the assignments might not
368 always happen. Mark the expressions as not available to any outer blocks. */
369 for(map<Assignment::Target, ExpressionInfo>::iterator i=expressions.begin(); i!=expressions.end(); ++i)
370 if(i->second.assign_scope==&block)
371 i->second.available = false;
374 void ExpressionInliner::visit(RefPtr<Expression> &expr)
378 if(r_ref_info && r_ref_info->expression && r_ref_info->available)
380 if(iteration_body && !r_ref_info->trivial)
382 /* Don't inline non-trivial expressions which were assigned outside
383 an iteration statement. The iteration may run multiple times, which
384 would cause the expression to also be evaluated multiple times. */
385 Block *i = r_ref_info->assign_scope;
386 for(; (i && i!=iteration_body); i=i->parent) ;
391 if(r_ref_info->trivial)
392 inline_expression(*r_ref_info->expression, expr);
394 /* Record the inline point for a non-trivial expression but don't
395 inline it yet. It might turn out it shouldn't be inlined after all. */
396 r_ref_info->inline_point = &expr;
402 void ExpressionInliner::visit(VariableReference &var)
406 map<Assignment::Target, ExpressionInfo>::iterator i = expressions.find(var.declaration);
407 if(i!=expressions.end())
409 /* If a non-trivial expression is referenced multiple times, don't
411 if(i->second.inline_point && !i->second.trivial)
412 i->second.expression = 0;
413 /* Mutating expressions are analogous to self-referencing assignments
414 and prevent inlining. */
416 i->second.expression = 0;
417 r_ref_info = &i->second;
422 void ExpressionInliner::visit(MemberAccess &memacc)
428 void ExpressionInliner::visit(Swizzle &swizzle)
434 void ExpressionInliner::visit(UnaryExpression &unary)
436 SetFlag set_target(mutating, mutating || unary.oper->token[1]=='+' || unary.oper->token[1]=='-');
437 visit(unary.expression);
441 void ExpressionInliner::visit(BinaryExpression &binary)
445 SetFlag clear_target(mutating, false);
451 void ExpressionInliner::visit(Assignment &assign)
454 SetFlag set_target(mutating);
460 map<Assignment::Target, ExpressionInfo>::iterator i = expressions.find(assign.target);
461 if(i!=expressions.end())
463 /* Self-referencing assignments can't be inlined without additional
464 work. Just clear any previous expression. */
465 i->second.expression = (assign.self_referencing ? 0 : assign.right.get());
466 i->second.assign_scope = current_block;
467 i->second.inline_point = 0;
468 i->second.available = true;
474 void ExpressionInliner::visit(TernaryExpression &ternary)
476 visit(ternary.condition);
477 visit(ternary.true_expr);
478 visit(ternary.false_expr);
482 void ExpressionInliner::visit(FunctionCall &call)
484 TraversingVisitor::visit(call);
488 void ExpressionInliner::visit(VariableDeclaration &var)
492 TraversingVisitor::visit(var);
494 bool constant = var.constant;
495 if(constant && var.layout)
497 for(vector<Layout::Qualifier>::const_iterator i=var.layout->qualifiers.begin(); (constant && i!=var.layout->qualifiers.end()); ++i)
498 constant = (i->name!="constant_id");
501 /* Only inline global variables if they're constant and have trivial
502 initializers. Non-constant variables could change in ways which are hard to
503 analyze and non-trivial expressions could be expensive to inline. */
504 if((current_block->parent || (constant && r_trivial)) && var.interface.empty())
506 ExpressionInfo &info = expressions[&var];
507 /* Assume variables declared in an iteration initialization statement
508 will have their values change throughout the iteration. */
509 info.expression = (iteration_init ? 0 : var.init_expression.get());
510 info.assign_scope = current_block;
511 info.trivial = r_trivial;
515 void ExpressionInliner::visit(Iteration &iter)
517 SetForScope<Block *> set_block(current_block, &iter.body);
518 if(iter.init_statement)
520 SetFlag set_init(iteration_init);
521 iter.init_statement->visit(*this);
524 SetForScope<Block *> set_body(iteration_body, &iter.body);
526 visit(iter.condition);
527 iter.body.visit(*this);
528 if(iter.loop_expression)
529 visit(iter.loop_expression);
533 BasicTypeDeclaration::Kind ConstantFolder::get_value_kind(const Variant &value)
535 if(value.check_type<bool>())
536 return BasicTypeDeclaration::BOOL;
537 else if(value.check_type<int>())
538 return BasicTypeDeclaration::INT;
539 else if(value.check_type<float>())
540 return BasicTypeDeclaration::FLOAT;
542 return BasicTypeDeclaration::VOID;
546 T ConstantFolder::evaluate_logical(char oper, T left, T right)
550 case '&': return left&right;
551 case '|': return left|right;
552 case '^': return left^right;
558 bool ConstantFolder::evaluate_relation(const char *oper, T left, T right)
560 switch(oper[0]|oper[1])
562 case '<': return left<right;
563 case '<'|'=': return left<=right;
564 case '>': return left>right;
565 case '>'|'=': return left>=right;
566 default: return false;
571 T ConstantFolder::evaluate_arithmetic(char oper, T left, T right)
575 case '+': return left+right;
576 case '-': return left-right;
577 case '*': return left*right;
578 case '/': return left/right;
583 void ConstantFolder::set_result(const Variant &value, bool literal)
585 r_constant_value = value;
590 void ConstantFolder::visit(RefPtr<Expression> &expr)
592 r_constant_value = Variant();
595 r_uses_iter_var = false;
597 /* Don't replace literals since they'd only be replaced with an identical
598 literal. Also skip anything that uses an iteration variable, but pass on
599 the result so the Iteration visiting function can handle it. */
600 if(!r_constant || r_literal || r_uses_iter_var)
603 BasicTypeDeclaration::Kind kind = get_value_kind(r_constant_value);
604 if(kind==BasicTypeDeclaration::VOID)
610 RefPtr<Literal> literal = new Literal;
611 if(kind==BasicTypeDeclaration::BOOL)
612 literal->token = (r_constant_value.value<bool>() ? "true" : "false");
613 else if(kind==BasicTypeDeclaration::INT)
614 literal->token = lexical_cast<string>(r_constant_value.value<int>());
615 else if(kind==BasicTypeDeclaration::FLOAT)
616 literal->token = lexical_cast<string>(r_constant_value.value<float>());
617 literal->value = r_constant_value;
621 void ConstantFolder::visit(Literal &literal)
623 set_result(literal.value, true);
626 void ConstantFolder::visit(VariableReference &var)
628 /* If an iteration variable is initialized with a constant value, return
629 that value here for the purpose of evaluating the loop condition for the
631 if(var.declaration==iteration_var)
633 set_result(iter_init_value);
634 r_uses_iter_var = true;
638 void ConstantFolder::visit(MemberAccess &memacc)
640 TraversingVisitor::visit(memacc);
644 void ConstantFolder::visit(Swizzle &swizzle)
646 TraversingVisitor::visit(swizzle);
650 void ConstantFolder::visit(UnaryExpression &unary)
652 TraversingVisitor::visit(unary);
653 bool can_fold = r_constant;
658 BasicTypeDeclaration::Kind kind = get_value_kind(r_constant_value);
660 char oper = unary.oper->token[0];
661 char oper2 = unary.oper->token[1];
664 if(kind==BasicTypeDeclaration::BOOL)
665 set_result(!r_constant_value.value<bool>());
669 if(kind==BasicTypeDeclaration::INT)
670 set_result(~r_constant_value.value<int>());
672 else if(oper=='-' && !oper2)
674 if(kind==BasicTypeDeclaration::INT)
675 set_result(-r_constant_value.value<int>());
676 else if(kind==BasicTypeDeclaration::FLOAT)
677 set_result(-r_constant_value.value<float>());
681 void ConstantFolder::visit(BinaryExpression &binary)
684 bool left_constant = r_constant;
685 bool left_iter_var = r_uses_iter_var;
686 Variant left_value = r_constant_value;
689 r_uses_iter_var = true;
691 bool can_fold = (left_constant && r_constant);
696 BasicTypeDeclaration::Kind left_kind = get_value_kind(left_value);
697 BasicTypeDeclaration::Kind right_kind = get_value_kind(r_constant_value);
698 // Currently only expressions with both sides of equal types are handled.
699 if(left_kind!=right_kind)
702 char oper = binary.oper->token[0];
703 char oper2 = binary.oper->token[1];
704 if(oper=='&' || oper=='|' || oper=='^')
706 if(oper2==oper && left_kind==BasicTypeDeclaration::BOOL)
707 set_result(evaluate_logical(oper, left_value.value<bool>(), r_constant_value.value<bool>()));
708 else if(!oper2 && left_kind==BasicTypeDeclaration::INT)
709 set_result(evaluate_logical(oper, left_value.value<int>(), r_constant_value.value<int>()));
711 else if((oper=='<' || oper=='>') && oper2!=oper)
713 if(left_kind==BasicTypeDeclaration::INT)
714 set_result(evaluate_relation(binary.oper->token, left_value.value<int>(), r_constant_value.value<int>()));
715 else if(left_kind==BasicTypeDeclaration::FLOAT)
716 set_result(evaluate_relation(binary.oper->token, left_value.value<float>(), r_constant_value.value<float>()));
718 else if((oper=='=' || oper=='!') && oper2=='=')
720 if(left_kind==BasicTypeDeclaration::INT)
721 set_result((left_value.value<int>()==r_constant_value.value<int>()) == (oper=='='));
722 if(left_kind==BasicTypeDeclaration::FLOAT)
723 set_result((left_value.value<float>()==r_constant_value.value<float>()) == (oper=='='));
725 else if(oper=='+' || oper=='-' || oper=='*' || oper=='/')
727 if(left_kind==BasicTypeDeclaration::INT)
728 set_result(evaluate_arithmetic(oper, left_value.value<int>(), r_constant_value.value<int>()));
729 else if(left_kind==BasicTypeDeclaration::FLOAT)
730 set_result(evaluate_arithmetic(oper, left_value.value<float>(), r_constant_value.value<float>()));
732 else if(oper=='%' || ((oper=='<' || oper=='>') && oper2==oper))
734 if(left_kind!=BasicTypeDeclaration::INT)
738 set_result(left_value.value<int>()%r_constant_value.value<int>());
740 set_result(left_value.value<int>()<<r_constant_value.value<int>());
742 set_result(left_value.value<int>()>>r_constant_value.value<int>());
746 void ConstantFolder::visit(Assignment &assign)
748 TraversingVisitor::visit(assign);
752 void ConstantFolder::visit(TernaryExpression &ternary)
754 TraversingVisitor::visit(ternary);
758 void ConstantFolder::visit(FunctionCall &call)
760 TraversingVisitor::visit(call);
764 void ConstantFolder::visit(VariableDeclaration &var)
766 if(iteration_init && var.init_expression)
768 visit(var.init_expression);
771 /* Record the value of a constant initialization expression of an
772 iteration, so it can be used to evaluate the loop condition. */
773 iteration_var = &var;
774 iter_init_value = r_constant_value;
778 TraversingVisitor::visit(var);
781 void ConstantFolder::visit(Iteration &iter)
783 SetForScope<Block *> set_block(current_block, &iter.body);
785 /* The iteration variable is not normally inlined into expressions, so we
786 process it specially here. If the initial value causes the loop condition
787 to evaluate to false, then the expression can be folded. */
789 if(iter.init_statement)
791 SetFlag set_init(iteration_init);
792 iter.init_statement->visit(*this);
797 visit(iter.condition);
798 if(r_constant && r_constant_value.check_type<bool>() && !r_constant_value.value<bool>())
800 RefPtr<Literal> literal = new Literal;
801 literal->token = "false";
802 literal->value = r_constant_value;
803 iter.condition = literal;
808 iter.body.visit(*this);
809 if(iter.loop_expression)
810 visit(iter.loop_expression);
814 void ConstantConditionEliminator::apply(Stage &stage)
816 stage.content.visit(*this);
817 NodeRemover().apply(stage, nodes_to_remove);
820 ConstantConditionEliminator::ConstantStatus ConstantConditionEliminator::check_constant_condition(const Expression &expr)
822 if(const Literal *literal = dynamic_cast<const Literal *>(&expr))
823 if(literal->value.check_type<bool>())
824 return (literal->value.value<bool>() ? CONSTANT_TRUE : CONSTANT_FALSE);
828 void ConstantConditionEliminator::visit(Block &block)
830 SetForScope<Block *> set_block(current_block, &block);
831 for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
838 void ConstantConditionEliminator::visit(RefPtr<Expression> &expr)
840 r_ternary_result = 0;
843 expr = r_ternary_result;
844 r_ternary_result = 0;
847 void ConstantConditionEliminator::visit(TernaryExpression &ternary)
849 ConstantStatus result = check_constant_condition(*ternary.condition);
850 if(result!=NOT_CONSTANT)
851 r_ternary_result = (result==CONSTANT_TRUE ? ternary.true_expr : ternary.false_expr);
853 r_ternary_result = 0;
856 void ConstantConditionEliminator::visit(Conditional &cond)
858 ConstantStatus result = check_constant_condition(*cond.condition);
859 if(result!=NOT_CONSTANT)
861 Block &block = (result==CONSTANT_TRUE ? cond.body : cond.else_body);
862 // TODO should check variable names for conflicts. Potentially reuse InlineContentInjector?
863 current_block->body.splice(insert_point, block.body);
864 nodes_to_remove.insert(&cond);
868 TraversingVisitor::visit(cond);
871 void ConstantConditionEliminator::visit(Iteration &iter)
875 ConstantStatus result = check_constant_condition(*iter.condition);
876 if(result==CONSTANT_FALSE)
878 nodes_to_remove.insert(&iter);
883 TraversingVisitor::visit(iter);
887 bool UnusedTypeRemover::apply(Stage &stage)
889 stage.content.visit(*this);
890 NodeRemover().apply(stage, unused_nodes);
891 return !unused_nodes.empty();
894 void UnusedTypeRemover::visit(Literal &literal)
896 unused_nodes.erase(literal.type);
899 void UnusedTypeRemover::visit(UnaryExpression &unary)
901 unused_nodes.erase(unary.type);
902 TraversingVisitor::visit(unary);
905 void UnusedTypeRemover::visit(BinaryExpression &binary)
907 unused_nodes.erase(binary.type);
908 TraversingVisitor::visit(binary);
911 void UnusedTypeRemover::visit(TernaryExpression &ternary)
913 unused_nodes.erase(ternary.type);
914 TraversingVisitor::visit(ternary);
917 void UnusedTypeRemover::visit(FunctionCall &call)
919 unused_nodes.erase(call.type);
920 TraversingVisitor::visit(call);
923 void UnusedTypeRemover::visit(BasicTypeDeclaration &type)
926 unused_nodes.erase(type.base_type);
927 unused_nodes.insert(&type);
930 void UnusedTypeRemover::visit(ImageTypeDeclaration &type)
933 unused_nodes.erase(type.base_type);
934 unused_nodes.insert(&type);
937 void UnusedTypeRemover::visit(StructDeclaration &strct)
939 unused_nodes.insert(&strct);
940 TraversingVisitor::visit(strct);
943 void UnusedTypeRemover::visit(VariableDeclaration &var)
945 unused_nodes.erase(var.type_declaration);
948 void UnusedTypeRemover::visit(InterfaceBlock &iface)
950 unused_nodes.erase(iface.type_declaration);
953 void UnusedTypeRemover::visit(FunctionDeclaration &func)
955 unused_nodes.erase(func.return_type_declaration);
956 TraversingVisitor::visit(func);
960 UnusedVariableRemover::UnusedVariableRemover():
964 assignment_target(false),
965 r_side_effects(false)
968 bool UnusedVariableRemover::apply(Stage &s)
971 s.content.visit(*this);
973 for(list<AssignmentInfo>::const_iterator i=assignments.begin(); i!=assignments.end(); ++i)
974 if(i->used_by.empty())
975 unused_nodes.insert(i->node);
977 for(map<string, InterfaceBlock *>::const_iterator i=s.interface_blocks.begin(); i!=s.interface_blocks.end(); ++i)
978 if(i->second->instance_name.empty())
979 unused_nodes.insert(i->second);
981 for(BlockVariableMap::const_iterator i=variables.begin(); i!=variables.end(); ++i)
985 /* The last visible assignments of output variables are used by the
986 next stage or the API. */
987 for(vector<AssignmentInfo *>::const_iterator j=i->second.assignments.begin(); j!=i->second.assignments.end(); ++j)
988 unused_nodes.erase((*j)->node);
991 if(!i->second.output && !i->second.referenced)
993 // Don't remove variables from inside interface blocks.
994 if(!i->second.interface_block)
995 unused_nodes.insert(i->first);
997 else if(i->second.interface_block)
998 // Interface blocks are kept if even one member is used.
999 unused_nodes.erase(i->second.interface_block);
1002 NodeRemover().apply(s, unused_nodes);
1004 return !unused_nodes.empty();
1007 void UnusedVariableRemover::referenced(const Assignment::Target &target, Node &node)
1009 VariableInfo &var_info = variables[target.declaration];
1010 var_info.referenced = true;
1011 if(!assignment_target)
1013 for(vector<AssignmentInfo *>::const_iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i)
1014 (*i)->used_by.push_back(&node);
1018 void UnusedVariableRemover::visit(VariableReference &var)
1020 referenced(var.declaration, var);
1023 void UnusedVariableRemover::visit(InterfaceBlockReference &iface)
1025 referenced(iface.declaration, iface);
1028 void UnusedVariableRemover::visit(UnaryExpression &unary)
1030 TraversingVisitor::visit(unary);
1031 if(unary.oper->token[1]=='+' || unary.oper->token[1]=='-')
1032 r_side_effects = true;
1035 void UnusedVariableRemover::visit(BinaryExpression &binary)
1037 if(binary.oper->token[0]=='[')
1039 binary.left->visit(*this);
1040 SetFlag set(assignment_target, false);
1041 binary.right->visit(*this);
1044 TraversingVisitor::visit(binary);
1047 void UnusedVariableRemover::visit(Assignment &assign)
1050 SetFlag set(assignment_target, (assign.oper->token[0]=='='));
1051 assign.left->visit(*this);
1053 assign.right->visit(*this);
1054 r_assignment = &assign;
1055 r_side_effects = true;
1058 void UnusedVariableRemover::visit(FunctionCall &call)
1060 TraversingVisitor::visit(call);
1061 /* Treat function calls as having side effects so expression statements
1062 consisting of nothing but a function call won't be optimized away. */
1063 r_side_effects = true;
1065 if(stage->type==Stage::GEOMETRY && call.name=="EmitVertex")
1067 for(map<Statement *, VariableInfo>::const_iterator i=variables.begin(); i!=variables.end(); ++i)
1068 if(i->second.output)
1069 referenced(i->first, call);
1073 void UnusedVariableRemover::record_assignment(const Assignment::Target &target, Node &node)
1075 assignments.push_back(AssignmentInfo());
1076 AssignmentInfo &assign_info = assignments.back();
1077 assign_info.node = &node;
1078 assign_info.target = target;
1080 /* An assignment to the target hides any assignments to the same target or
1082 VariableInfo &var_info = variables[target.declaration];
1083 for(unsigned i=0; i<var_info.assignments.size(); ++i)
1085 const Assignment::Target &t = var_info.assignments[i]->target;
1087 bool subfield = (t.chain_len>=target.chain_len);
1088 for(unsigned j=0; (subfield && j<target.chain_len); ++j)
1089 subfield = (t.chain[j]==target.chain[j]);
1092 var_info.assignments.erase(var_info.assignments.begin()+i);
1097 var_info.assignments.push_back(&assign_info);
1100 void UnusedVariableRemover::visit(ExpressionStatement &expr)
1103 r_side_effects = false;
1104 TraversingVisitor::visit(expr);
1105 if(r_assignment && r_assignment->target.declaration)
1106 record_assignment(r_assignment->target, expr);
1108 unused_nodes.insert(&expr);
1111 void UnusedVariableRemover::visit(VariableDeclaration &var)
1113 VariableInfo &var_info = variables[&var];
1114 var_info.interface_block = interface_block;
1116 /* Mark variables as output if they're used by the next stage or the
1119 var_info.output = (interface_block->interface=="out" && (interface_block->linked_block || !interface_block->name.compare(0, 3, "gl_")));
1121 var_info.output = (var.interface=="out" && (stage->type==Stage::FRAGMENT || var.linked_declaration || !var.name.compare(0, 3, "gl_")));
1123 if(var.init_expression)
1125 var_info.initialized = true;
1126 record_assignment(&var, *var.init_expression);
1128 TraversingVisitor::visit(var);
1131 void UnusedVariableRemover::visit(InterfaceBlock &iface)
1133 if(iface.instance_name.empty())
1135 SetForScope<InterfaceBlock *> set_block(interface_block, &iface);
1136 iface.struct_declaration->members.visit(*this);
1140 VariableInfo &var_info = variables[&iface];
1141 var_info.output = (iface.interface=="out" && (iface.linked_block || !iface.name.compare(0, 3, "gl_")));
1145 void UnusedVariableRemover::merge_variables(const BlockVariableMap &other_vars)
1147 for(BlockVariableMap::const_iterator i=other_vars.begin(); i!=other_vars.end(); ++i)
1149 BlockVariableMap::iterator j = variables.find(i->first);
1150 if(j!=variables.end())
1152 /* The merged blocks started as copies of each other so any common
1153 assignments must be in the beginning. */
1155 for(; (k<i->second.assignments.size() && k<j->second.assignments.size()); ++k)
1156 if(i->second.assignments[k]!=j->second.assignments[k])
1159 // Remaining assignments are unique to each block; merge them.
1160 j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin()+k, i->second.assignments.end());
1161 j->second.referenced |= i->second.referenced;
1164 variables.insert(*i);
1168 void UnusedVariableRemover::visit(FunctionDeclaration &func)
1170 if(func.body.body.empty())
1173 BlockVariableMap saved_vars = variables;
1174 // Assignments from other functions should not be visible.
1175 for(BlockVariableMap::iterator i=variables.begin(); i!=variables.end(); ++i)
1176 i->second.assignments.resize(i->second.initialized);
1177 TraversingVisitor::visit(func);
1178 swap(variables, saved_vars);
1179 merge_variables(saved_vars);
1181 /* Always treat function parameters as referenced. Removing unused
1182 parameters is not currently supported. */
1183 for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
1185 BlockVariableMap::iterator j = variables.find(i->get());
1186 if(j!=variables.end())
1187 j->second.referenced = true;
1191 void UnusedVariableRemover::visit(Conditional &cond)
1193 cond.condition->visit(*this);
1194 BlockVariableMap saved_vars = variables;
1195 cond.body.visit(*this);
1196 swap(saved_vars, variables);
1197 cond.else_body.visit(*this);
1199 /* Visible assignments after the conditional is the union of those visible
1200 at the end of the if and else blocks. If there was no else block, then it's
1201 the union of the if block and the state before it. */
1202 merge_variables(saved_vars);
1205 void UnusedVariableRemover::visit(Iteration &iter)
1207 BlockVariableMap saved_vars = variables;
1208 TraversingVisitor::visit(iter);
1210 /* Merge assignments from the iteration, without clearing previous state.
1211 Further analysis is needed to determine which parts of the iteration body
1212 are always executed, if any. */
1213 merge_variables(saved_vars);
1217 bool UnusedFunctionRemover::apply(Stage &stage)
1219 stage.content.visit(*this);
1220 NodeRemover().apply(stage, unused_nodes);
1221 return !unused_nodes.empty();
1224 void UnusedFunctionRemover::visit(FunctionCall &call)
1226 TraversingVisitor::visit(call);
1228 unused_nodes.erase(call.declaration);
1229 if(call.declaration && call.declaration->definition!=call.declaration)
1230 used_definitions.insert(call.declaration->definition);
1233 void UnusedFunctionRemover::visit(FunctionDeclaration &func)
1235 TraversingVisitor::visit(func);
1237 if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func))
1238 unused_nodes.insert(&func);