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():
72 const string &InlineContentInjector::apply(Stage &stage, FunctionDeclaration &target_func, Block &tgt_blk, const NodeList<Statement>::iterator &ins_pt, FunctionDeclaration &src)
74 target_block = &tgt_blk;
76 remap_prefix = source_func->name;
78 vector<RefPtr<Statement> > inlined;
79 inlined.reserve(src.body.body.size());
80 for(NodeList<Statement>::iterator i=src.body.body.begin(); i!=src.body.body.end(); ++i)
82 r_inlined_statement = 0;
84 if(!r_inlined_statement)
85 r_inlined_statement = (*i)->clone();
87 SetForScope<unsigned> set_remap(remap_names, 2);
88 r_inlined_statement->visit(*this);
89 inlined.push_back(r_inlined_statement);
92 SetForScope<unsigned> set_remap(remap_names, 1);
93 SetForScope<string> set_prefix(remap_prefix, target_func.name);
95 target_func.visit(*this);
97 tgt_blk.body.insert(ins_pt, inlined.begin(), inlined.end());
99 NodeReorderer().apply(stage, target_func, dependencies);
101 return r_result_name;
104 void InlineContentInjector::visit(VariableReference &var)
108 map<string, VariableDeclaration *>::const_iterator i = variable_map.find(var.name);
109 if(i!=variable_map.end())
110 var.name = i->second->name;
112 else if(var.declaration)
114 if(!variable_map.count(var.name))
116 dependencies.insert(var.declaration);
117 referenced_names.insert(var.name);
119 var.declaration->visit(*this);
123 void InlineContentInjector::visit(InterfaceBlockReference &iface)
125 if(!remap_names && iface.declaration)
127 dependencies.insert(iface.declaration);
128 referenced_names.insert(iface.name);
129 iface.declaration->visit(*this);
133 void InlineContentInjector::visit(FunctionCall &call)
135 if(!remap_names && call.declaration)
137 dependencies.insert(call.declaration);
138 referenced_names.insert(call.name);
140 TraversingVisitor::visit(call);
143 void InlineContentInjector::visit(VariableDeclaration &var)
145 TraversingVisitor::visit(var);
149 if(remap_names==2 || referenced_names.count(var.name))
151 string mapped_name = get_unused_variable_name(*target_block, var.name, remap_prefix);
152 variable_map[var.name] = &var;
153 var.name = mapped_name;
156 else if(var.type_declaration)
158 dependencies.insert(var.type_declaration);
159 referenced_names.insert(var.type_declaration->name);
160 var.type_declaration->visit(*this);
164 void InlineContentInjector::visit(Return &ret)
166 TraversingVisitor::visit(ret);
168 if(!remap_names && ret.expression)
170 /* Create a new variable to hold the return value of the inlined
172 r_result_name = get_unused_variable_name(*target_block, "_return", source_func->name);
173 RefPtr<VariableDeclaration> var = new VariableDeclaration;
174 var->source = ret.source;
175 var->line = ret.line;
176 var->type = source_func->return_type;
177 var->name = r_result_name;
178 var->init_expression = ret.expression->clone();
179 r_inlined_statement = var;
184 FunctionInliner::FunctionInliner():
186 r_any_inlined(false),
187 r_inlined_here(false)
190 bool FunctionInliner::apply(Stage &s)
193 inlineable = InlineableFunctionLocator().apply(s);
194 r_any_inlined = false;
195 s.content.visit(*this);
196 return r_any_inlined;
199 void FunctionInliner::visit(RefPtr<Expression> &ptr)
205 ptr = r_inline_result;
206 r_any_inlined = true;
211 void FunctionInliner::visit(Block &block)
213 SetForScope<Block *> set_block(current_block, &block);
214 SetForScope<NodeList<Statement>::iterator> save_insert_point(insert_point, block.body.begin());
215 for(NodeList<Statement>::iterator i=block.body.begin(); (!r_inlined_here && i!=block.body.end()); ++i)
222 void FunctionInliner::visit(FunctionCall &call)
227 for(NodeArray<Expression>::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
230 FunctionDeclaration *def = call.declaration;
232 def = def->definition;
234 if(def && inlineable.count(def))
236 string result_name = InlineContentInjector().apply(*stage, *current_function, *current_block, insert_point, *def);
238 // This will later get removed by UnusedVariableRemover.
239 if(result_name.empty())
240 result_name = "msp_unused_from_inline";
242 RefPtr<VariableReference> ref = new VariableReference;
243 ref->name = result_name;
244 r_inline_result = ref;
246 /* Inlined variables need to be resolved before this function can be
248 inlineable.erase(current_function);
249 r_inlined_here = true;
253 void FunctionInliner::visit(FunctionDeclaration &func)
255 SetForScope<FunctionDeclaration *> set_func(current_function, &func);
256 TraversingVisitor::visit(func);
257 r_inlined_here = false;
260 void FunctionInliner::visit(Iteration &iter)
262 /* Visit the initialization statement before entering the loop body so the
263 inlined statements get inserted outside. */
264 if(iter.init_statement)
265 iter.init_statement->visit(*this);
267 SetForScope<Block *> set_block(current_block, &iter.body);
268 /* Skip the condition and loop expression parts because they're not properly
269 inside the body block. Inlining anything into them will require a more
270 comprehensive transformation. */
271 iter.body.visit(*this);
275 ExpressionInliner::ExpressionInfo::ExpressionInfo():
284 ExpressionInliner::ExpressionInliner():
286 r_any_inlined(false),
289 iteration_init(false),
294 bool ExpressionInliner::apply(Stage &s)
296 s.content.visit(*this);
297 return r_any_inlined;
300 void ExpressionInliner::inline_expression(Expression &expr, RefPtr<Expression> &ptr)
303 r_any_inlined = true;
306 void ExpressionInliner::visit(Block &block)
308 TraversingVisitor::visit(block);
310 for(map<string, VariableDeclaration *>::iterator i=block.variables.begin(); i!=block.variables.end(); ++i)
312 map<Assignment::Target, ExpressionInfo>::iterator j = expressions.lower_bound(i->second);
313 for(; (j!=expressions.end() && j->first.declaration==i->second); )
315 if(j->second.expression && j->second.inline_point)
316 inline_expression(*j->second.expression, *j->second.inline_point);
318 expressions.erase(j++);
322 /* Expressions assigned in this block may depend on local variables of the
323 block. If this is a conditionally executed block, the assignments might not
324 always happen. Mark the expressions as not available to any outer blocks. */
325 for(map<Assignment::Target, ExpressionInfo>::iterator i=expressions.begin(); i!=expressions.end(); ++i)
326 if(i->second.assign_scope==&block)
327 i->second.available = false;
330 void ExpressionInliner::visit(RefPtr<Expression> &expr)
334 if(r_ref_info && r_ref_info->expression && r_ref_info->available)
336 if(iteration_body && !r_ref_info->trivial)
338 /* Don't inline non-trivial expressions which were assigned outside
339 an iteration statement. The iteration may run multiple times, which
340 would cause the expression to also be evaluated multiple times. */
341 Block *i = r_ref_info->assign_scope;
342 for(; (i && i!=iteration_body); i=i->parent) ;
347 if(r_ref_info->trivial)
348 inline_expression(*r_ref_info->expression, expr);
350 /* Record the inline point for a non-trivial expression but don't
351 inline it yet. It might turn out it shouldn't be inlined after all. */
352 r_ref_info->inline_point = &expr;
358 void ExpressionInliner::visit(VariableReference &var)
362 map<Assignment::Target, ExpressionInfo>::iterator i = expressions.find(var.declaration);
363 if(i!=expressions.end())
365 /* If a non-trivial expression is referenced multiple times, don't
367 if(i->second.inline_point && !i->second.trivial)
368 i->second.expression = 0;
369 /* Mutating expressions are analogous to self-referencing assignments
370 and prevent inlining. */
372 i->second.expression = 0;
373 r_ref_info = &i->second;
378 void ExpressionInliner::visit(MemberAccess &memacc)
384 void ExpressionInliner::visit(Swizzle &swizzle)
390 void ExpressionInliner::visit(UnaryExpression &unary)
392 SetFlag set_target(mutating, mutating || unary.oper->token[1]=='+' || unary.oper->token[1]=='-');
393 visit(unary.expression);
397 void ExpressionInliner::visit(BinaryExpression &binary)
401 SetFlag clear_target(mutating, false);
407 void ExpressionInliner::visit(Assignment &assign)
410 SetFlag set_target(mutating);
416 map<Assignment::Target, ExpressionInfo>::iterator i = expressions.find(assign.target);
417 if(i!=expressions.end())
419 /* Self-referencing assignments can't be inlined without additional
420 work. Just clear any previous expression. */
421 i->second.expression = (assign.self_referencing ? 0 : assign.right.get());
422 i->second.assign_scope = current_block;
423 i->second.inline_point = 0;
424 i->second.available = true;
430 void ExpressionInliner::visit(TernaryExpression &ternary)
432 visit(ternary.condition);
433 visit(ternary.true_expr);
434 visit(ternary.false_expr);
438 void ExpressionInliner::visit(FunctionCall &call)
440 TraversingVisitor::visit(call);
444 void ExpressionInliner::visit(VariableDeclaration &var)
448 TraversingVisitor::visit(var);
450 bool constant = var.constant;
451 if(constant && var.layout)
453 for(vector<Layout::Qualifier>::const_iterator i=var.layout->qualifiers.begin(); (constant && i!=var.layout->qualifiers.end()); ++i)
454 constant = (i->name!="constant_id");
457 /* Only inline global variables if they're constant and have trivial
458 initializers. Non-constant variables could change in ways which are hard to
459 analyze and non-trivial expressions could be expensive to inline. */
460 if((current_block->parent || (constant && r_trivial)) && var.interface.empty())
462 ExpressionInfo &info = expressions[&var];
463 /* Assume variables declared in an iteration initialization statement
464 will have their values change throughout the iteration. */
465 info.expression = (iteration_init ? 0 : var.init_expression.get());
466 info.assign_scope = current_block;
467 info.trivial = r_trivial;
471 void ExpressionInliner::visit(Iteration &iter)
473 SetForScope<Block *> set_block(current_block, &iter.body);
474 if(iter.init_statement)
476 SetFlag set_init(iteration_init);
477 iter.init_statement->visit(*this);
480 SetForScope<Block *> set_body(iteration_body, &iter.body);
482 visit(iter.condition);
483 iter.body.visit(*this);
484 if(iter.loop_expression)
485 visit(iter.loop_expression);
489 BasicTypeDeclaration::Kind ConstantFolder::get_value_kind(const Variant &value)
491 if(value.check_type<bool>())
492 return BasicTypeDeclaration::BOOL;
493 else if(value.check_type<int>())
494 return BasicTypeDeclaration::INT;
495 else if(value.check_type<float>())
496 return BasicTypeDeclaration::FLOAT;
498 return BasicTypeDeclaration::VOID;
502 T ConstantFolder::evaluate_logical(char oper, T left, T right)
506 case '&': return left&right;
507 case '|': return left|right;
508 case '^': return left^right;
514 bool ConstantFolder::evaluate_relation(const char *oper, T left, T right)
516 switch(oper[0]|oper[1])
518 case '<': return left<right;
519 case '<'|'=': return left<=right;
520 case '>': return left>right;
521 case '>'|'=': return left>=right;
522 default: return false;
527 T ConstantFolder::evaluate_arithmetic(char oper, T left, T right)
531 case '+': return left+right;
532 case '-': return left-right;
533 case '*': return left*right;
534 case '/': return left/right;
539 void ConstantFolder::set_result(const Variant &value, bool literal)
541 r_constant_value = value;
546 void ConstantFolder::visit(RefPtr<Expression> &expr)
548 r_constant_value = Variant();
551 r_uses_iter_var = false;
553 /* Don't replace literals since they'd only be replaced with an identical
554 literal. Also skip anything that uses an iteration variable, but pass on
555 the result so the Iteration visiting function can handle it. */
556 if(!r_constant || r_literal || r_uses_iter_var)
559 BasicTypeDeclaration::Kind kind = get_value_kind(r_constant_value);
560 if(kind==BasicTypeDeclaration::VOID)
566 RefPtr<Literal> literal = new Literal;
567 if(kind==BasicTypeDeclaration::BOOL)
568 literal->token = (r_constant_value.value<bool>() ? "true" : "false");
569 else if(kind==BasicTypeDeclaration::INT)
570 literal->token = lexical_cast<string>(r_constant_value.value<int>());
571 else if(kind==BasicTypeDeclaration::FLOAT)
572 literal->token = lexical_cast<string>(r_constant_value.value<float>());
573 literal->value = r_constant_value;
577 void ConstantFolder::visit(Literal &literal)
579 set_result(literal.value, true);
582 void ConstantFolder::visit(VariableReference &var)
584 /* If an iteration variable is initialized with a constant value, return
585 that value here for the purpose of evaluating the loop condition for the
587 if(var.declaration==iteration_var)
589 set_result(iter_init_value);
590 r_uses_iter_var = true;
594 void ConstantFolder::visit(MemberAccess &memacc)
596 TraversingVisitor::visit(memacc);
600 void ConstantFolder::visit(Swizzle &swizzle)
602 TraversingVisitor::visit(swizzle);
606 void ConstantFolder::visit(UnaryExpression &unary)
608 TraversingVisitor::visit(unary);
609 bool can_fold = r_constant;
614 BasicTypeDeclaration::Kind kind = get_value_kind(r_constant_value);
616 char oper = unary.oper->token[0];
617 char oper2 = unary.oper->token[1];
620 if(kind==BasicTypeDeclaration::BOOL)
621 set_result(!r_constant_value.value<bool>());
625 if(kind==BasicTypeDeclaration::INT)
626 set_result(~r_constant_value.value<int>());
628 else if(oper=='-' && !oper2)
630 if(kind==BasicTypeDeclaration::INT)
631 set_result(-r_constant_value.value<int>());
632 else if(kind==BasicTypeDeclaration::FLOAT)
633 set_result(-r_constant_value.value<float>());
637 void ConstantFolder::visit(BinaryExpression &binary)
640 bool left_constant = r_constant;
641 bool left_iter_var = r_uses_iter_var;
642 Variant left_value = r_constant_value;
645 r_uses_iter_var = true;
647 bool can_fold = (left_constant && r_constant);
652 BasicTypeDeclaration::Kind left_kind = get_value_kind(left_value);
653 BasicTypeDeclaration::Kind right_kind = get_value_kind(r_constant_value);
654 // Currently only expressions with both sides of equal types are handled.
655 if(left_kind!=right_kind)
658 char oper = binary.oper->token[0];
659 char oper2 = binary.oper->token[1];
660 if(oper=='&' || oper=='|' || oper=='^')
662 if(oper2==oper && left_kind==BasicTypeDeclaration::BOOL)
663 set_result(evaluate_logical(oper, left_value.value<bool>(), r_constant_value.value<bool>()));
664 else if(!oper2 && left_kind==BasicTypeDeclaration::INT)
665 set_result(evaluate_logical(oper, left_value.value<int>(), r_constant_value.value<int>()));
667 else if((oper=='<' || oper=='>') && oper2!=oper)
669 if(left_kind==BasicTypeDeclaration::INT)
670 set_result(evaluate_relation(binary.oper->token, left_value.value<int>(), r_constant_value.value<int>()));
671 else if(left_kind==BasicTypeDeclaration::FLOAT)
672 set_result(evaluate_relation(binary.oper->token, left_value.value<float>(), r_constant_value.value<float>()));
674 else if((oper=='=' || oper=='!') && oper2=='=')
676 if(left_kind==BasicTypeDeclaration::INT)
677 set_result((left_value.value<int>()==r_constant_value.value<int>()) == (oper=='='));
678 if(left_kind==BasicTypeDeclaration::FLOAT)
679 set_result((left_value.value<float>()==r_constant_value.value<float>()) == (oper=='='));
681 else if(oper=='+' || oper=='-' || oper=='*' || oper=='/')
683 if(left_kind==BasicTypeDeclaration::INT)
684 set_result(evaluate_arithmetic(oper, left_value.value<int>(), r_constant_value.value<int>()));
685 else if(left_kind==BasicTypeDeclaration::FLOAT)
686 set_result(evaluate_arithmetic(oper, left_value.value<float>(), r_constant_value.value<float>()));
688 else if(oper=='%' || ((oper=='<' || oper=='>') && oper2==oper))
690 if(left_kind!=BasicTypeDeclaration::INT)
694 set_result(left_value.value<int>()%r_constant_value.value<int>());
696 set_result(left_value.value<int>()<<r_constant_value.value<int>());
698 set_result(left_value.value<int>()>>r_constant_value.value<int>());
702 void ConstantFolder::visit(Assignment &assign)
704 TraversingVisitor::visit(assign);
708 void ConstantFolder::visit(TernaryExpression &ternary)
710 TraversingVisitor::visit(ternary);
714 void ConstantFolder::visit(FunctionCall &call)
716 TraversingVisitor::visit(call);
720 void ConstantFolder::visit(VariableDeclaration &var)
722 if(iteration_init && var.init_expression)
724 visit(var.init_expression);
727 /* Record the value of a constant initialization expression of an
728 iteration, so it can be used to evaluate the loop condition. */
729 iteration_var = &var;
730 iter_init_value = r_constant_value;
734 TraversingVisitor::visit(var);
737 void ConstantFolder::visit(Iteration &iter)
739 SetForScope<Block *> set_block(current_block, &iter.body);
741 /* The iteration variable is not normally inlined into expressions, so we
742 process it specially here. If the initial value causes the loop condition
743 to evaluate to false, then the expression can be folded. */
745 if(iter.init_statement)
747 SetFlag set_init(iteration_init);
748 iter.init_statement->visit(*this);
753 visit(iter.condition);
754 if(r_constant && r_constant_value.check_type<bool>() && !r_constant_value.value<bool>())
756 RefPtr<Literal> literal = new Literal;
757 literal->token = "false";
758 literal->value = r_constant_value;
759 iter.condition = literal;
764 iter.body.visit(*this);
765 if(iter.loop_expression)
766 visit(iter.loop_expression);
770 void ConstantConditionEliminator::apply(Stage &stage)
772 stage.content.visit(*this);
773 NodeRemover().apply(stage, nodes_to_remove);
776 ConstantConditionEliminator::ConstantStatus ConstantConditionEliminator::check_constant_condition(const Expression &expr)
778 if(const Literal *literal = dynamic_cast<const Literal *>(&expr))
779 if(literal->value.check_type<bool>())
780 return (literal->value.value<bool>() ? CONSTANT_TRUE : CONSTANT_FALSE);
784 void ConstantConditionEliminator::visit(Block &block)
786 SetForScope<Block *> set_block(current_block, &block);
787 for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
794 void ConstantConditionEliminator::visit(RefPtr<Expression> &expr)
796 r_ternary_result = 0;
799 expr = r_ternary_result;
800 r_ternary_result = 0;
803 void ConstantConditionEliminator::visit(TernaryExpression &ternary)
805 ConstantStatus result = check_constant_condition(*ternary.condition);
806 if(result!=NOT_CONSTANT)
807 r_ternary_result = (result==CONSTANT_TRUE ? ternary.true_expr : ternary.false_expr);
809 r_ternary_result = 0;
812 void ConstantConditionEliminator::visit(Conditional &cond)
814 ConstantStatus result = check_constant_condition(*cond.condition);
815 if(result!=NOT_CONSTANT)
817 Block &block = (result==CONSTANT_TRUE ? cond.body : cond.else_body);
818 // TODO should check variable names for conflicts. Potentially reuse InlineContentInjector?
819 current_block->body.splice(insert_point, block.body);
820 nodes_to_remove.insert(&cond);
824 TraversingVisitor::visit(cond);
827 void ConstantConditionEliminator::visit(Iteration &iter)
831 ConstantStatus result = check_constant_condition(*iter.condition);
832 if(result==CONSTANT_FALSE)
834 nodes_to_remove.insert(&iter);
839 TraversingVisitor::visit(iter);
843 bool UnusedTypeRemover::apply(Stage &stage)
845 stage.content.visit(*this);
846 NodeRemover().apply(stage, unused_nodes);
847 return !unused_nodes.empty();
850 void UnusedTypeRemover::visit(Literal &literal)
852 unused_nodes.erase(literal.type);
855 void UnusedTypeRemover::visit(UnaryExpression &unary)
857 unused_nodes.erase(unary.type);
858 TraversingVisitor::visit(unary);
861 void UnusedTypeRemover::visit(BinaryExpression &binary)
863 unused_nodes.erase(binary.type);
864 TraversingVisitor::visit(binary);
867 void UnusedTypeRemover::visit(TernaryExpression &ternary)
869 unused_nodes.erase(ternary.type);
870 TraversingVisitor::visit(ternary);
873 void UnusedTypeRemover::visit(FunctionCall &call)
875 unused_nodes.erase(call.type);
876 TraversingVisitor::visit(call);
879 void UnusedTypeRemover::visit(BasicTypeDeclaration &type)
882 unused_nodes.erase(type.base_type);
883 unused_nodes.insert(&type);
886 void UnusedTypeRemover::visit(ImageTypeDeclaration &type)
889 unused_nodes.erase(type.base_type);
890 unused_nodes.insert(&type);
893 void UnusedTypeRemover::visit(StructDeclaration &strct)
895 unused_nodes.insert(&strct);
896 TraversingVisitor::visit(strct);
899 void UnusedTypeRemover::visit(VariableDeclaration &var)
901 unused_nodes.erase(var.type_declaration);
904 void UnusedTypeRemover::visit(InterfaceBlock &iface)
906 unused_nodes.erase(iface.type_declaration);
909 void UnusedTypeRemover::visit(FunctionDeclaration &func)
911 unused_nodes.erase(func.return_type_declaration);
912 TraversingVisitor::visit(func);
916 UnusedVariableRemover::UnusedVariableRemover():
920 assignment_target(false),
921 r_side_effects(false)
924 bool UnusedVariableRemover::apply(Stage &s)
927 s.content.visit(*this);
929 for(list<AssignmentInfo>::const_iterator i=assignments.begin(); i!=assignments.end(); ++i)
930 if(i->used_by.empty())
931 unused_nodes.insert(i->node);
933 for(map<string, InterfaceBlock *>::const_iterator i=s.interface_blocks.begin(); i!=s.interface_blocks.end(); ++i)
934 if(i->second->instance_name.empty())
935 unused_nodes.insert(i->second);
937 for(BlockVariableMap::const_iterator i=variables.begin(); i!=variables.end(); ++i)
941 /* The last visible assignments of output variables are used by the
942 next stage or the API. */
943 for(vector<AssignmentInfo *>::const_iterator j=i->second.assignments.begin(); j!=i->second.assignments.end(); ++j)
944 unused_nodes.erase((*j)->node);
947 if(!i->second.output && !i->second.referenced)
949 // Don't remove variables from inside interface blocks.
950 if(!i->second.interface_block)
951 unused_nodes.insert(i->first);
953 else if(i->second.interface_block)
954 // Interface blocks are kept if even one member is used.
955 unused_nodes.erase(i->second.interface_block);
958 NodeRemover().apply(s, unused_nodes);
960 return !unused_nodes.empty();
963 void UnusedVariableRemover::referenced(const Assignment::Target &target, Node &node)
965 VariableInfo &var_info = variables[target.declaration];
966 var_info.referenced = true;
967 if(!assignment_target)
969 for(vector<AssignmentInfo *>::const_iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i)
970 (*i)->used_by.push_back(&node);
974 void UnusedVariableRemover::visit(VariableReference &var)
976 referenced(var.declaration, var);
979 void UnusedVariableRemover::visit(InterfaceBlockReference &iface)
981 referenced(iface.declaration, iface);
984 void UnusedVariableRemover::visit(UnaryExpression &unary)
986 TraversingVisitor::visit(unary);
987 if(unary.oper->token[1]=='+' || unary.oper->token[1]=='-')
988 r_side_effects = true;
991 void UnusedVariableRemover::visit(BinaryExpression &binary)
993 if(binary.oper->token[0]=='[')
995 binary.left->visit(*this);
996 SetFlag set(assignment_target, false);
997 binary.right->visit(*this);
1000 TraversingVisitor::visit(binary);
1003 void UnusedVariableRemover::visit(Assignment &assign)
1006 SetFlag set(assignment_target, (assign.oper->token[0]=='='));
1007 assign.left->visit(*this);
1009 assign.right->visit(*this);
1010 r_assignment = &assign;
1011 r_side_effects = true;
1014 void UnusedVariableRemover::visit(FunctionCall &call)
1016 TraversingVisitor::visit(call);
1017 /* Treat function calls as having side effects so expression statements
1018 consisting of nothing but a function call won't be optimized away. */
1019 r_side_effects = true;
1021 if(stage->type==Stage::GEOMETRY && call.name=="EmitVertex")
1023 for(map<Statement *, VariableInfo>::const_iterator i=variables.begin(); i!=variables.end(); ++i)
1024 if(i->second.output)
1025 referenced(i->first, call);
1029 void UnusedVariableRemover::record_assignment(const Assignment::Target &target, Node &node)
1031 assignments.push_back(AssignmentInfo());
1032 AssignmentInfo &assign_info = assignments.back();
1033 assign_info.node = &node;
1034 assign_info.target = target;
1036 /* An assignment to the target hides any assignments to the same target or
1038 VariableInfo &var_info = variables[target.declaration];
1039 for(unsigned i=0; i<var_info.assignments.size(); ++i)
1041 const Assignment::Target &t = var_info.assignments[i]->target;
1043 bool subfield = (t.chain_len>=target.chain_len);
1044 for(unsigned j=0; (subfield && j<target.chain_len); ++j)
1045 subfield = (t.chain[j]==target.chain[j]);
1048 var_info.assignments.erase(var_info.assignments.begin()+i);
1053 var_info.assignments.push_back(&assign_info);
1056 void UnusedVariableRemover::visit(ExpressionStatement &expr)
1059 r_side_effects = false;
1060 TraversingVisitor::visit(expr);
1061 if(r_assignment && r_assignment->target.declaration)
1062 record_assignment(r_assignment->target, expr);
1064 unused_nodes.insert(&expr);
1067 void UnusedVariableRemover::visit(VariableDeclaration &var)
1069 VariableInfo &var_info = variables[&var];
1070 var_info.interface_block = interface_block;
1072 /* Mark variables as output if they're used by the next stage or the
1075 var_info.output = (interface_block->interface=="out" && (interface_block->linked_block || !interface_block->name.compare(0, 3, "gl_")));
1077 var_info.output = (var.interface=="out" && (stage->type==Stage::FRAGMENT || var.linked_declaration || !var.name.compare(0, 3, "gl_")));
1079 if(var.init_expression)
1081 var_info.initialized = true;
1082 record_assignment(&var, *var.init_expression);
1084 TraversingVisitor::visit(var);
1087 void UnusedVariableRemover::visit(InterfaceBlock &iface)
1089 if(iface.instance_name.empty())
1091 SetForScope<InterfaceBlock *> set_block(interface_block, &iface);
1092 iface.struct_declaration->members.visit(*this);
1096 VariableInfo &var_info = variables[&iface];
1097 var_info.output = (iface.interface=="out" && (iface.linked_block || !iface.name.compare(0, 3, "gl_")));
1101 void UnusedVariableRemover::merge_variables(const BlockVariableMap &other_vars)
1103 for(BlockVariableMap::const_iterator i=other_vars.begin(); i!=other_vars.end(); ++i)
1105 BlockVariableMap::iterator j = variables.find(i->first);
1106 if(j!=variables.end())
1108 /* The merged blocks started as copies of each other so any common
1109 assignments must be in the beginning. */
1111 for(; (k<i->second.assignments.size() && k<j->second.assignments.size()); ++k)
1112 if(i->second.assignments[k]!=j->second.assignments[k])
1115 // Remaining assignments are unique to each block; merge them.
1116 j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin()+k, i->second.assignments.end());
1117 j->second.referenced |= i->second.referenced;
1120 variables.insert(*i);
1124 void UnusedVariableRemover::visit(FunctionDeclaration &func)
1126 if(func.body.body.empty())
1129 BlockVariableMap saved_vars = variables;
1130 // Assignments from other functions should not be visible.
1131 for(BlockVariableMap::iterator i=variables.begin(); i!=variables.end(); ++i)
1132 i->second.assignments.resize(i->second.initialized);
1133 TraversingVisitor::visit(func);
1134 swap(variables, saved_vars);
1135 merge_variables(saved_vars);
1137 /* Always treat function parameters as referenced. Removing unused
1138 parameters is not currently supported. */
1139 for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
1141 BlockVariableMap::iterator j = variables.find(i->get());
1142 if(j!=variables.end())
1143 j->second.referenced = true;
1147 void UnusedVariableRemover::visit(Conditional &cond)
1149 cond.condition->visit(*this);
1150 BlockVariableMap saved_vars = variables;
1151 cond.body.visit(*this);
1152 swap(saved_vars, variables);
1153 cond.else_body.visit(*this);
1155 /* Visible assignments after the conditional is the union of those visible
1156 at the end of the if and else blocks. If there was no else block, then it's
1157 the union of the if block and the state before it. */
1158 merge_variables(saved_vars);
1161 void UnusedVariableRemover::visit(Iteration &iter)
1163 BlockVariableMap saved_vars = variables;
1164 TraversingVisitor::visit(iter);
1166 /* Merge assignments from the iteration, without clearing previous state.
1167 Further analysis is needed to determine which parts of the iteration body
1168 are always executed, if any. */
1169 merge_variables(saved_vars);
1173 bool UnusedFunctionRemover::apply(Stage &stage)
1175 stage.content.visit(*this);
1176 NodeRemover().apply(stage, unused_nodes);
1177 return !unused_nodes.empty();
1180 void UnusedFunctionRemover::visit(FunctionCall &call)
1182 TraversingVisitor::visit(call);
1184 unused_nodes.erase(call.declaration);
1185 if(call.declaration && call.declaration->definition!=call.declaration)
1186 used_definitions.insert(call.declaration->definition);
1189 void UnusedFunctionRemover::visit(FunctionDeclaration &func)
1191 TraversingVisitor::visit(func);
1193 if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func))
1194 unused_nodes.insert(&func);