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 unsigned &count = refcounts[func.definition];
38 if(count<=1 && func.parameters.empty())
39 inlineable.insert(func.definition);
41 SetForScope<FunctionDeclaration *> set(current_function, &func);
43 TraversingVisitor::visit(func);
46 void InlineableFunctionLocator::visit(Conditional &cond)
48 TraversingVisitor::visit(cond);
49 inlineable.erase(current_function);
52 void InlineableFunctionLocator::visit(Iteration &iter)
54 TraversingVisitor::visit(iter);
55 inlineable.erase(current_function);
58 void InlineableFunctionLocator::visit(Return &ret)
60 TraversingVisitor::visit(ret);
62 inlineable.erase(current_function);
67 InlineContentInjector::InlineContentInjector():
73 const string &InlineContentInjector::apply(Stage &stage, FunctionDeclaration &target_func, Block &tgt_blk, const NodeList<Statement>::iterator &ins_pt, FunctionDeclaration &src)
75 target_block = &tgt_blk;
77 remap_prefix = source_func->name;
79 vector<RefPtr<Statement> > inlined;
80 inlined.reserve(src.body.body.size());
81 for(NodeList<Statement>::iterator i=src.body.body.begin(); i!=src.body.body.end(); ++i)
83 r_inlined_statement = 0;
85 if(!r_inlined_statement)
86 r_inlined_statement = (*i)->clone();
88 SetForScope<unsigned> set_remap(remap_names, 2);
89 r_inlined_statement->visit(*this);
90 inlined.push_back(r_inlined_statement);
93 // Insert the variables here to enable further inlinings to avoid conflicts.
94 tgt_blk.variables.insert(variable_map.begin(), variable_map.end());
96 SetForScope<unsigned> set_remap(remap_names, 1);
97 SetForScope<string> set_prefix(remap_prefix, target_func.name);
99 target_func.visit(*this);
101 tgt_blk.body.insert(ins_pt, inlined.begin(), inlined.end());
103 NodeReorderer().apply(stage, target_func, dependencies);
105 return r_result_name;
108 void InlineContentInjector::visit(VariableReference &var)
112 map<string, VariableDeclaration *>::const_iterator i = variable_map.find(var.name);
113 if(i!=variable_map.end())
114 var.name = i->second->name;
116 else if(var.declaration)
118 SetFlag set_deps(deps_only);
119 if(!variable_map.count(var.name))
121 dependencies.insert(var.declaration);
122 referenced_names.insert(var.name);
124 var.declaration->visit(*this);
128 void InlineContentInjector::visit(InterfaceBlockReference &iface)
130 if(!remap_names && iface.declaration)
132 SetFlag set_deps(deps_only);
133 dependencies.insert(iface.declaration);
134 referenced_names.insert(iface.name);
135 iface.declaration->visit(*this);
139 void InlineContentInjector::visit(FunctionCall &call)
141 if(!remap_names && call.declaration)
143 dependencies.insert(call.declaration);
144 referenced_names.insert(call.name);
146 TraversingVisitor::visit(call);
149 void InlineContentInjector::visit(VariableDeclaration &var)
151 TraversingVisitor::visit(var);
155 if(remap_names==2 || referenced_names.count(var.name))
157 string mapped_name = get_unused_variable_name(*target_block, var.name, remap_prefix);
158 variable_map[var.name] = &var;
159 var.name = mapped_name;
162 else if(var.type_declaration)
164 SetFlag set_deps(deps_only);
165 dependencies.insert(var.type_declaration);
166 referenced_names.insert(var.type_declaration->name);
167 var.type_declaration->visit(*this);
171 void InlineContentInjector::visit(Return &ret)
173 TraversingVisitor::visit(ret);
175 if(!remap_names && ret.expression)
177 /* Create a new variable to hold the return value of the inlined
179 r_result_name = get_unused_variable_name(*target_block, "_return", source_func->name);
180 RefPtr<VariableDeclaration> var = new VariableDeclaration;
181 var->source = ret.source;
182 var->line = ret.line;
183 var->type = source_func->return_type;
184 var->name = r_result_name;
185 var->init_expression = ret.expression->clone();
186 r_inlined_statement = var;
191 FunctionInliner::FunctionInliner():
196 bool FunctionInliner::apply(Stage &s)
199 inlineable = InlineableFunctionLocator().apply(s);
200 r_any_inlined = false;
201 s.content.visit(*this);
202 return r_any_inlined;
205 void FunctionInliner::visit(RefPtr<Expression> &ptr)
211 ptr = r_inline_result;
212 r_any_inlined = true;
217 void FunctionInliner::visit(Block &block)
219 SetForScope<Block *> set_block(current_block, &block);
220 SetForScope<NodeList<Statement>::iterator> save_insert_point(insert_point, block.body.begin());
221 for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
228 void FunctionInliner::visit(FunctionCall &call)
230 for(NodeArray<Expression>::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
233 FunctionDeclaration *def = call.declaration;
235 def = def->definition;
237 if(def && inlineable.count(def))
239 string result_name = InlineContentInjector().apply(*stage, *current_function, *current_block, insert_point, *def);
241 // This will later get removed by UnusedVariableRemover.
242 if(result_name.empty())
243 result_name = "msp_unused_from_inline";
245 RefPtr<VariableReference> ref = new VariableReference;
246 ref->name = result_name;
247 r_inline_result = ref;
249 /* Inlined variables need to be resolved before this function can be
251 inlineable.erase(current_function);
255 void FunctionInliner::visit(FunctionDeclaration &func)
257 SetForScope<FunctionDeclaration *> set_func(current_function, &func);
258 TraversingVisitor::visit(func);
261 void FunctionInliner::visit(Iteration &iter)
263 /* Visit the initialization statement before entering the loop body so the
264 inlined statements get inserted outside. */
265 if(iter.init_statement)
266 iter.init_statement->visit(*this);
268 SetForScope<Block *> set_block(current_block, &iter.body);
269 /* Skip the condition and loop expression parts because they're not properly
270 inside the body block. Inlining anything into them will require a more
271 comprehensive transformation. */
272 iter.body.visit(*this);
276 ExpressionInliner::ExpressionInfo::ExpressionInfo():
285 ExpressionInliner::ExpressionInliner():
287 r_any_inlined(false),
290 iteration_init(false),
295 bool ExpressionInliner::apply(Stage &s)
297 s.content.visit(*this);
298 return r_any_inlined;
301 void ExpressionInliner::inline_expression(Expression &expr, RefPtr<Expression> &ptr)
304 r_any_inlined = true;
307 void ExpressionInliner::visit(Block &block)
309 TraversingVisitor::visit(block);
311 for(map<string, VariableDeclaration *>::iterator i=block.variables.begin(); i!=block.variables.end(); ++i)
313 map<Assignment::Target, ExpressionInfo>::iterator j = expressions.lower_bound(i->second);
314 for(; (j!=expressions.end() && j->first.declaration==i->second); )
316 if(j->second.expression && j->second.inline_point)
317 inline_expression(*j->second.expression, *j->second.inline_point);
319 expressions.erase(j++);
323 /* Expressions assigned in this block may depend on local variables of the
324 block. If this is a conditionally executed block, the assignments might not
325 always happen. Mark the expressions as not available to any outer blocks. */
326 for(map<Assignment::Target, ExpressionInfo>::iterator i=expressions.begin(); i!=expressions.end(); ++i)
327 if(i->second.assign_scope==&block)
328 i->second.available = false;
331 void ExpressionInliner::visit(RefPtr<Expression> &expr)
335 if(r_ref_info && r_ref_info->expression && r_ref_info->available)
337 if(iteration_body && !r_ref_info->trivial)
339 /* Don't inline non-trivial expressions which were assigned outside
340 an iteration statement. The iteration may run multiple times, which
341 would cause the expression to also be evaluated multiple times. */
342 Block *i = r_ref_info->assign_scope;
343 for(; (i && i!=iteration_body); i=i->parent) ;
348 if(r_ref_info->trivial)
349 inline_expression(*r_ref_info->expression, expr);
351 /* Record the inline point for a non-trivial expression but don't
352 inline it yet. It might turn out it shouldn't be inlined after all. */
353 r_ref_info->inline_point = &expr;
359 void ExpressionInliner::visit(VariableReference &var)
363 map<Assignment::Target, ExpressionInfo>::iterator i = expressions.find(var.declaration);
364 if(i!=expressions.end())
366 /* If a non-trivial expression is referenced multiple times, don't
368 if(i->second.inline_point && !i->second.trivial)
369 i->second.expression = 0;
370 /* Mutating expressions are analogous to self-referencing assignments
371 and prevent inlining. */
373 i->second.expression = 0;
374 r_ref_info = &i->second;
379 void ExpressionInliner::visit(MemberAccess &memacc)
385 void ExpressionInliner::visit(Swizzle &swizzle)
391 void ExpressionInliner::visit(UnaryExpression &unary)
393 SetFlag set_target(mutating, mutating || unary.oper->token[1]=='+' || unary.oper->token[1]=='-');
394 visit(unary.expression);
398 void ExpressionInliner::visit(BinaryExpression &binary)
402 SetFlag clear_target(mutating, false);
408 void ExpressionInliner::visit(Assignment &assign)
411 SetFlag set_target(mutating);
417 map<Assignment::Target, ExpressionInfo>::iterator i = expressions.find(assign.target);
418 if(i!=expressions.end())
420 /* Self-referencing assignments can't be inlined without additional
421 work. Just clear any previous expression. */
422 i->second.expression = (assign.self_referencing ? 0 : assign.right.get());
423 i->second.assign_scope = current_block;
424 i->second.inline_point = 0;
425 i->second.available = true;
431 void ExpressionInliner::visit(TernaryExpression &ternary)
433 visit(ternary.condition);
434 visit(ternary.true_expr);
435 visit(ternary.false_expr);
439 void ExpressionInliner::visit(FunctionCall &call)
441 TraversingVisitor::visit(call);
445 void ExpressionInliner::visit(VariableDeclaration &var)
449 TraversingVisitor::visit(var);
451 bool constant = var.constant;
452 if(constant && var.layout)
454 for(vector<Layout::Qualifier>::const_iterator i=var.layout->qualifiers.begin(); (constant && i!=var.layout->qualifiers.end()); ++i)
455 constant = (i->name!="constant_id");
458 /* Only inline global variables if they're constant and have trivial
459 initializers. Non-constant variables could change in ways which are hard to
460 analyze and non-trivial expressions could be expensive to inline. */
461 if((current_block->parent || (constant && r_trivial)) && var.interface.empty())
463 ExpressionInfo &info = expressions[&var];
464 /* Assume variables declared in an iteration initialization statement
465 will have their values change throughout the iteration. */
466 info.expression = (iteration_init ? 0 : var.init_expression.get());
467 info.assign_scope = current_block;
468 info.trivial = r_trivial;
472 void ExpressionInliner::visit(Iteration &iter)
474 SetForScope<Block *> set_block(current_block, &iter.body);
475 if(iter.init_statement)
477 SetFlag set_init(iteration_init);
478 iter.init_statement->visit(*this);
481 SetForScope<Block *> set_body(iteration_body, &iter.body);
483 visit(iter.condition);
484 iter.body.visit(*this);
485 if(iter.loop_expression)
486 visit(iter.loop_expression);
490 BasicTypeDeclaration::Kind ConstantFolder::get_value_kind(const Variant &value)
492 if(value.check_type<bool>())
493 return BasicTypeDeclaration::BOOL;
494 else if(value.check_type<int>())
495 return BasicTypeDeclaration::INT;
496 else if(value.check_type<float>())
497 return BasicTypeDeclaration::FLOAT;
499 return BasicTypeDeclaration::VOID;
503 T ConstantFolder::evaluate_logical(char oper, T left, T right)
507 case '&': return left&right;
508 case '|': return left|right;
509 case '^': return left^right;
515 bool ConstantFolder::evaluate_relation(const char *oper, T left, T right)
517 switch(oper[0]|oper[1])
519 case '<': return left<right;
520 case '<'|'=': return left<=right;
521 case '>': return left>right;
522 case '>'|'=': return left>=right;
523 default: return false;
528 T ConstantFolder::evaluate_arithmetic(char oper, T left, T right)
532 case '+': return left+right;
533 case '-': return left-right;
534 case '*': return left*right;
535 case '/': return left/right;
540 void ConstantFolder::set_result(const Variant &value, bool literal)
542 r_constant_value = value;
547 void ConstantFolder::visit(RefPtr<Expression> &expr)
549 r_constant_value = Variant();
552 r_uses_iter_var = false;
554 /* Don't replace literals since they'd only be replaced with an identical
555 literal. Also skip anything that uses an iteration variable, but pass on
556 the result so the Iteration visiting function can handle it. */
557 if(!r_constant || r_literal || r_uses_iter_var)
560 BasicTypeDeclaration::Kind kind = get_value_kind(r_constant_value);
561 if(kind==BasicTypeDeclaration::VOID)
567 RefPtr<Literal> literal = new Literal;
568 if(kind==BasicTypeDeclaration::BOOL)
569 literal->token = (r_constant_value.value<bool>() ? "true" : "false");
570 else if(kind==BasicTypeDeclaration::INT)
571 literal->token = lexical_cast<string>(r_constant_value.value<int>());
572 else if(kind==BasicTypeDeclaration::FLOAT)
573 literal->token = lexical_cast<string>(r_constant_value.value<float>());
574 literal->value = r_constant_value;
578 void ConstantFolder::visit(Literal &literal)
580 set_result(literal.value, true);
583 void ConstantFolder::visit(VariableReference &var)
585 /* If an iteration variable is initialized with a constant value, return
586 that value here for the purpose of evaluating the loop condition for the
588 if(var.declaration==iteration_var)
590 set_result(iter_init_value);
591 r_uses_iter_var = true;
595 void ConstantFolder::visit(MemberAccess &memacc)
597 TraversingVisitor::visit(memacc);
601 void ConstantFolder::visit(Swizzle &swizzle)
603 TraversingVisitor::visit(swizzle);
607 void ConstantFolder::visit(UnaryExpression &unary)
609 TraversingVisitor::visit(unary);
610 bool can_fold = r_constant;
615 BasicTypeDeclaration::Kind kind = get_value_kind(r_constant_value);
617 char oper = unary.oper->token[0];
618 char oper2 = unary.oper->token[1];
621 if(kind==BasicTypeDeclaration::BOOL)
622 set_result(!r_constant_value.value<bool>());
626 if(kind==BasicTypeDeclaration::INT)
627 set_result(~r_constant_value.value<int>());
629 else if(oper=='-' && !oper2)
631 if(kind==BasicTypeDeclaration::INT)
632 set_result(-r_constant_value.value<int>());
633 else if(kind==BasicTypeDeclaration::FLOAT)
634 set_result(-r_constant_value.value<float>());
638 void ConstantFolder::visit(BinaryExpression &binary)
641 bool left_constant = r_constant;
642 bool left_iter_var = r_uses_iter_var;
643 Variant left_value = r_constant_value;
646 r_uses_iter_var = true;
648 bool can_fold = (left_constant && r_constant);
653 BasicTypeDeclaration::Kind left_kind = get_value_kind(left_value);
654 BasicTypeDeclaration::Kind right_kind = get_value_kind(r_constant_value);
655 // Currently only expressions with both sides of equal types are handled.
656 if(left_kind!=right_kind)
659 char oper = binary.oper->token[0];
660 char oper2 = binary.oper->token[1];
661 if(oper=='&' || oper=='|' || oper=='^')
663 if(oper2==oper && left_kind==BasicTypeDeclaration::BOOL)
664 set_result(evaluate_logical(oper, left_value.value<bool>(), r_constant_value.value<bool>()));
665 else if(!oper2 && left_kind==BasicTypeDeclaration::INT)
666 set_result(evaluate_logical(oper, left_value.value<int>(), r_constant_value.value<int>()));
668 else if((oper=='<' || oper=='>') && oper2!=oper)
670 if(left_kind==BasicTypeDeclaration::INT)
671 set_result(evaluate_relation(binary.oper->token, left_value.value<int>(), r_constant_value.value<int>()));
672 else if(left_kind==BasicTypeDeclaration::FLOAT)
673 set_result(evaluate_relation(binary.oper->token, left_value.value<float>(), r_constant_value.value<float>()));
675 else if((oper=='=' || oper=='!') && oper2=='=')
677 if(left_kind==BasicTypeDeclaration::INT)
678 set_result((left_value.value<int>()==r_constant_value.value<int>()) == (oper=='='));
679 if(left_kind==BasicTypeDeclaration::FLOAT)
680 set_result((left_value.value<float>()==r_constant_value.value<float>()) == (oper=='='));
682 else if(oper=='+' || oper=='-' || oper=='*' || oper=='/')
684 if(left_kind==BasicTypeDeclaration::INT)
685 set_result(evaluate_arithmetic(oper, left_value.value<int>(), r_constant_value.value<int>()));
686 else if(left_kind==BasicTypeDeclaration::FLOAT)
687 set_result(evaluate_arithmetic(oper, left_value.value<float>(), r_constant_value.value<float>()));
689 else if(oper=='%' || ((oper=='<' || oper=='>') && oper2==oper))
691 if(left_kind!=BasicTypeDeclaration::INT)
695 set_result(left_value.value<int>()%r_constant_value.value<int>());
697 set_result(left_value.value<int>()<<r_constant_value.value<int>());
699 set_result(left_value.value<int>()>>r_constant_value.value<int>());
703 void ConstantFolder::visit(Assignment &assign)
705 TraversingVisitor::visit(assign);
709 void ConstantFolder::visit(TernaryExpression &ternary)
711 TraversingVisitor::visit(ternary);
715 void ConstantFolder::visit(FunctionCall &call)
717 TraversingVisitor::visit(call);
721 void ConstantFolder::visit(VariableDeclaration &var)
723 if(iteration_init && var.init_expression)
725 visit(var.init_expression);
728 /* Record the value of a constant initialization expression of an
729 iteration, so it can be used to evaluate the loop condition. */
730 iteration_var = &var;
731 iter_init_value = r_constant_value;
735 TraversingVisitor::visit(var);
738 void ConstantFolder::visit(Iteration &iter)
740 SetForScope<Block *> set_block(current_block, &iter.body);
742 /* The iteration variable is not normally inlined into expressions, so we
743 process it specially here. If the initial value causes the loop condition
744 to evaluate to false, then the expression can be folded. */
746 if(iter.init_statement)
748 SetFlag set_init(iteration_init);
749 iter.init_statement->visit(*this);
754 visit(iter.condition);
755 if(r_constant && r_constant_value.check_type<bool>() && !r_constant_value.value<bool>())
757 RefPtr<Literal> literal = new Literal;
758 literal->token = "false";
759 literal->value = r_constant_value;
760 iter.condition = literal;
765 iter.body.visit(*this);
766 if(iter.loop_expression)
767 visit(iter.loop_expression);
771 void ConstantConditionEliminator::apply(Stage &stage)
773 stage.content.visit(*this);
774 NodeRemover().apply(stage, nodes_to_remove);
777 ConstantConditionEliminator::ConstantStatus ConstantConditionEliminator::check_constant_condition(const Expression &expr)
779 if(const Literal *literal = dynamic_cast<const Literal *>(&expr))
780 if(literal->value.check_type<bool>())
781 return (literal->value.value<bool>() ? CONSTANT_TRUE : CONSTANT_FALSE);
785 void ConstantConditionEliminator::visit(Block &block)
787 SetForScope<Block *> set_block(current_block, &block);
788 for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
795 void ConstantConditionEliminator::visit(RefPtr<Expression> &expr)
797 r_ternary_result = 0;
800 expr = r_ternary_result;
801 r_ternary_result = 0;
804 void ConstantConditionEliminator::visit(TernaryExpression &ternary)
806 ConstantStatus result = check_constant_condition(*ternary.condition);
807 if(result!=NOT_CONSTANT)
808 r_ternary_result = (result==CONSTANT_TRUE ? ternary.true_expr : ternary.false_expr);
810 r_ternary_result = 0;
813 void ConstantConditionEliminator::visit(Conditional &cond)
815 ConstantStatus result = check_constant_condition(*cond.condition);
816 if(result!=NOT_CONSTANT)
818 Block &block = (result==CONSTANT_TRUE ? cond.body : cond.else_body);
819 // TODO should check variable names for conflicts. Potentially reuse InlineContentInjector?
820 current_block->body.splice(insert_point, block.body);
821 nodes_to_remove.insert(&cond);
825 TraversingVisitor::visit(cond);
828 void ConstantConditionEliminator::visit(Iteration &iter)
832 ConstantStatus result = check_constant_condition(*iter.condition);
833 if(result==CONSTANT_FALSE)
835 nodes_to_remove.insert(&iter);
840 TraversingVisitor::visit(iter);
844 bool UnusedTypeRemover::apply(Stage &stage)
846 stage.content.visit(*this);
847 NodeRemover().apply(stage, unused_nodes);
848 return !unused_nodes.empty();
851 void UnusedTypeRemover::visit(Literal &literal)
853 unused_nodes.erase(literal.type);
856 void UnusedTypeRemover::visit(UnaryExpression &unary)
858 unused_nodes.erase(unary.type);
859 TraversingVisitor::visit(unary);
862 void UnusedTypeRemover::visit(BinaryExpression &binary)
864 unused_nodes.erase(binary.type);
865 TraversingVisitor::visit(binary);
868 void UnusedTypeRemover::visit(TernaryExpression &ternary)
870 unused_nodes.erase(ternary.type);
871 TraversingVisitor::visit(ternary);
874 void UnusedTypeRemover::visit(FunctionCall &call)
876 unused_nodes.erase(call.type);
877 TraversingVisitor::visit(call);
880 void UnusedTypeRemover::visit(BasicTypeDeclaration &type)
883 unused_nodes.erase(type.base_type);
884 unused_nodes.insert(&type);
887 void UnusedTypeRemover::visit(ImageTypeDeclaration &type)
890 unused_nodes.erase(type.base_type);
891 unused_nodes.insert(&type);
894 void UnusedTypeRemover::visit(StructDeclaration &strct)
896 unused_nodes.insert(&strct);
897 TraversingVisitor::visit(strct);
900 void UnusedTypeRemover::visit(VariableDeclaration &var)
902 unused_nodes.erase(var.type_declaration);
905 void UnusedTypeRemover::visit(InterfaceBlock &iface)
907 unused_nodes.erase(iface.type_declaration);
910 void UnusedTypeRemover::visit(FunctionDeclaration &func)
912 unused_nodes.erase(func.return_type_declaration);
913 TraversingVisitor::visit(func);
917 UnusedVariableRemover::UnusedVariableRemover():
921 assignment_target(false),
922 r_side_effects(false)
925 bool UnusedVariableRemover::apply(Stage &s)
928 s.content.visit(*this);
930 for(list<AssignmentInfo>::const_iterator i=assignments.begin(); i!=assignments.end(); ++i)
931 if(i->used_by.empty())
932 unused_nodes.insert(i->node);
934 for(map<string, InterfaceBlock *>::const_iterator i=s.interface_blocks.begin(); i!=s.interface_blocks.end(); ++i)
935 if(i->second->instance_name.empty())
936 unused_nodes.insert(i->second);
938 for(BlockVariableMap::const_iterator i=variables.begin(); i!=variables.end(); ++i)
942 /* The last visible assignments of output variables are used by the
943 next stage or the API. */
944 for(vector<AssignmentInfo *>::const_iterator j=i->second.assignments.begin(); j!=i->second.assignments.end(); ++j)
945 unused_nodes.erase((*j)->node);
948 if(!i->second.output && !i->second.referenced)
950 // Don't remove variables from inside interface blocks.
951 if(!i->second.interface_block)
952 unused_nodes.insert(i->first);
954 else if(i->second.interface_block)
955 // Interface blocks are kept if even one member is used.
956 unused_nodes.erase(i->second.interface_block);
959 NodeRemover().apply(s, unused_nodes);
961 return !unused_nodes.empty();
964 void UnusedVariableRemover::referenced(const Assignment::Target &target, Node &node)
966 VariableInfo &var_info = variables[target.declaration];
967 var_info.referenced = true;
968 if(!assignment_target)
970 for(vector<AssignmentInfo *>::const_iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i)
971 (*i)->used_by.push_back(&node);
975 void UnusedVariableRemover::visit(VariableReference &var)
977 referenced(var.declaration, var);
980 void UnusedVariableRemover::visit(InterfaceBlockReference &iface)
982 referenced(iface.declaration, iface);
985 void UnusedVariableRemover::visit(UnaryExpression &unary)
987 TraversingVisitor::visit(unary);
988 if(unary.oper->token[1]=='+' || unary.oper->token[1]=='-')
989 r_side_effects = true;
992 void UnusedVariableRemover::visit(BinaryExpression &binary)
994 if(binary.oper->token[0]=='[')
996 binary.left->visit(*this);
997 SetFlag set(assignment_target, false);
998 binary.right->visit(*this);
1001 TraversingVisitor::visit(binary);
1004 void UnusedVariableRemover::visit(Assignment &assign)
1007 SetFlag set(assignment_target, (assign.oper->token[0]=='='));
1008 assign.left->visit(*this);
1010 assign.right->visit(*this);
1011 r_assignment = &assign;
1012 r_side_effects = true;
1015 void UnusedVariableRemover::visit(FunctionCall &call)
1017 TraversingVisitor::visit(call);
1018 /* Treat function calls as having side effects so expression statements
1019 consisting of nothing but a function call won't be optimized away. */
1020 r_side_effects = true;
1022 if(stage->type==Stage::GEOMETRY && call.name=="EmitVertex")
1024 for(map<Statement *, VariableInfo>::const_iterator i=variables.begin(); i!=variables.end(); ++i)
1025 if(i->second.output)
1026 referenced(i->first, call);
1030 void UnusedVariableRemover::record_assignment(const Assignment::Target &target, Node &node)
1032 assignments.push_back(AssignmentInfo());
1033 AssignmentInfo &assign_info = assignments.back();
1034 assign_info.node = &node;
1035 assign_info.target = target;
1037 /* An assignment to the target hides any assignments to the same target or
1039 VariableInfo &var_info = variables[target.declaration];
1040 for(unsigned i=0; i<var_info.assignments.size(); ++i)
1042 const Assignment::Target &t = var_info.assignments[i]->target;
1044 bool subfield = (t.chain_len>=target.chain_len);
1045 for(unsigned j=0; (subfield && j<target.chain_len); ++j)
1046 subfield = (t.chain[j]==target.chain[j]);
1049 var_info.assignments.erase(var_info.assignments.begin()+i);
1054 var_info.assignments.push_back(&assign_info);
1057 void UnusedVariableRemover::visit(ExpressionStatement &expr)
1060 r_side_effects = false;
1061 TraversingVisitor::visit(expr);
1062 if(r_assignment && r_assignment->target.declaration)
1063 record_assignment(r_assignment->target, expr);
1065 unused_nodes.insert(&expr);
1068 void UnusedVariableRemover::visit(VariableDeclaration &var)
1070 VariableInfo &var_info = variables[&var];
1071 var_info.interface_block = interface_block;
1073 /* Mark variables as output if they're used by the next stage or the
1076 var_info.output = (interface_block->interface=="out" && (interface_block->linked_block || !interface_block->name.compare(0, 3, "gl_")));
1078 var_info.output = (var.interface=="out" && (stage->type==Stage::FRAGMENT || var.linked_declaration || !var.name.compare(0, 3, "gl_")));
1080 if(var.init_expression)
1082 var_info.initialized = true;
1083 record_assignment(&var, *var.init_expression);
1085 TraversingVisitor::visit(var);
1088 void UnusedVariableRemover::visit(InterfaceBlock &iface)
1090 if(iface.instance_name.empty())
1092 SetForScope<InterfaceBlock *> set_block(interface_block, &iface);
1093 iface.struct_declaration->members.visit(*this);
1097 VariableInfo &var_info = variables[&iface];
1098 var_info.output = (iface.interface=="out" && (iface.linked_block || !iface.name.compare(0, 3, "gl_")));
1102 void UnusedVariableRemover::merge_variables(const BlockVariableMap &other_vars)
1104 for(BlockVariableMap::const_iterator i=other_vars.begin(); i!=other_vars.end(); ++i)
1106 BlockVariableMap::iterator j = variables.find(i->first);
1107 if(j!=variables.end())
1109 /* The merged blocks started as copies of each other so any common
1110 assignments must be in the beginning. */
1112 for(; (k<i->second.assignments.size() && k<j->second.assignments.size()); ++k)
1113 if(i->second.assignments[k]!=j->second.assignments[k])
1116 // Remaining assignments are unique to each block; merge them.
1117 j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin()+k, i->second.assignments.end());
1118 j->second.referenced |= i->second.referenced;
1121 variables.insert(*i);
1125 void UnusedVariableRemover::visit(FunctionDeclaration &func)
1127 if(func.body.body.empty())
1130 BlockVariableMap saved_vars = variables;
1131 // Assignments from other functions should not be visible.
1132 for(BlockVariableMap::iterator i=variables.begin(); i!=variables.end(); ++i)
1133 i->second.assignments.resize(i->second.initialized);
1134 TraversingVisitor::visit(func);
1135 swap(variables, saved_vars);
1136 merge_variables(saved_vars);
1138 /* Always treat function parameters as referenced. Removing unused
1139 parameters is not currently supported. */
1140 for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
1142 BlockVariableMap::iterator j = variables.find(i->get());
1143 if(j!=variables.end())
1144 j->second.referenced = true;
1148 void UnusedVariableRemover::visit(Conditional &cond)
1150 cond.condition->visit(*this);
1151 BlockVariableMap saved_vars = variables;
1152 cond.body.visit(*this);
1153 swap(saved_vars, variables);
1154 cond.else_body.visit(*this);
1156 /* Visible assignments after the conditional is the union of those visible
1157 at the end of the if and else blocks. If there was no else block, then it's
1158 the union of the if block and the state before it. */
1159 merge_variables(saved_vars);
1162 void UnusedVariableRemover::visit(Iteration &iter)
1164 BlockVariableMap saved_vars = variables;
1165 TraversingVisitor::visit(iter);
1167 /* Merge assignments from the iteration, without clearing previous state.
1168 Further analysis is needed to determine which parts of the iteration body
1169 are always executed, if any. */
1170 merge_variables(saved_vars);
1174 bool UnusedFunctionRemover::apply(Stage &stage)
1176 stage.content.visit(*this);
1177 NodeRemover().apply(stage, unused_nodes);
1178 return !unused_nodes.empty();
1181 void UnusedFunctionRemover::visit(FunctionCall &call)
1183 TraversingVisitor::visit(call);
1185 unused_nodes.erase(call.declaration);
1186 if(call.declaration && call.declaration->definition!=call.declaration)
1187 used_definitions.insert(call.declaration->definition);
1190 void UnusedFunctionRemover::visit(FunctionDeclaration &func)
1192 TraversingVisitor::visit(func);
1194 if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func))
1195 unused_nodes.insert(&func);