]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/optimize.cpp
Add support for uint types in GLSL
[libs/gl.git] / source / glsl / optimize.cpp
1 #include <msp/core/raii.h>
2 #include <msp/strings/format.h>
3 #include <msp/strings/utils.h>
4 #include "optimize.h"
5 #include "reflect.h"
6
7 using namespace std;
8
9 namespace Msp {
10 namespace GL {
11 namespace SL {
12
13 ConstantSpecializer::ConstantSpecializer():
14         values(0)
15 { }
16
17 void ConstantSpecializer::apply(Stage &stage, const map<string, int> &v)
18 {
19         values = &v;
20         stage.content.visit(*this);
21 }
22
23 void ConstantSpecializer::visit(VariableDeclaration &var)
24 {
25         bool specializable = false;
26         if(var.layout)
27         {
28                 vector<Layout::Qualifier> &qualifiers = var.layout->qualifiers;
29                 for(vector<Layout::Qualifier>::iterator i=qualifiers.begin(); (!specializable && i!=qualifiers.end()); ++i)
30                         if(i->name=="constant_id")
31                         {
32                                 specializable = true;
33                                 qualifiers.erase(i);
34                         }
35
36                 if(qualifiers.empty())
37                         var.layout = 0;
38         }
39
40         if(specializable)
41         {
42                 map<string, int>::const_iterator i = values->find(var.name);
43                 if(i!=values->end())
44                 {
45                         RefPtr<Literal> literal = new Literal;
46                         if(var.type=="bool")
47                         {
48                                 literal->token = (i->second ? "true" : "false");
49                                 literal->value = static_cast<bool>(i->second);
50                         }
51                         else if(var.type=="int")
52                         {
53                                 literal->token = lexical_cast<string>(i->second);
54                                 literal->value = i->second;
55                         }
56                         var.init_expression = literal;
57                 }
58         }
59 }
60
61
62 InlineableFunctionLocator::InlineableFunctionLocator():
63         current_function(0),
64         return_count(0)
65 { }
66
67 void InlineableFunctionLocator::visit(FunctionCall &call)
68 {
69         FunctionDeclaration *def = call.declaration;
70         if(def)
71                 def = def->definition;
72
73         if(def)
74         {
75                 unsigned &count = refcounts[def];
76                 ++count;
77                 /* Don't inline functions which are called more than once or are called
78                 recursively. */
79                 if((count>1 && def->source!=BUILTIN_SOURCE) || def==current_function)
80                         inlineable.erase(def);
81         }
82
83         TraversingVisitor::visit(call);
84 }
85
86 void InlineableFunctionLocator::visit(FunctionDeclaration &func)
87 {
88         bool has_out_params = false;
89         for(NodeArray<VariableDeclaration>::const_iterator i=func.parameters.begin(); (!has_out_params && i!=func.parameters.end()); ++i)
90                 has_out_params = ((*i)->interface=="out");
91
92         unsigned &count = refcounts[func.definition];
93         if((count<=1 || func.source==BUILTIN_SOURCE) && !has_out_params)
94                 inlineable.insert(func.definition);
95
96         SetForScope<FunctionDeclaration *> set(current_function, &func);
97         return_count = 0;
98         TraversingVisitor::visit(func);
99 }
100
101 void InlineableFunctionLocator::visit(Conditional &cond)
102 {
103         TraversingVisitor::visit(cond);
104         inlineable.erase(current_function);
105 }
106
107 void InlineableFunctionLocator::visit(Iteration &iter)
108 {
109         TraversingVisitor::visit(iter);
110         inlineable.erase(current_function);
111 }
112
113 void InlineableFunctionLocator::visit(Return &ret)
114 {
115         TraversingVisitor::visit(ret);
116         if(return_count)
117                 inlineable.erase(current_function);
118         ++return_count;
119 }
120
121
122 InlineContentInjector::InlineContentInjector():
123         source_func(0),
124         pass(REFERENCED)
125 { }
126
127 string InlineContentInjector::apply(Stage &stage, FunctionDeclaration &target_func, Block &tgt_blk, const NodeList<Statement>::iterator &ins_pt, FunctionCall &call)
128 {
129         source_func = call.declaration->definition;
130
131         /* Populate referenced_names from the target function so we can rename
132         variables from the inlined function that would conflict. */
133         pass = REFERENCED;
134         target_func.visit(*this);
135
136         /* Inline and rename passes must be interleaved so used variable names are
137         known when inlining the return statement. */
138         pass = INLINE;
139         staging_block.parent = &tgt_blk;
140         staging_block.variables.clear();
141
142         vector<RefPtr<VariableDeclaration> > params;
143         params.reserve(source_func->parameters.size());
144         for(NodeArray<VariableDeclaration>::iterator i=source_func->parameters.begin(); i!=source_func->parameters.end(); ++i)
145         {
146                 RefPtr<VariableDeclaration> var = (*i)->clone();
147                 var->interface.clear();
148
149                 SetForScope<Pass> set_pass(pass, RENAME);
150                 var->visit(*this);
151
152                 staging_block.body.push_back_nocopy(var);
153                 params.push_back(var);
154         }
155
156         for(NodeList<Statement>::iterator i=source_func->body.body.begin(); i!=source_func->body.body.end(); ++i)
157         {
158                 r_inlined_statement = 0;
159                 (*i)->visit(*this);
160                 if(!r_inlined_statement)
161                         r_inlined_statement = (*i)->clone();
162
163                 SetForScope<Pass> set_pass(pass, RENAME);
164                 r_inlined_statement->visit(*this);
165
166                 staging_block.body.push_back_nocopy(r_inlined_statement);
167         }
168
169         /* Now collect names from the staging block.  Local variables that would
170         have conflicted with the target function were renamed earlier. */
171         pass = REFERENCED;
172         referenced_names.clear();
173         staging_block.variables.clear();
174         staging_block.visit(*this);
175
176         /* Rename variables in the target function so they don't interfere with
177         global identifiers used by the source function. */
178         pass = RENAME;
179         staging_block.parent = source_func->body.parent;
180         target_func.visit(*this);
181
182         // Put the argument expressions in place after all renaming has been done.
183         for(unsigned i=0; i<source_func->parameters.size(); ++i)
184                 params[i]->init_expression = call.arguments[i]->clone();
185
186         tgt_blk.body.splice(ins_pt, staging_block.body);
187
188         NodeReorderer().apply(stage, target_func, DependencyCollector().apply(*source_func));
189
190         return r_result_name;
191 }
192
193 void InlineContentInjector::visit(VariableReference &var)
194 {
195         if(pass==RENAME)
196         {
197                 map<string, VariableDeclaration *>::const_iterator i = staging_block.variables.find(var.name);
198                 if(i!=staging_block.variables.end())
199                         var.name = i->second->name;
200         }
201         else if(pass==REFERENCED)
202                 referenced_names.insert(var.name);
203 }
204
205 void InlineContentInjector::visit(InterfaceBlockReference &iface)
206 {
207         if(pass==REFERENCED)
208                 referenced_names.insert(iface.name);
209 }
210
211 void InlineContentInjector::visit(FunctionCall &call)
212 {
213         if(pass==REFERENCED)
214                 referenced_names.insert(call.name);
215         TraversingVisitor::visit(call);
216 }
217
218 void InlineContentInjector::visit(VariableDeclaration &var)
219 {
220         TraversingVisitor::visit(var);
221
222         if(pass==RENAME)
223         {
224                 /* Check against conflicts with the other context as well as variables
225                 already renamed here. */
226                 bool conflict = (staging_block.variables.count(var.name) || referenced_names.count(var.name));
227                 staging_block.variables[var.name] = &var;
228                 if(conflict)
229                 {
230                         string mapped_name = get_unused_variable_name(staging_block, var.name);
231                         if(mapped_name!=var.name)
232                         {
233                                 staging_block.variables[mapped_name] = &var;
234                                 var.name = mapped_name;
235                         }
236                 }
237         }
238         else if(pass==REFERENCED)
239                 referenced_names.insert(var.type);
240 }
241
242 void InlineContentInjector::visit(Return &ret)
243 {
244         TraversingVisitor::visit(ret);
245
246         if(pass==INLINE && ret.expression)
247         {
248                 // Create a new variable to hold the return value of the inlined function.
249                 r_result_name = get_unused_variable_name(staging_block, "_return");
250                 RefPtr<VariableDeclaration> var = new VariableDeclaration;
251                 var->source = ret.source;
252                 var->line = ret.line;
253                 var->type = source_func->return_type;
254                 var->name = r_result_name;
255                 var->init_expression = ret.expression->clone();
256                 r_inlined_statement = var;
257         }
258 }
259
260
261 FunctionInliner::FunctionInliner():
262         current_function(0),
263         r_any_inlined(false),
264         r_inlined_here(false)
265 { }
266
267 bool FunctionInliner::apply(Stage &s)
268 {
269         stage = &s;
270         inlineable = InlineableFunctionLocator().apply(s);
271         r_any_inlined = false;
272         s.content.visit(*this);
273         return r_any_inlined;
274 }
275
276 void FunctionInliner::visit(RefPtr<Expression> &ptr)
277 {
278         r_inline_result = 0;
279         ptr->visit(*this);
280         if(r_inline_result)
281         {
282                 ptr = r_inline_result;
283                 r_any_inlined = true;
284         }
285         r_inline_result = 0;
286 }
287
288 void FunctionInliner::visit(Block &block)
289 {
290         SetForScope<Block *> set_block(current_block, &block);
291         SetForScope<NodeList<Statement>::iterator> save_insert_point(insert_point, block.body.begin());
292         for(NodeList<Statement>::iterator i=block.body.begin(); (!r_inlined_here && i!=block.body.end()); ++i)
293         {
294                 insert_point = i;
295                 (*i)->visit(*this);
296         }
297 }
298
299 void FunctionInliner::visit(FunctionCall &call)
300 {
301         for(NodeArray<Expression>::iterator i=call.arguments.begin(); (!r_inlined_here && i!=call.arguments.end()); ++i)
302                 visit(*i);
303
304         if(r_inlined_here)
305                 return;
306
307         FunctionDeclaration *def = call.declaration;
308         if(def)
309                 def = def->definition;
310
311         if(def && inlineable.count(def))
312         {
313                 string result_name = InlineContentInjector().apply(*stage, *current_function, *current_block, insert_point, call);
314
315                 // This will later get removed by UnusedVariableRemover.
316                 if(result_name.empty())
317                         result_name = "_msp_unused_from_inline";
318
319                 RefPtr<VariableReference> ref = new VariableReference;
320                 ref->name = result_name;
321                 r_inline_result = ref;
322
323                 /* Inlined variables need to be resolved before this function can be
324                 inlined further. */
325                 inlineable.erase(current_function);
326                 r_inlined_here = true;
327         }
328 }
329
330 void FunctionInliner::visit(FunctionDeclaration &func)
331 {
332         SetForScope<FunctionDeclaration *> set_func(current_function, &func);
333         TraversingVisitor::visit(func);
334         r_inlined_here = false;
335 }
336
337 void FunctionInliner::visit(Iteration &iter)
338 {
339         /* Visit the initialization statement before entering the loop body so the
340         inlined statements get inserted outside. */
341         if(iter.init_statement)
342                 iter.init_statement->visit(*this);
343
344         SetForScope<Block *> set_block(current_block, &iter.body);
345         /* Skip the condition and loop expression parts because they're not properly
346         inside the body block.  Inlining anything into them will require a more
347         comprehensive transformation. */
348         iter.body.visit(*this);
349 }
350
351
352 ExpressionInliner::ExpressionInliner():
353         r_ref_info(0),
354         r_any_inlined(false),
355         r_trivial(false),
356         mutating(false),
357         iteration_init(false),
358         iteration_body(0),
359         r_oper(0)
360 { }
361
362 bool ExpressionInliner::apply(Stage &s)
363 {
364         s.content.visit(*this);
365         return r_any_inlined;
366 }
367
368 void ExpressionInliner::inline_expression(Expression &expr, RefPtr<Expression> &ptr)
369 {
370         ptr = expr.clone();
371         r_any_inlined = true;
372 }
373
374 void ExpressionInliner::visit(Block &block)
375 {
376         TraversingVisitor::visit(block);
377
378         for(map<string, VariableDeclaration *>::iterator i=block.variables.begin(); i!=block.variables.end(); ++i)
379         {
380                 map<Assignment::Target, ExpressionInfo>::iterator j = expressions.lower_bound(i->second);
381                 for(; (j!=expressions.end() && j->first.declaration==i->second); )
382                 {
383                         if(j->second.expression && j->second.inline_point)
384                                 inline_expression(*j->second.expression, *j->second.inline_point);
385
386                         expressions.erase(j++);
387                 }
388         }
389
390         /* Expressions assigned in this block may depend on local variables of the
391         block.  If this is a conditionally executed block, the assignments might not
392         always happen.  Mark the expressions as not available to any outer blocks. */
393         for(map<Assignment::Target, ExpressionInfo>::iterator i=expressions.begin(); i!=expressions.end(); ++i)
394                 if(i->second.assign_scope==&block)
395                         i->second.available = false;
396 }
397
398 void ExpressionInliner::visit(RefPtr<Expression> &expr)
399 {
400         r_ref_info = 0;
401         expr->visit(*this);
402         if(r_ref_info && r_ref_info->expression && r_ref_info->available)
403         {
404                 if(iteration_body && !r_ref_info->trivial)
405                 {
406                         /* Don't inline non-trivial expressions which were assigned outside
407                         an iteration statement.  The iteration may run multiple times, which
408                         would cause the expression to also be evaluated multiple times. */
409                         Block *i = r_ref_info->assign_scope;
410                         for(; (i && i!=iteration_body); i=i->parent) ;
411                         if(!i)
412                                 return;
413                 }
414
415                 if(r_ref_info->trivial)
416                         inline_expression(*r_ref_info->expression, expr);
417                 else
418                         /* Record the inline point for a non-trivial expression but don't
419                         inline it yet.  It might turn out it shouldn't be inlined after all. */
420                         r_ref_info->inline_point = &expr;
421         }
422         r_oper = expr->oper;
423         r_ref_info = 0;
424 }
425
426 void ExpressionInliner::visit(VariableReference &var)
427 {
428         if(var.declaration)
429         {
430                 map<Assignment::Target, ExpressionInfo>::iterator i = expressions.find(var.declaration);
431                 if(i!=expressions.end())
432                 {
433                         /* If a non-trivial expression is referenced multiple times, don't
434                         inline it. */
435                         if(i->second.inline_point && !i->second.trivial)
436                                 i->second.expression = 0;
437                         /* Mutating expressions are analogous to self-referencing assignments
438                         and prevent inlining. */
439                         if(mutating)
440                                 i->second.expression = 0;
441                         r_ref_info = &i->second;
442                 }
443         }
444 }
445
446 void ExpressionInliner::visit(MemberAccess &memacc)
447 {
448         visit(memacc.left);
449         r_trivial = false;
450 }
451
452 void ExpressionInliner::visit(Swizzle &swizzle)
453 {
454         visit(swizzle.left);
455         r_trivial = false;
456 }
457
458 void ExpressionInliner::visit(UnaryExpression &unary)
459 {
460         SetFlag set_target(mutating, mutating || unary.oper->token[1]=='+' || unary.oper->token[1]=='-');
461         visit(unary.expression);
462         r_trivial = false;
463 }
464
465 void ExpressionInliner::visit(BinaryExpression &binary)
466 {
467         visit(binary.left);
468         {
469                 SetFlag clear_target(mutating, false);
470                 visit(binary.right);
471         }
472         r_trivial = false;
473 }
474
475 void ExpressionInliner::visit(Assignment &assign)
476 {
477         {
478                 SetFlag set_target(mutating);
479                 visit(assign.left);
480         }
481         r_oper = 0;
482         visit(assign.right);
483
484         map<Assignment::Target, ExpressionInfo>::iterator i = expressions.find(assign.target);
485         if(i!=expressions.end())
486         {
487                 /* Self-referencing assignments can't be inlined without additional
488                 work.  Just clear any previous expression. */
489                 i->second.expression = (assign.self_referencing ? 0 : assign.right.get());
490                 i->second.assign_scope = current_block;
491                 i->second.inline_point = 0;
492                 i->second.available = true;
493         }
494
495         r_trivial = false;
496 }
497
498 void ExpressionInliner::visit(TernaryExpression &ternary)
499 {
500         visit(ternary.condition);
501         visit(ternary.true_expr);
502         visit(ternary.false_expr);
503         r_trivial = false;
504 }
505
506 void ExpressionInliner::visit(FunctionCall &call)
507 {
508         TraversingVisitor::visit(call);
509         r_trivial = false;
510 }
511
512 void ExpressionInliner::visit(VariableDeclaration &var)
513 {
514         r_oper = 0;
515         r_trivial = true;
516         TraversingVisitor::visit(var);
517
518         bool constant = var.constant;
519         if(constant && var.layout)
520         {
521                 for(vector<Layout::Qualifier>::const_iterator i=var.layout->qualifiers.begin(); (constant && i!=var.layout->qualifiers.end()); ++i)
522                         constant = (i->name!="constant_id");
523         }
524
525         /* Only inline global variables if they're constant and have trivial
526         initializers.  Non-constant variables could change in ways which are hard to
527         analyze and non-trivial expressions could be expensive to inline.  */
528         if((current_block->parent || (constant && r_trivial)) && var.interface.empty())
529         {
530                 ExpressionInfo &info = expressions[&var];
531                 /* Assume variables declared in an iteration initialization statement
532                 will have their values change throughout the iteration. */
533                 info.expression = (iteration_init ? 0 : var.init_expression.get());
534                 info.assign_scope = current_block;
535                 info.trivial = r_trivial;
536         }
537 }
538
539 void ExpressionInliner::visit(Iteration &iter)
540 {
541         SetForScope<Block *> set_block(current_block, &iter.body);
542         if(iter.init_statement)
543         {
544                 SetFlag set_init(iteration_init);
545                 iter.init_statement->visit(*this);
546         }
547
548         SetForScope<Block *> set_body(iteration_body, &iter.body);
549         if(iter.condition)
550                 visit(iter.condition);
551         iter.body.visit(*this);
552         if(iter.loop_expression)
553                 visit(iter.loop_expression);
554 }
555
556
557 template<typename T>
558 T ConstantFolder::evaluate_logical(char oper, T left, T right)
559 {
560         switch(oper)
561         {
562         case '&': return left&right;
563         case '|': return left|right;
564         case '^': return left^right;
565         default: return T();
566         }
567 }
568
569 template<typename T>
570 bool ConstantFolder::evaluate_relation(const char *oper, T left, T right)
571 {
572         switch(oper[0]|oper[1])
573         {
574         case '<': return left<right;
575         case '<'|'=': return left<=right;
576         case '>': return left>right;
577         case '>'|'=': return left>=right;
578         default: return false;
579         }
580 }
581
582 template<typename T>
583 T ConstantFolder::evaluate_arithmetic(char oper, T left, T right)
584 {
585         switch(oper)
586         {
587         case '+': return left+right;
588         case '-': return left-right;
589         case '*': return left*right;
590         case '/': return left/right;
591         default: return T();
592         }
593 }
594
595 template<typename T>
596 T ConstantFolder::evaluate_int_special_op(char oper, T left, T right)
597 {
598         switch(oper)
599         {
600         case '%': return left%right;
601         case '<': return left<<right;
602         case '>': return left>>right;
603         default: return T();
604         }
605 }
606
607 template<typename T>
608 void ConstantFolder::convert_to_result(const Variant &value)
609 {
610         if(value.check_type<bool>())
611                 set_result(static_cast<T>(value.value<bool>()));
612         else if(value.check_type<int>())
613                 set_result(static_cast<T>(value.value<int>()));
614         else if(value.check_type<unsigned>())
615                 set_result(static_cast<T>(value.value<unsigned>()));
616         else if(value.check_type<float>())
617                 set_result(static_cast<T>(value.value<float>()));
618 }
619
620 void ConstantFolder::set_result(const Variant &value, bool literal)
621 {
622         r_constant_value = value;
623         r_constant = true;
624         r_literal = literal;
625 }
626
627 void ConstantFolder::visit(RefPtr<Expression> &expr)
628 {
629         r_constant_value = Variant();
630         r_constant = false;
631         r_literal = false;
632         r_uses_iter_var = false;
633         expr->visit(*this);
634         /* Don't replace literals since they'd only be replaced with an identical
635         literal.  Also skip anything that uses an iteration variable, but pass on
636         the result so the Iteration visiting function can handle it. */
637         if(!r_constant || r_literal || r_uses_iter_var)
638                 return;
639
640         RefPtr<Literal> literal = new Literal;
641         if(r_constant_value.check_type<bool>())
642                 literal->token = (r_constant_value.value<bool>() ? "true" : "false");
643         else if(r_constant_value.check_type<int>())
644                 literal->token = lexical_cast<string>(r_constant_value.value<int>());
645         else if(r_constant_value.check_type<unsigned>())
646                 literal->token = lexical_cast<string>(r_constant_value.value<unsigned>())+"u";
647         else if(r_constant_value.check_type<float>())
648         {
649                 literal->token = lexical_cast<string>(r_constant_value.value<float>());
650                 if(isnumrc(literal->token))
651                         literal->token += ".0";
652         }
653         else
654         {
655                 r_constant = false;
656                 return;
657         }
658         literal->value = r_constant_value;
659         expr = literal;
660 }
661
662 void ConstantFolder::visit(Literal &literal)
663 {
664         set_result(literal.value, true);
665 }
666
667 void ConstantFolder::visit(VariableReference &var)
668 {
669         /* If an iteration variable is initialized with a constant value, return
670         that value here for the purpose of evaluating the loop condition for the
671         first iteration. */
672         if(var.declaration==iteration_var)
673         {
674                 set_result(iter_init_value);
675                 r_uses_iter_var = true;
676         }
677 }
678
679 void ConstantFolder::visit(MemberAccess &memacc)
680 {
681         TraversingVisitor::visit(memacc);
682         r_constant = false;
683 }
684
685 void ConstantFolder::visit(Swizzle &swizzle)
686 {
687         TraversingVisitor::visit(swizzle);
688         r_constant = false;
689 }
690
691 void ConstantFolder::visit(UnaryExpression &unary)
692 {
693         TraversingVisitor::visit(unary);
694         bool can_fold = r_constant;
695         r_constant = false;
696         if(!can_fold)
697                 return;
698
699         char oper = unary.oper->token[0];
700         char oper2 = unary.oper->token[1];
701         if(oper=='!')
702         {
703                 if(r_constant_value.check_type<bool>())
704                         set_result(!r_constant_value.value<bool>());
705         }
706         else if(oper=='~')
707         {
708                 if(r_constant_value.check_type<int>())
709                         set_result(~r_constant_value.value<int>());
710                 else if(r_constant_value.check_type<unsigned>())
711                         set_result(~r_constant_value.value<unsigned>());
712         }
713         else if(oper=='-' && !oper2)
714         {
715                 if(r_constant_value.check_type<int>())
716                         set_result(-r_constant_value.value<int>());
717                 else if(r_constant_value.check_type<unsigned>())
718                         set_result(-r_constant_value.value<unsigned>());
719                 else if(r_constant_value.check_type<float>())
720                         set_result(-r_constant_value.value<float>());
721         }
722 }
723
724 void ConstantFolder::visit(BinaryExpression &binary)
725 {
726         visit(binary.left);
727         bool left_constant = r_constant;
728         bool left_iter_var = r_uses_iter_var;
729         Variant left_value = r_constant_value;
730         visit(binary.right);
731         if(left_iter_var)
732                 r_uses_iter_var = true;
733
734         bool can_fold = (left_constant && r_constant);
735         r_constant = false;
736         if(!can_fold)
737                 return;
738
739         // Currently only expressions with both sides of equal types are handled.
740         if(!left_value.check_same_type(r_constant_value))
741                 return;
742
743         char oper = binary.oper->token[0];
744         char oper2 = binary.oper->token[1];
745         if(oper=='&' || oper=='|' || oper=='^')
746         {
747                 if(oper2==oper && left_value.check_type<bool>())
748                         set_result(evaluate_logical(oper, left_value.value<bool>(), r_constant_value.value<bool>()));
749                 else if(!oper2 && left_value.check_type<int>())
750                         set_result(evaluate_logical(oper, left_value.value<int>(), r_constant_value.value<int>()));
751                 else if(!oper2 && left_value.check_type<unsigned>())
752                         set_result(evaluate_logical(oper, left_value.value<unsigned>(), r_constant_value.value<unsigned>()));
753         }
754         else if((oper=='<' || oper=='>') && oper2!=oper)
755         {
756                 if(left_value.check_type<int>())
757                         set_result(evaluate_relation(binary.oper->token, left_value.value<int>(), r_constant_value.value<int>()));
758                 else if(left_value.check_type<unsigned>())
759                         set_result(evaluate_relation(binary.oper->token, left_value.value<unsigned>(), r_constant_value.value<unsigned>()));
760                 else if(left_value.check_type<float>())
761                         set_result(evaluate_relation(binary.oper->token, left_value.value<float>(), r_constant_value.value<float>()));
762         }
763         else if((oper=='=' || oper=='!') && oper2=='=')
764         {
765                 if(left_value.check_type<int>())
766                         set_result((left_value.value<int>()==r_constant_value.value<int>()) == (oper=='='));
767                 else if(left_value.check_type<unsigned>())
768                         set_result((left_value.value<unsigned>()==r_constant_value.value<unsigned>()) == (oper=='='));
769                 else if(left_value.check_type<float>())
770                         set_result((left_value.value<float>()==r_constant_value.value<float>()) == (oper=='='));
771         }
772         else if(oper=='+' || oper=='-' || oper=='*' || oper=='/')
773         {
774                 if(left_value.check_type<int>())
775                         set_result(evaluate_arithmetic(oper, left_value.value<int>(), r_constant_value.value<int>()));
776                 else if(left_value.check_type<unsigned>())
777                         set_result(evaluate_arithmetic(oper, left_value.value<unsigned>(), r_constant_value.value<unsigned>()));
778                 else if(left_value.check_type<float>())
779                         set_result(evaluate_arithmetic(oper, left_value.value<float>(), r_constant_value.value<float>()));
780         }
781         else if(oper=='%' || ((oper=='<' || oper=='>') && oper2==oper))
782         {
783                 if(left_value.check_type<int>())
784                         set_result(evaluate_int_special_op(oper, left_value.value<int>(), r_constant_value.value<int>()));
785                 else if(left_value.check_type<unsigned>())
786                         set_result(evaluate_int_special_op(oper, left_value.value<unsigned>(), r_constant_value.value<unsigned>()));
787         }
788 }
789
790 void ConstantFolder::visit(Assignment &assign)
791 {
792         TraversingVisitor::visit(assign);
793         r_constant = false;
794 }
795
796 void ConstantFolder::visit(TernaryExpression &ternary)
797 {
798         TraversingVisitor::visit(ternary);
799         r_constant = false;
800 }
801
802 void ConstantFolder::visit(FunctionCall &call)
803 {
804         if(call.constructor && call.type && call.arguments.size()==1)
805         {
806                 const BasicTypeDeclaration *basic = dynamic_cast<const BasicTypeDeclaration *>(call.type);
807                 if(basic)
808                 {
809                         call.arguments[0]->visit(*this);
810                         bool can_fold = r_constant;
811                         r_constant = false;
812                         if(!can_fold)
813                                 return;
814
815                         if(basic->kind==BasicTypeDeclaration::BOOL)
816                                 convert_to_result<bool>(r_constant_value);
817                         else if(basic->kind==BasicTypeDeclaration::INT && basic->size==32 && basic->sign)
818                                 convert_to_result<int>(r_constant_value);
819                         else if(basic->kind==BasicTypeDeclaration::INT && basic->size==32 && !basic->sign)
820                                 convert_to_result<unsigned>(r_constant_value);
821                         else if(basic->kind==BasicTypeDeclaration::FLOAT && basic->size==32)
822                                 convert_to_result<float>(r_constant_value);
823
824                         return;
825                 }
826         }
827
828         TraversingVisitor::visit(call);
829         r_constant = false;
830 }
831
832 void ConstantFolder::visit(VariableDeclaration &var)
833 {
834         if(iteration_init && var.init_expression)
835         {
836                 visit(var.init_expression);
837                 if(r_constant)
838                 {
839                         /* Record the value of a constant initialization expression of an
840                         iteration, so it can be used to evaluate the loop condition. */
841                         iteration_var = &var;
842                         iter_init_value = r_constant_value;
843                 }
844         }
845         else
846                 TraversingVisitor::visit(var);
847 }
848
849 void ConstantFolder::visit(Iteration &iter)
850 {
851         SetForScope<Block *> set_block(current_block, &iter.body);
852
853         /* The iteration variable is not normally inlined into expressions, so we
854         process it specially here.  If the initial value causes the loop condition
855         to evaluate to false, then the expression can be folded. */
856         iteration_var = 0;
857         if(iter.init_statement)
858         {
859                 SetFlag set_init(iteration_init);
860                 iter.init_statement->visit(*this);
861         }
862
863         if(iter.condition)
864         {
865                 visit(iter.condition);
866                 if(r_constant && r_constant_value.check_type<bool>() && !r_constant_value.value<bool>())
867                 {
868                         RefPtr<Literal> literal = new Literal;
869                         literal->token = "false";
870                         literal->value = r_constant_value;
871                         iter.condition = literal;
872                 }
873         }
874         iteration_var = 0;
875
876         iter.body.visit(*this);
877         if(iter.loop_expression)
878                 visit(iter.loop_expression);
879 }
880
881
882 void ConstantConditionEliminator::apply(Stage &stage)
883 {
884         stage.content.visit(*this);
885         NodeRemover().apply(stage, nodes_to_remove);
886 }
887
888 ConstantConditionEliminator::ConstantStatus ConstantConditionEliminator::check_constant_condition(const Expression &expr)
889 {
890         if(const Literal *literal = dynamic_cast<const Literal *>(&expr))
891                 if(literal->value.check_type<bool>())
892                         return (literal->value.value<bool>() ? CONSTANT_TRUE : CONSTANT_FALSE);
893         return NOT_CONSTANT;
894 }
895
896 void ConstantConditionEliminator::visit(Block &block)
897 {
898         SetForScope<Block *> set_block(current_block, &block);
899         for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
900         {
901                 insert_point = i;
902                 (*i)->visit(*this);
903         }
904 }
905
906 void ConstantConditionEliminator::visit(RefPtr<Expression> &expr)
907 {
908         r_ternary_result = 0;
909         expr->visit(*this);
910         if(r_ternary_result)
911                 expr = r_ternary_result;
912         r_ternary_result = 0;
913 }
914
915 void ConstantConditionEliminator::visit(TernaryExpression &ternary)
916 {
917         ConstantStatus result = check_constant_condition(*ternary.condition);
918         if(result!=NOT_CONSTANT)
919                 r_ternary_result = (result==CONSTANT_TRUE ? ternary.true_expr : ternary.false_expr);
920         else
921                 r_ternary_result = 0;
922 }
923
924 void ConstantConditionEliminator::visit(Conditional &cond)
925 {
926         ConstantStatus result = check_constant_condition(*cond.condition);
927         if(result!=NOT_CONSTANT)
928         {
929                 Block &block = (result==CONSTANT_TRUE ? cond.body : cond.else_body);
930                 // TODO should check variable names for conflicts.  Potentially reuse InlineContentInjector?
931                 current_block->body.splice(insert_point, block.body);
932                 nodes_to_remove.insert(&cond);
933                 return;
934         }
935
936         TraversingVisitor::visit(cond);
937 }
938
939 void ConstantConditionEliminator::visit(Iteration &iter)
940 {
941         if(iter.condition)
942         {
943                 ConstantStatus result = check_constant_condition(*iter.condition);
944                 if(result==CONSTANT_FALSE)
945                 {
946                         nodes_to_remove.insert(&iter);
947                         return;
948                 }
949         }
950
951         TraversingVisitor::visit(iter);
952 }
953
954
955 UnreachableCodeRemover::UnreachableCodeRemover():
956         reachable(true)
957 { }
958
959 bool UnreachableCodeRemover::apply(Stage &stage)
960 {
961         stage.content.visit(*this);
962         NodeRemover().apply(stage, unreachable_nodes);
963         return !unreachable_nodes.empty();
964 }
965
966 void UnreachableCodeRemover::visit(Block &block)
967 {
968         NodeList<Statement>::iterator i = block.body.begin();
969         for(; (reachable && i!=block.body.end()); ++i)
970                 (*i)->visit(*this);
971         for(; i!=block.body.end(); ++i)
972                 unreachable_nodes.insert(i->get());
973 }
974
975 void UnreachableCodeRemover::visit(FunctionDeclaration &func)
976 {
977         TraversingVisitor::visit(func);
978         reachable = true;
979 }
980
981 void UnreachableCodeRemover::visit(Conditional &cond)
982 {
983         cond.body.visit(*this);
984         bool reachable_if_true = reachable;
985         reachable = true;
986         cond.else_body.visit(*this);
987
988         reachable |= reachable_if_true;
989 }
990
991 void UnreachableCodeRemover::visit(Iteration &iter)
992 {
993         TraversingVisitor::visit(iter);
994
995         /* Always consider code after a loop reachable, since there's no checking
996         for whether the loop executes. */
997         reachable = true;
998 }
999
1000
1001 bool UnusedTypeRemover::apply(Stage &stage)
1002 {
1003         stage.content.visit(*this);
1004         NodeRemover().apply(stage, unused_nodes);
1005         return !unused_nodes.empty();
1006 }
1007
1008 void UnusedTypeRemover::visit(RefPtr<Expression> &expr)
1009 {
1010         unused_nodes.erase(expr->type);
1011         TraversingVisitor::visit(expr);
1012 }
1013
1014 void UnusedTypeRemover::visit(BasicTypeDeclaration &type)
1015 {
1016         if(type.base_type)
1017                 unused_nodes.erase(type.base_type);
1018         unused_nodes.insert(&type);
1019 }
1020
1021 void UnusedTypeRemover::visit(ImageTypeDeclaration &type)
1022 {
1023         if(type.base_type)
1024                 unused_nodes.erase(type.base_type);
1025         unused_nodes.insert(&type);
1026 }
1027
1028 void UnusedTypeRemover::visit(StructDeclaration &strct)
1029 {
1030         unused_nodes.insert(&strct);
1031         TraversingVisitor::visit(strct);
1032 }
1033
1034 void UnusedTypeRemover::visit(VariableDeclaration &var)
1035 {
1036         unused_nodes.erase(var.type_declaration);
1037         TraversingVisitor::visit(var);
1038 }
1039
1040 void UnusedTypeRemover::visit(InterfaceBlock &iface)
1041 {
1042         unused_nodes.erase(iface.type_declaration);
1043 }
1044
1045 void UnusedTypeRemover::visit(FunctionDeclaration &func)
1046 {
1047         unused_nodes.erase(func.return_type_declaration);
1048         TraversingVisitor::visit(func);
1049 }
1050
1051
1052 UnusedVariableRemover::UnusedVariableRemover():
1053         stage(0),
1054         interface_block(0),
1055         r_assignment(0),
1056         assignment_target(false),
1057         r_side_effects(false),
1058         in_struct(false),
1059         composite_reference(false)
1060 { }
1061
1062 bool UnusedVariableRemover::apply(Stage &s)
1063 {
1064         stage = &s;
1065         s.content.visit(*this);
1066
1067         for(list<AssignmentInfo>::const_iterator i=assignments.begin(); i!=assignments.end(); ++i)
1068                 if(i->used_by.empty())
1069                         unused_nodes.insert(i->node);
1070
1071         for(BlockVariableMap::const_iterator i=variables.begin(); i!=variables.end(); ++i)
1072         {
1073                 if(i->second.output)
1074                 {
1075                         /* The last visible assignments of output variables are used by the
1076                         next stage or the API. */
1077                         for(vector<AssignmentInfo *>::const_iterator j=i->second.assignments.begin(); j!=i->second.assignments.end(); ++j)
1078                                 unused_nodes.erase((*j)->node);
1079                 }
1080
1081                 if(!i->second.output && !i->second.referenced)
1082                 {
1083                         // Don't remove variables from inside interface blocks.
1084                         if(!i->second.interface_block)
1085                                 unused_nodes.insert(i->first);
1086                 }
1087                 else if(i->second.interface_block)
1088                         // Interface blocks are kept if even one member is used.
1089                         unused_nodes.erase(i->second.interface_block);
1090         }
1091
1092         NodeRemover().apply(s, unused_nodes);
1093
1094         return !unused_nodes.empty();
1095 }
1096
1097 void UnusedVariableRemover::referenced(const Assignment::Target &target, Node &node)
1098 {
1099         VariableInfo &var_info = variables[target.declaration];
1100         var_info.referenced = true;
1101         if(!assignment_target)
1102         {
1103                 for(vector<AssignmentInfo *>::const_iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i)
1104                 {
1105                         bool covered = true;
1106                         for(unsigned j=0; (covered && j<(*i)->target.chain_len && j<target.chain_len); ++j)
1107                         {
1108                                 Assignment::Target::ChainType type1 = static_cast<Assignment::Target::ChainType>((*i)->target.chain[j]&0xC0);
1109                                 Assignment::Target::ChainType type2 = static_cast<Assignment::Target::ChainType>(target.chain[j]&0xC0);
1110                                 if(type1==Assignment::Target::SWIZZLE || type2==Assignment::Target::SWIZZLE)
1111                                 {
1112                                         unsigned index1 = (*i)->target.chain[j]&0x3F;
1113                                         unsigned index2 = target.chain[j]&0x3F;
1114                                         if(type1==Assignment::Target::SWIZZLE && type2==Assignment::Target::SWIZZLE)
1115                                                 covered = index1&index2;
1116                                         else if(type1==Assignment::Target::ARRAY && index1<4)
1117                                                 covered = index2&(1<<index1);
1118                                         else if(type2==Assignment::Target::ARRAY && index2<4)
1119                                                 covered = index1&(1<<index2);
1120                                         /* If it's some other combination (shouldn't happen), leave
1121                                         covered as true */
1122                                 }
1123                                 else
1124                                         covered = ((*i)->target.chain[j]==target.chain[j]);
1125                         }
1126                         if(covered)
1127                                 (*i)->used_by.push_back(&node);
1128                 }
1129         }
1130 }
1131
1132 void UnusedVariableRemover::visit(VariableReference &var)
1133 {
1134         if(composite_reference)
1135                 r_reference.declaration = var.declaration;
1136         else
1137                 referenced(var.declaration, var);
1138 }
1139
1140 void UnusedVariableRemover::visit(InterfaceBlockReference &iface)
1141 {
1142         if(composite_reference)
1143                 r_reference.declaration = iface.declaration;
1144         else
1145                 referenced(iface.declaration, iface);
1146 }
1147
1148 void UnusedVariableRemover::visit_composite(Expression &expr)
1149 {
1150         if(!composite_reference)
1151                 r_reference = Assignment::Target();
1152
1153         SetFlag set_composite(composite_reference);
1154         expr.visit(*this);
1155 }
1156
1157 void UnusedVariableRemover::visit(MemberAccess &memacc)
1158 {
1159         visit_composite(*memacc.left);
1160
1161         add_to_chain(r_reference, Assignment::Target::MEMBER, memacc.index);
1162
1163         if(!composite_reference && r_reference.declaration)
1164                 referenced(r_reference, memacc);
1165 }
1166
1167 void UnusedVariableRemover::visit(Swizzle &swizzle)
1168 {
1169         visit_composite(*swizzle.left);
1170
1171         unsigned mask = 0;
1172         for(unsigned i=0; i<swizzle.count; ++i)
1173                 mask |= 1<<swizzle.components[i];
1174         add_to_chain(r_reference, Assignment::Target::SWIZZLE, mask);
1175
1176         if(!composite_reference && r_reference.declaration)
1177                 referenced(r_reference, swizzle);
1178 }
1179
1180 void UnusedVariableRemover::visit(UnaryExpression &unary)
1181 {
1182         TraversingVisitor::visit(unary);
1183         if(unary.oper->token[1]=='+' || unary.oper->token[1]=='-')
1184                 r_side_effects = true;
1185 }
1186
1187 void UnusedVariableRemover::visit(BinaryExpression &binary)
1188 {
1189         if(binary.oper->token[0]=='[')
1190         {
1191                 visit_composite(*binary.left);
1192
1193                 {
1194                         SetFlag clear_assignment(assignment_target, false);
1195                         SetFlag clear_composite(composite_reference, false);
1196                         binary.right->visit(*this);
1197                 }
1198
1199                 add_to_chain(r_reference, Assignment::Target::ARRAY, 0x3F);
1200
1201                 if(!composite_reference && r_reference.declaration)
1202                         referenced(r_reference, binary);
1203         }
1204         else
1205         {
1206                 SetFlag clear_composite(composite_reference, false);
1207                 TraversingVisitor::visit(binary);
1208         }
1209 }
1210
1211 void UnusedVariableRemover::visit(TernaryExpression &ternary)
1212 {
1213         SetFlag clear_composite(composite_reference, false);
1214         TraversingVisitor::visit(ternary);
1215 }
1216
1217 void UnusedVariableRemover::visit(Assignment &assign)
1218 {
1219         {
1220                 SetFlag set(assignment_target, (assign.oper->token[0]=='='));
1221                 assign.left->visit(*this);
1222         }
1223         assign.right->visit(*this);
1224         r_assignment = &assign;
1225         r_side_effects = true;
1226 }
1227
1228 void UnusedVariableRemover::visit(FunctionCall &call)
1229 {
1230         SetFlag clear_composite(composite_reference, false);
1231         TraversingVisitor::visit(call);
1232         /* Treat function calls as having side effects so expression statements
1233         consisting of nothing but a function call won't be optimized away. */
1234         r_side_effects = true;
1235
1236         if(stage->type==Stage::GEOMETRY && call.name=="EmitVertex")
1237         {
1238                 for(map<Statement *, VariableInfo>::const_iterator i=variables.begin(); i!=variables.end(); ++i)
1239                         if(i->second.output)
1240                                 referenced(i->first, call);
1241         }
1242 }
1243
1244 void UnusedVariableRemover::record_assignment(const Assignment::Target &target, Node &node)
1245 {
1246         assignments.push_back(AssignmentInfo());
1247         AssignmentInfo &assign_info = assignments.back();
1248         assign_info.node = &node;
1249         assign_info.target = target;
1250
1251         /* An assignment to the target hides any assignments to the same target or
1252         its subfields. */
1253         VariableInfo &var_info = variables[target.declaration];
1254         for(unsigned i=0; i<var_info.assignments.size(); ++i)
1255         {
1256                 const Assignment::Target &t = var_info.assignments[i]->target;
1257
1258                 bool subfield = (t.chain_len>=target.chain_len);
1259                 for(unsigned j=0; (subfield && j<target.chain_len); ++j)
1260                         subfield = (t.chain[j]==target.chain[j]);
1261
1262                 if(subfield)
1263                         var_info.assignments.erase(var_info.assignments.begin()+i);
1264                 else
1265                         ++i;
1266         }
1267
1268         var_info.assignments.push_back(&assign_info);
1269 }
1270
1271 void UnusedVariableRemover::visit(ExpressionStatement &expr)
1272 {
1273         r_assignment = 0;
1274         r_side_effects = false;
1275         TraversingVisitor::visit(expr);
1276         if(r_assignment && r_assignment->target.declaration)
1277                 record_assignment(r_assignment->target, expr);
1278         if(!r_side_effects)
1279                 unused_nodes.insert(&expr);
1280 }
1281
1282 void UnusedVariableRemover::visit(StructDeclaration &strct)
1283 {
1284         SetFlag set_struct(in_struct);
1285         TraversingVisitor::visit(strct);
1286 }
1287
1288 void UnusedVariableRemover::visit(VariableDeclaration &var)
1289 {
1290         TraversingVisitor::visit(var);
1291
1292         if(in_struct)
1293                 return;
1294
1295         VariableInfo &var_info = variables[&var];
1296         var_info.interface_block = interface_block;
1297
1298         /* Mark variables as output if they're used by the next stage or the
1299         graphics API. */
1300         if(interface_block)
1301                 var_info.output = (interface_block->interface=="out" && (interface_block->linked_block || !interface_block->block_name.compare(0, 3, "gl_")));
1302         else
1303                 var_info.output = (var.interface=="out" && (stage->type==Stage::FRAGMENT || var.linked_declaration || !var.name.compare(0, 3, "gl_")));
1304
1305         if(var.init_expression)
1306         {
1307                 var_info.initialized = true;
1308                 record_assignment(&var, *var.init_expression);
1309         }
1310 }
1311
1312 void UnusedVariableRemover::visit(InterfaceBlock &iface)
1313 {
1314         VariableInfo &var_info = variables[&iface];
1315         var_info.output = (iface.interface=="out" && (iface.linked_block || !iface.block_name.compare(0, 3, "gl_")));
1316 }
1317
1318 void UnusedVariableRemover::merge_variables(const BlockVariableMap &other_vars)
1319 {
1320         for(BlockVariableMap::const_iterator i=other_vars.begin(); i!=other_vars.end(); ++i)
1321         {
1322                 BlockVariableMap::iterator j = variables.find(i->first);
1323                 if(j!=variables.end())
1324                 {
1325                         /* The merged blocks started as copies of each other so any common
1326                         assignments must be in the beginning. */
1327                         unsigned k = 0;
1328                         for(; (k<i->second.assignments.size() && k<j->second.assignments.size()); ++k)
1329                                 if(i->second.assignments[k]!=j->second.assignments[k])
1330                                         break;
1331
1332                         // Remaining assignments are unique to each block; merge them.
1333                         j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin()+k, i->second.assignments.end());
1334                         j->second.referenced |= i->second.referenced;
1335                 }
1336                 else
1337                         variables.insert(*i);
1338         }
1339 }
1340
1341 void UnusedVariableRemover::visit(FunctionDeclaration &func)
1342 {
1343         if(func.body.body.empty())
1344                 return;
1345
1346         BlockVariableMap saved_vars = variables;
1347         // Assignments from other functions should not be visible.
1348         for(BlockVariableMap::iterator i=variables.begin(); i!=variables.end(); ++i)
1349                 i->second.assignments.resize(i->second.initialized);
1350         TraversingVisitor::visit(func);
1351         swap(variables, saved_vars);
1352         merge_variables(saved_vars);
1353
1354         /* Always treat function parameters as referenced.  Removing unused
1355         parameters is not currently supported. */
1356         for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
1357         {
1358                 BlockVariableMap::iterator j = variables.find(i->get());
1359                 if(j!=variables.end())
1360                         j->second.referenced = true;
1361         }
1362 }
1363
1364 void UnusedVariableRemover::visit(Conditional &cond)
1365 {
1366         cond.condition->visit(*this);
1367         BlockVariableMap saved_vars = variables;
1368         cond.body.visit(*this);
1369         swap(saved_vars, variables);
1370         cond.else_body.visit(*this);
1371
1372         /* Visible assignments after the conditional is the union of those visible
1373         at the end of the if and else blocks.  If there was no else block, then it's
1374         the union of the if block and the state before it. */
1375         merge_variables(saved_vars);
1376 }
1377
1378 void UnusedVariableRemover::visit(Iteration &iter)
1379 {
1380         BlockVariableMap saved_vars = variables;
1381         TraversingVisitor::visit(iter);
1382
1383         /* Merge assignments from the iteration, without clearing previous state.
1384         Further analysis is needed to determine which parts of the iteration body
1385         are always executed, if any. */
1386         merge_variables(saved_vars);
1387 }
1388
1389
1390 bool UnusedFunctionRemover::apply(Stage &stage)
1391 {
1392         stage.content.visit(*this);
1393         NodeRemover().apply(stage, unused_nodes);
1394         return !unused_nodes.empty();
1395 }
1396
1397 void UnusedFunctionRemover::visit(FunctionCall &call)
1398 {
1399         TraversingVisitor::visit(call);
1400
1401         unused_nodes.erase(call.declaration);
1402         if(call.declaration && call.declaration->definition!=call.declaration)
1403                 used_definitions.insert(call.declaration->definition);
1404 }
1405
1406 void UnusedFunctionRemover::visit(FunctionDeclaration &func)
1407 {
1408         TraversingVisitor::visit(func);
1409
1410         if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func))
1411                 unused_nodes.insert(&func);
1412 }
1413
1414 } // namespace SL
1415 } // namespace GL
1416 } // namespace Msp