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 SetForScope<unsigned> set_remap(remap_names, 1);
94 SetForScope<string> set_prefix(remap_prefix, target_func.name);
96 target_func.visit(*this);
98 tgt_blk.body.insert(ins_pt, inlined.begin(), inlined.end());
100 NodeReorderer().apply(stage, target_func, dependencies);
102 return r_result_name;
105 void InlineContentInjector::visit(VariableReference &var)
109 map<string, VariableDeclaration *>::const_iterator i = variable_map.find(var.name);
110 if(i!=variable_map.end())
111 var.name = i->second->name;
113 else if(var.declaration)
115 SetFlag set_deps(deps_only);
116 if(!variable_map.count(var.name))
118 dependencies.insert(var.declaration);
119 referenced_names.insert(var.name);
121 var.declaration->visit(*this);
125 void InlineContentInjector::visit(InterfaceBlockReference &iface)
127 if(!remap_names && iface.declaration)
129 SetFlag set_deps(deps_only);
130 dependencies.insert(iface.declaration);
131 referenced_names.insert(iface.name);
132 iface.declaration->visit(*this);
136 void InlineContentInjector::visit(FunctionCall &call)
138 if(!remap_names && call.declaration)
140 dependencies.insert(call.declaration);
141 referenced_names.insert(call.name);
143 TraversingVisitor::visit(call);
146 void InlineContentInjector::visit(VariableDeclaration &var)
148 TraversingVisitor::visit(var);
152 if(remap_names==2 || referenced_names.count(var.name))
154 string mapped_name = get_unused_variable_name(*target_block, var.name, remap_prefix);
155 variable_map[var.name] = &var;
156 var.name = mapped_name;
159 else if(var.type_declaration)
161 SetFlag set_deps(deps_only);
162 dependencies.insert(var.type_declaration);
163 referenced_names.insert(var.type_declaration->name);
164 var.type_declaration->visit(*this);
168 void InlineContentInjector::visit(Return &ret)
170 TraversingVisitor::visit(ret);
172 if(!remap_names && ret.expression)
174 /* Create a new variable to hold the return value of the inlined
176 r_result_name = get_unused_variable_name(*target_block, "_return", source_func->name);
177 RefPtr<VariableDeclaration> var = new VariableDeclaration;
178 var->source = ret.source;
179 var->line = ret.line;
180 var->type = source_func->return_type;
181 var->name = r_result_name;
182 var->init_expression = ret.expression->clone();
183 r_inlined_statement = var;
188 FunctionInliner::FunctionInliner():
190 r_any_inlined(false),
191 r_inlined_here(false)
194 bool FunctionInliner::apply(Stage &s)
197 inlineable = InlineableFunctionLocator().apply(s);
198 r_any_inlined = false;
199 s.content.visit(*this);
200 return r_any_inlined;
203 void FunctionInliner::visit(RefPtr<Expression> &ptr)
209 ptr = r_inline_result;
210 r_any_inlined = true;
215 void FunctionInliner::visit(Block &block)
217 SetForScope<Block *> set_block(current_block, &block);
218 SetForScope<NodeList<Statement>::iterator> save_insert_point(insert_point, block.body.begin());
219 for(NodeList<Statement>::iterator i=block.body.begin(); (!r_inlined_here && i!=block.body.end()); ++i)
226 void FunctionInliner::visit(FunctionCall &call)
231 for(NodeArray<Expression>::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
234 FunctionDeclaration *def = call.declaration;
236 def = def->definition;
238 if(def && inlineable.count(def))
240 string result_name = InlineContentInjector().apply(*stage, *current_function, *current_block, insert_point, *def);
242 // This will later get removed by UnusedVariableRemover.
243 if(result_name.empty())
244 result_name = "msp_unused_from_inline";
246 RefPtr<VariableReference> ref = new VariableReference;
247 ref->name = result_name;
248 r_inline_result = ref;
250 /* Inlined variables need to be resolved before this function can be
252 inlineable.erase(current_function);
253 r_inlined_here = true;
257 void FunctionInliner::visit(FunctionDeclaration &func)
259 SetForScope<FunctionDeclaration *> set_func(current_function, &func);
260 TraversingVisitor::visit(func);
261 r_inlined_here = false;
264 void FunctionInliner::visit(Iteration &iter)
266 /* Visit the initialization statement before entering the loop body so the
267 inlined statements get inserted outside. */
268 if(iter.init_statement)
269 iter.init_statement->visit(*this);
271 SetForScope<Block *> set_block(current_block, &iter.body);
272 /* Skip the condition and loop expression parts because they're not properly
273 inside the body block. Inlining anything into them will require a more
274 comprehensive transformation. */
275 iter.body.visit(*this);
279 ExpressionInliner::ExpressionInfo::ExpressionInfo():
288 ExpressionInliner::ExpressionInliner():
290 r_any_inlined(false),
293 iteration_init(false),
298 bool ExpressionInliner::apply(Stage &s)
300 s.content.visit(*this);
301 return r_any_inlined;
304 void ExpressionInliner::inline_expression(Expression &expr, RefPtr<Expression> &ptr)
307 r_any_inlined = true;
310 void ExpressionInliner::visit(Block &block)
312 TraversingVisitor::visit(block);
314 for(map<string, VariableDeclaration *>::iterator i=block.variables.begin(); i!=block.variables.end(); ++i)
316 map<Assignment::Target, ExpressionInfo>::iterator j = expressions.lower_bound(i->second);
317 for(; (j!=expressions.end() && j->first.declaration==i->second); )
319 if(j->second.expression && j->second.inline_point)
320 inline_expression(*j->second.expression, *j->second.inline_point);
322 expressions.erase(j++);
326 /* Expressions assigned in this block may depend on local variables of the
327 block. If this is a conditionally executed block, the assignments might not
328 always happen. Mark the expressions as not available to any outer blocks. */
329 for(map<Assignment::Target, ExpressionInfo>::iterator i=expressions.begin(); i!=expressions.end(); ++i)
330 if(i->second.assign_scope==&block)
331 i->second.available = false;
334 void ExpressionInliner::visit(RefPtr<Expression> &expr)
338 if(r_ref_info && r_ref_info->expression && r_ref_info->available)
340 if(iteration_body && !r_ref_info->trivial)
342 /* Don't inline non-trivial expressions which were assigned outside
343 an iteration statement. The iteration may run multiple times, which
344 would cause the expression to also be evaluated multiple times. */
345 Block *i = r_ref_info->assign_scope;
346 for(; (i && i!=iteration_body); i=i->parent) ;
351 if(r_ref_info->trivial)
352 inline_expression(*r_ref_info->expression, expr);
354 /* Record the inline point for a non-trivial expression but don't
355 inline it yet. It might turn out it shouldn't be inlined after all. */
356 r_ref_info->inline_point = &expr;
362 void ExpressionInliner::visit(VariableReference &var)
366 map<Assignment::Target, ExpressionInfo>::iterator i = expressions.find(var.declaration);
367 if(i!=expressions.end())
369 /* If a non-trivial expression is referenced multiple times, don't
371 if(i->second.inline_point && !i->second.trivial)
372 i->second.expression = 0;
373 /* Mutating expressions are analogous to self-referencing assignments
374 and prevent inlining. */
376 i->second.expression = 0;
377 r_ref_info = &i->second;
382 void ExpressionInliner::visit(MemberAccess &memacc)
388 void ExpressionInliner::visit(Swizzle &swizzle)
394 void ExpressionInliner::visit(UnaryExpression &unary)
396 SetFlag set_target(mutating, mutating || unary.oper->token[1]=='+' || unary.oper->token[1]=='-');
397 visit(unary.expression);
401 void ExpressionInliner::visit(BinaryExpression &binary)
405 SetFlag clear_target(mutating, false);
411 void ExpressionInliner::visit(Assignment &assign)
414 SetFlag set_target(mutating);
420 map<Assignment::Target, ExpressionInfo>::iterator i = expressions.find(assign.target);
421 if(i!=expressions.end())
423 /* Self-referencing assignments can't be inlined without additional
424 work. Just clear any previous expression. */
425 i->second.expression = (assign.self_referencing ? 0 : assign.right.get());
426 i->second.assign_scope = current_block;
427 i->second.inline_point = 0;
428 i->second.available = true;
434 void ExpressionInliner::visit(TernaryExpression &ternary)
436 visit(ternary.condition);
437 visit(ternary.true_expr);
438 visit(ternary.false_expr);
442 void ExpressionInliner::visit(FunctionCall &call)
444 TraversingVisitor::visit(call);
448 void ExpressionInliner::visit(VariableDeclaration &var)
452 TraversingVisitor::visit(var);
454 bool constant = var.constant;
455 if(constant && var.layout)
457 for(vector<Layout::Qualifier>::const_iterator i=var.layout->qualifiers.begin(); (constant && i!=var.layout->qualifiers.end()); ++i)
458 constant = (i->name!="constant_id");
461 /* Only inline global variables if they're constant and have trivial
462 initializers. Non-constant variables could change in ways which are hard to
463 analyze and non-trivial expressions could be expensive to inline. */
464 if((current_block->parent || (constant && r_trivial)) && var.interface.empty())
466 ExpressionInfo &info = expressions[&var];
467 /* Assume variables declared in an iteration initialization statement
468 will have their values change throughout the iteration. */
469 info.expression = (iteration_init ? 0 : var.init_expression.get());
470 info.assign_scope = current_block;
471 info.trivial = r_trivial;
475 void ExpressionInliner::visit(Iteration &iter)
477 SetForScope<Block *> set_block(current_block, &iter.body);
478 if(iter.init_statement)
480 SetFlag set_init(iteration_init);
481 iter.init_statement->visit(*this);
484 SetForScope<Block *> set_body(iteration_body, &iter.body);
486 visit(iter.condition);
487 iter.body.visit(*this);
488 if(iter.loop_expression)
489 visit(iter.loop_expression);
493 BasicTypeDeclaration::Kind ConstantFolder::get_value_kind(const Variant &value)
495 if(value.check_type<bool>())
496 return BasicTypeDeclaration::BOOL;
497 else if(value.check_type<int>())
498 return BasicTypeDeclaration::INT;
499 else if(value.check_type<float>())
500 return BasicTypeDeclaration::FLOAT;
502 return BasicTypeDeclaration::VOID;
506 T ConstantFolder::evaluate_logical(char oper, T left, T right)
510 case '&': return left&right;
511 case '|': return left|right;
512 case '^': return left^right;
518 bool ConstantFolder::evaluate_relation(const char *oper, T left, T right)
520 switch(oper[0]|oper[1])
522 case '<': return left<right;
523 case '<'|'=': return left<=right;
524 case '>': return left>right;
525 case '>'|'=': return left>=right;
526 default: return false;
531 T ConstantFolder::evaluate_arithmetic(char oper, T left, T right)
535 case '+': return left+right;
536 case '-': return left-right;
537 case '*': return left*right;
538 case '/': return left/right;
543 void ConstantFolder::set_result(const Variant &value, bool literal)
545 r_constant_value = value;
550 void ConstantFolder::visit(RefPtr<Expression> &expr)
552 r_constant_value = Variant();
555 r_uses_iter_var = false;
557 /* Don't replace literals since they'd only be replaced with an identical
558 literal. Also skip anything that uses an iteration variable, but pass on
559 the result so the Iteration visiting function can handle it. */
560 if(!r_constant || r_literal || r_uses_iter_var)
563 BasicTypeDeclaration::Kind kind = get_value_kind(r_constant_value);
564 if(kind==BasicTypeDeclaration::VOID)
570 RefPtr<Literal> literal = new Literal;
571 if(kind==BasicTypeDeclaration::BOOL)
572 literal->token = (r_constant_value.value<bool>() ? "true" : "false");
573 else if(kind==BasicTypeDeclaration::INT)
574 literal->token = lexical_cast<string>(r_constant_value.value<int>());
575 else if(kind==BasicTypeDeclaration::FLOAT)
576 literal->token = lexical_cast<string>(r_constant_value.value<float>());
577 literal->value = r_constant_value;
581 void ConstantFolder::visit(Literal &literal)
583 set_result(literal.value, true);
586 void ConstantFolder::visit(VariableReference &var)
588 /* If an iteration variable is initialized with a constant value, return
589 that value here for the purpose of evaluating the loop condition for the
591 if(var.declaration==iteration_var)
593 set_result(iter_init_value);
594 r_uses_iter_var = true;
598 void ConstantFolder::visit(MemberAccess &memacc)
600 TraversingVisitor::visit(memacc);
604 void ConstantFolder::visit(Swizzle &swizzle)
606 TraversingVisitor::visit(swizzle);
610 void ConstantFolder::visit(UnaryExpression &unary)
612 TraversingVisitor::visit(unary);
613 bool can_fold = r_constant;
618 BasicTypeDeclaration::Kind kind = get_value_kind(r_constant_value);
620 char oper = unary.oper->token[0];
621 char oper2 = unary.oper->token[1];
624 if(kind==BasicTypeDeclaration::BOOL)
625 set_result(!r_constant_value.value<bool>());
629 if(kind==BasicTypeDeclaration::INT)
630 set_result(~r_constant_value.value<int>());
632 else if(oper=='-' && !oper2)
634 if(kind==BasicTypeDeclaration::INT)
635 set_result(-r_constant_value.value<int>());
636 else if(kind==BasicTypeDeclaration::FLOAT)
637 set_result(-r_constant_value.value<float>());
641 void ConstantFolder::visit(BinaryExpression &binary)
644 bool left_constant = r_constant;
645 bool left_iter_var = r_uses_iter_var;
646 Variant left_value = r_constant_value;
649 r_uses_iter_var = true;
651 bool can_fold = (left_constant && r_constant);
656 BasicTypeDeclaration::Kind left_kind = get_value_kind(left_value);
657 BasicTypeDeclaration::Kind right_kind = get_value_kind(r_constant_value);
658 // Currently only expressions with both sides of equal types are handled.
659 if(left_kind!=right_kind)
662 char oper = binary.oper->token[0];
663 char oper2 = binary.oper->token[1];
664 if(oper=='&' || oper=='|' || oper=='^')
666 if(oper2==oper && left_kind==BasicTypeDeclaration::BOOL)
667 set_result(evaluate_logical(oper, left_value.value<bool>(), r_constant_value.value<bool>()));
668 else if(!oper2 && left_kind==BasicTypeDeclaration::INT)
669 set_result(evaluate_logical(oper, left_value.value<int>(), r_constant_value.value<int>()));
671 else if((oper=='<' || oper=='>') && oper2!=oper)
673 if(left_kind==BasicTypeDeclaration::INT)
674 set_result(evaluate_relation(binary.oper->token, left_value.value<int>(), r_constant_value.value<int>()));
675 else if(left_kind==BasicTypeDeclaration::FLOAT)
676 set_result(evaluate_relation(binary.oper->token, left_value.value<float>(), r_constant_value.value<float>()));
678 else if((oper=='=' || oper=='!') && oper2=='=')
680 if(left_kind==BasicTypeDeclaration::INT)
681 set_result((left_value.value<int>()==r_constant_value.value<int>()) == (oper=='='));
682 if(left_kind==BasicTypeDeclaration::FLOAT)
683 set_result((left_value.value<float>()==r_constant_value.value<float>()) == (oper=='='));
685 else if(oper=='+' || oper=='-' || oper=='*' || oper=='/')
687 if(left_kind==BasicTypeDeclaration::INT)
688 set_result(evaluate_arithmetic(oper, left_value.value<int>(), r_constant_value.value<int>()));
689 else if(left_kind==BasicTypeDeclaration::FLOAT)
690 set_result(evaluate_arithmetic(oper, left_value.value<float>(), r_constant_value.value<float>()));
692 else if(oper=='%' || ((oper=='<' || oper=='>') && oper2==oper))
694 if(left_kind!=BasicTypeDeclaration::INT)
698 set_result(left_value.value<int>()%r_constant_value.value<int>());
700 set_result(left_value.value<int>()<<r_constant_value.value<int>());
702 set_result(left_value.value<int>()>>r_constant_value.value<int>());
706 void ConstantFolder::visit(Assignment &assign)
708 TraversingVisitor::visit(assign);
712 void ConstantFolder::visit(TernaryExpression &ternary)
714 TraversingVisitor::visit(ternary);
718 void ConstantFolder::visit(FunctionCall &call)
720 TraversingVisitor::visit(call);
724 void ConstantFolder::visit(VariableDeclaration &var)
726 if(iteration_init && var.init_expression)
728 visit(var.init_expression);
731 /* Record the value of a constant initialization expression of an
732 iteration, so it can be used to evaluate the loop condition. */
733 iteration_var = &var;
734 iter_init_value = r_constant_value;
738 TraversingVisitor::visit(var);
741 void ConstantFolder::visit(Iteration &iter)
743 SetForScope<Block *> set_block(current_block, &iter.body);
745 /* The iteration variable is not normally inlined into expressions, so we
746 process it specially here. If the initial value causes the loop condition
747 to evaluate to false, then the expression can be folded. */
749 if(iter.init_statement)
751 SetFlag set_init(iteration_init);
752 iter.init_statement->visit(*this);
757 visit(iter.condition);
758 if(r_constant && r_constant_value.check_type<bool>() && !r_constant_value.value<bool>())
760 RefPtr<Literal> literal = new Literal;
761 literal->token = "false";
762 literal->value = r_constant_value;
763 iter.condition = literal;
768 iter.body.visit(*this);
769 if(iter.loop_expression)
770 visit(iter.loop_expression);
774 void ConstantConditionEliminator::apply(Stage &stage)
776 stage.content.visit(*this);
777 NodeRemover().apply(stage, nodes_to_remove);
780 ConstantConditionEliminator::ConstantStatus ConstantConditionEliminator::check_constant_condition(const Expression &expr)
782 if(const Literal *literal = dynamic_cast<const Literal *>(&expr))
783 if(literal->value.check_type<bool>())
784 return (literal->value.value<bool>() ? CONSTANT_TRUE : CONSTANT_FALSE);
788 void ConstantConditionEliminator::visit(Block &block)
790 SetForScope<Block *> set_block(current_block, &block);
791 for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
798 void ConstantConditionEliminator::visit(RefPtr<Expression> &expr)
800 r_ternary_result = 0;
803 expr = r_ternary_result;
804 r_ternary_result = 0;
807 void ConstantConditionEliminator::visit(TernaryExpression &ternary)
809 ConstantStatus result = check_constant_condition(*ternary.condition);
810 if(result!=NOT_CONSTANT)
811 r_ternary_result = (result==CONSTANT_TRUE ? ternary.true_expr : ternary.false_expr);
813 r_ternary_result = 0;
816 void ConstantConditionEliminator::visit(Conditional &cond)
818 ConstantStatus result = check_constant_condition(*cond.condition);
819 if(result!=NOT_CONSTANT)
821 Block &block = (result==CONSTANT_TRUE ? cond.body : cond.else_body);
822 // TODO should check variable names for conflicts. Potentially reuse InlineContentInjector?
823 current_block->body.splice(insert_point, block.body);
824 nodes_to_remove.insert(&cond);
828 TraversingVisitor::visit(cond);
831 void ConstantConditionEliminator::visit(Iteration &iter)
835 ConstantStatus result = check_constant_condition(*iter.condition);
836 if(result==CONSTANT_FALSE)
838 nodes_to_remove.insert(&iter);
843 TraversingVisitor::visit(iter);
847 bool UnusedTypeRemover::apply(Stage &stage)
849 stage.content.visit(*this);
850 NodeRemover().apply(stage, unused_nodes);
851 return !unused_nodes.empty();
854 void UnusedTypeRemover::visit(Literal &literal)
856 unused_nodes.erase(literal.type);
859 void UnusedTypeRemover::visit(UnaryExpression &unary)
861 unused_nodes.erase(unary.type);
862 TraversingVisitor::visit(unary);
865 void UnusedTypeRemover::visit(BinaryExpression &binary)
867 unused_nodes.erase(binary.type);
868 TraversingVisitor::visit(binary);
871 void UnusedTypeRemover::visit(TernaryExpression &ternary)
873 unused_nodes.erase(ternary.type);
874 TraversingVisitor::visit(ternary);
877 void UnusedTypeRemover::visit(FunctionCall &call)
879 unused_nodes.erase(call.type);
880 TraversingVisitor::visit(call);
883 void UnusedTypeRemover::visit(BasicTypeDeclaration &type)
886 unused_nodes.erase(type.base_type);
887 unused_nodes.insert(&type);
890 void UnusedTypeRemover::visit(ImageTypeDeclaration &type)
893 unused_nodes.erase(type.base_type);
894 unused_nodes.insert(&type);
897 void UnusedTypeRemover::visit(StructDeclaration &strct)
899 unused_nodes.insert(&strct);
900 TraversingVisitor::visit(strct);
903 void UnusedTypeRemover::visit(VariableDeclaration &var)
905 unused_nodes.erase(var.type_declaration);
908 void UnusedTypeRemover::visit(InterfaceBlock &iface)
910 unused_nodes.erase(iface.type_declaration);
913 void UnusedTypeRemover::visit(FunctionDeclaration &func)
915 unused_nodes.erase(func.return_type_declaration);
916 TraversingVisitor::visit(func);
920 UnusedVariableRemover::UnusedVariableRemover():
924 assignment_target(false),
925 r_side_effects(false)
928 bool UnusedVariableRemover::apply(Stage &s)
931 s.content.visit(*this);
933 for(list<AssignmentInfo>::const_iterator i=assignments.begin(); i!=assignments.end(); ++i)
934 if(i->used_by.empty())
935 unused_nodes.insert(i->node);
937 for(map<string, InterfaceBlock *>::const_iterator i=s.interface_blocks.begin(); i!=s.interface_blocks.end(); ++i)
938 if(i->second->instance_name.empty())
939 unused_nodes.insert(i->second);
941 for(BlockVariableMap::const_iterator i=variables.begin(); i!=variables.end(); ++i)
945 /* The last visible assignments of output variables are used by the
946 next stage or the API. */
947 for(vector<AssignmentInfo *>::const_iterator j=i->second.assignments.begin(); j!=i->second.assignments.end(); ++j)
948 unused_nodes.erase((*j)->node);
951 if(!i->second.output && !i->second.referenced)
953 // Don't remove variables from inside interface blocks.
954 if(!i->second.interface_block)
955 unused_nodes.insert(i->first);
957 else if(i->second.interface_block)
958 // Interface blocks are kept if even one member is used.
959 unused_nodes.erase(i->second.interface_block);
962 NodeRemover().apply(s, unused_nodes);
964 return !unused_nodes.empty();
967 void UnusedVariableRemover::referenced(const Assignment::Target &target, Node &node)
969 VariableInfo &var_info = variables[target.declaration];
970 var_info.referenced = true;
971 if(!assignment_target)
973 for(vector<AssignmentInfo *>::const_iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i)
974 (*i)->used_by.push_back(&node);
978 void UnusedVariableRemover::visit(VariableReference &var)
980 referenced(var.declaration, var);
983 void UnusedVariableRemover::visit(InterfaceBlockReference &iface)
985 referenced(iface.declaration, iface);
988 void UnusedVariableRemover::visit(UnaryExpression &unary)
990 TraversingVisitor::visit(unary);
991 if(unary.oper->token[1]=='+' || unary.oper->token[1]=='-')
992 r_side_effects = true;
995 void UnusedVariableRemover::visit(BinaryExpression &binary)
997 if(binary.oper->token[0]=='[')
999 binary.left->visit(*this);
1000 SetFlag set(assignment_target, false);
1001 binary.right->visit(*this);
1004 TraversingVisitor::visit(binary);
1007 void UnusedVariableRemover::visit(Assignment &assign)
1010 SetFlag set(assignment_target, (assign.oper->token[0]=='='));
1011 assign.left->visit(*this);
1013 assign.right->visit(*this);
1014 r_assignment = &assign;
1015 r_side_effects = true;
1018 void UnusedVariableRemover::visit(FunctionCall &call)
1020 TraversingVisitor::visit(call);
1021 /* Treat function calls as having side effects so expression statements
1022 consisting of nothing but a function call won't be optimized away. */
1023 r_side_effects = true;
1025 if(stage->type==Stage::GEOMETRY && call.name=="EmitVertex")
1027 for(map<Statement *, VariableInfo>::const_iterator i=variables.begin(); i!=variables.end(); ++i)
1028 if(i->second.output)
1029 referenced(i->first, call);
1033 void UnusedVariableRemover::record_assignment(const Assignment::Target &target, Node &node)
1035 assignments.push_back(AssignmentInfo());
1036 AssignmentInfo &assign_info = assignments.back();
1037 assign_info.node = &node;
1038 assign_info.target = target;
1040 /* An assignment to the target hides any assignments to the same target or
1042 VariableInfo &var_info = variables[target.declaration];
1043 for(unsigned i=0; i<var_info.assignments.size(); ++i)
1045 const Assignment::Target &t = var_info.assignments[i]->target;
1047 bool subfield = (t.chain_len>=target.chain_len);
1048 for(unsigned j=0; (subfield && j<target.chain_len); ++j)
1049 subfield = (t.chain[j]==target.chain[j]);
1052 var_info.assignments.erase(var_info.assignments.begin()+i);
1057 var_info.assignments.push_back(&assign_info);
1060 void UnusedVariableRemover::visit(ExpressionStatement &expr)
1063 r_side_effects = false;
1064 TraversingVisitor::visit(expr);
1065 if(r_assignment && r_assignment->target.declaration)
1066 record_assignment(r_assignment->target, expr);
1068 unused_nodes.insert(&expr);
1071 void UnusedVariableRemover::visit(VariableDeclaration &var)
1073 VariableInfo &var_info = variables[&var];
1074 var_info.interface_block = interface_block;
1076 /* Mark variables as output if they're used by the next stage or the
1079 var_info.output = (interface_block->interface=="out" && (interface_block->linked_block || !interface_block->name.compare(0, 3, "gl_")));
1081 var_info.output = (var.interface=="out" && (stage->type==Stage::FRAGMENT || var.linked_declaration || !var.name.compare(0, 3, "gl_")));
1083 if(var.init_expression)
1085 var_info.initialized = true;
1086 record_assignment(&var, *var.init_expression);
1088 TraversingVisitor::visit(var);
1091 void UnusedVariableRemover::visit(InterfaceBlock &iface)
1093 if(iface.instance_name.empty())
1095 SetForScope<InterfaceBlock *> set_block(interface_block, &iface);
1096 iface.struct_declaration->members.visit(*this);
1100 VariableInfo &var_info = variables[&iface];
1101 var_info.output = (iface.interface=="out" && (iface.linked_block || !iface.name.compare(0, 3, "gl_")));
1105 void UnusedVariableRemover::merge_variables(const BlockVariableMap &other_vars)
1107 for(BlockVariableMap::const_iterator i=other_vars.begin(); i!=other_vars.end(); ++i)
1109 BlockVariableMap::iterator j = variables.find(i->first);
1110 if(j!=variables.end())
1112 /* The merged blocks started as copies of each other so any common
1113 assignments must be in the beginning. */
1115 for(; (k<i->second.assignments.size() && k<j->second.assignments.size()); ++k)
1116 if(i->second.assignments[k]!=j->second.assignments[k])
1119 // Remaining assignments are unique to each block; merge them.
1120 j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin()+k, i->second.assignments.end());
1121 j->second.referenced |= i->second.referenced;
1124 variables.insert(*i);
1128 void UnusedVariableRemover::visit(FunctionDeclaration &func)
1130 if(func.body.body.empty())
1133 BlockVariableMap saved_vars = variables;
1134 // Assignments from other functions should not be visible.
1135 for(BlockVariableMap::iterator i=variables.begin(); i!=variables.end(); ++i)
1136 i->second.assignments.resize(i->second.initialized);
1137 TraversingVisitor::visit(func);
1138 swap(variables, saved_vars);
1139 merge_variables(saved_vars);
1141 /* Always treat function parameters as referenced. Removing unused
1142 parameters is not currently supported. */
1143 for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
1145 BlockVariableMap::iterator j = variables.find(i->get());
1146 if(j!=variables.end())
1147 j->second.referenced = true;
1151 void UnusedVariableRemover::visit(Conditional &cond)
1153 cond.condition->visit(*this);
1154 BlockVariableMap saved_vars = variables;
1155 cond.body.visit(*this);
1156 swap(saved_vars, variables);
1157 cond.else_body.visit(*this);
1159 /* Visible assignments after the conditional is the union of those visible
1160 at the end of the if and else blocks. If there was no else block, then it's
1161 the union of the if block and the state before it. */
1162 merge_variables(saved_vars);
1165 void UnusedVariableRemover::visit(Iteration &iter)
1167 BlockVariableMap saved_vars = variables;
1168 TraversingVisitor::visit(iter);
1170 /* Merge assignments from the iteration, without clearing previous state.
1171 Further analysis is needed to determine which parts of the iteration body
1172 are always executed, if any. */
1173 merge_variables(saved_vars);
1177 bool UnusedFunctionRemover::apply(Stage &stage)
1179 stage.content.visit(*this);
1180 NodeRemover().apply(stage, unused_nodes);
1181 return !unused_nodes.empty();
1184 void UnusedFunctionRemover::visit(FunctionCall &call)
1186 TraversingVisitor::visit(call);
1188 unused_nodes.erase(call.declaration);
1189 if(call.declaration && call.declaration->definition!=call.declaration)
1190 used_definitions.insert(call.declaration->definition);
1193 void UnusedFunctionRemover::visit(FunctionDeclaration &func)
1195 TraversingVisitor::visit(func);
1197 if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func))
1198 unused_nodes.insert(&func);