]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/optimize.cpp
Move the StageType enum inside the Stage struct
[libs/gl.git] / source / glsl / optimize.cpp
1 #include <msp/core/raii.h>
2 #include "optimize.h"
3
4 using namespace std;
5
6 namespace Msp {
7 namespace GL {
8 namespace SL {
9
10 InlineableFunctionLocator::InlineableFunctionLocator():
11         in_function(0)
12 { }
13
14 void InlineableFunctionLocator::visit(FunctionCall &call)
15 {
16         FunctionDeclaration *def = call.declaration;
17         if(def && def->definition!=def)
18                 def = def->definition;
19
20         if(def)
21         {
22                 unsigned &count = refcounts[def];
23                 ++count;
24                 if(count>1 || def==in_function)
25                         inlineable.erase(def);
26         }
27
28         TraversingVisitor::visit(call);
29 }
30
31 void InlineableFunctionLocator::visit(FunctionDeclaration &func)
32 {
33         unsigned &count = refcounts[func.definition];
34         if(!count && func.parameters.empty())
35                 inlineable.insert(func.definition);
36
37         SetForScope<FunctionDeclaration *> set(in_function, &func);
38         TraversingVisitor::visit(func);
39 }
40
41
42 FunctionInliner::FunctionInliner():
43         extract_result(0)
44 { }
45
46 FunctionInliner::FunctionInliner(const set<FunctionDeclaration *> &in):
47         inlineable(in),
48         extract_result(0)
49 { }
50
51 void FunctionInliner::visit_and_inline(RefPtr<Expression> &ptr)
52 {
53         inline_result = 0;
54         ptr->visit(*this);
55         if(inline_result)
56                 ptr = inline_result;
57 }
58
59 void FunctionInliner::visit(Block &block)
60 {
61         if(extract_result)
62                 --extract_result;
63
64         for(NodeList<Statement>::iterator i=block.body.begin(); i!=block.body.end(); ++i)
65         {
66                 (*i)->visit(*this);
67                 if(extract_result)
68                         --extract_result;
69         }
70 }
71
72 void FunctionInliner::visit(UnaryExpression &unary)
73 {
74         visit_and_inline(unary.expression);
75         inline_result = 0;
76 }
77
78 void FunctionInliner::visit(BinaryExpression &binary)
79 {
80         visit_and_inline(binary.left);
81         visit_and_inline(binary.right);
82         inline_result = 0;
83 }
84
85 void FunctionInliner::visit(MemberAccess &memacc)
86 {
87         visit_and_inline(memacc.left);
88         inline_result = 0;
89 }
90
91 void FunctionInliner::visit(FunctionCall &call)
92 {
93         for(NodeArray<Expression>::iterator i=call.arguments.begin(); i!=call.arguments.end(); ++i)
94                 visit_and_inline(*i);
95
96         FunctionDeclaration *def = call.declaration;
97         if(def && def->definition!=def)
98                 def = def->definition;
99
100         if(def && inlineable.count(def))
101         {
102                 extract_result = 2;
103                 def->visit(*this);
104         }
105         else
106                 inline_result = 0;
107 }
108
109 void FunctionInliner::visit(VariableDeclaration &var)
110 {
111         if(var.init_expression)
112                 visit_and_inline(var.init_expression);
113         inline_result = 0;
114 }
115
116 void FunctionInliner::visit(Return &ret)
117 {
118         TraversingVisitor::visit(ret);
119
120         if(extract_result)
121                 inline_result = ret.expression->clone();
122 }
123
124
125 ConstantConditionEliminator::ConstantConditionEliminator():
126         scope_level(0),
127         record_only(false)
128 { }
129
130 void ConstantConditionEliminator::visit(Block &block)
131 {
132         SetForScope<unsigned> set(scope_level, scope_level+1);
133         BlockModifier::visit(block);
134
135         for(map<string, VariableDeclaration *>::const_iterator i=block.variables.begin(); i!=block.variables.end(); ++i)
136                 variable_values.erase(i->second);
137 }
138
139 void ConstantConditionEliminator::visit(UnaryExpression &unary)
140 {
141         if(VariableReference *var = dynamic_cast<VariableReference *>(unary.expression.get()))
142                 if(unary.oper=="++" || unary.oper=="--")
143                         variable_values.erase(var->declaration);
144 }
145
146 void ConstantConditionEliminator::visit(Assignment &assign)
147 {
148         variable_values.erase(assign.target_declaration);
149 }
150
151 void ConstantConditionEliminator::visit(VariableDeclaration &var)
152 {
153         if(var.constant || scope_level>1)
154                 variable_values[&var] = var.init_expression.get();
155 }
156
157 void ConstantConditionEliminator::visit(Conditional &cond)
158 {
159         if(!record_only)
160         {
161                 ExpressionEvaluator eval(variable_values);
162                 cond.condition->visit(eval);
163                 if(eval.is_result_valid())
164                 {
165                         flatten_block(eval.get_result() ? cond.body : cond.else_body);
166                         return;
167                 }
168         }
169
170         TraversingVisitor::visit(cond);
171 }
172
173 void ConstantConditionEliminator::visit(Iteration &iter)
174 {
175         if(!record_only)
176         {
177                 if(iter.condition)
178                 {
179                         /* If the loop condition is always false on the first iteration, the
180                         entire loop can be removed */
181                         if(iter.init_statement)
182                                 iter.init_statement->visit(*this);
183                         ExpressionEvaluator eval(variable_values);
184                         iter.condition->visit(eval);
185                         if(eval.is_result_valid() && !eval.get_result())
186                         {
187                                 remove_node = true;
188                                 return;
189                         }
190                 }
191
192                 /* Record all assignments that occur inside the loop body so those
193                 variables won't be considered as constant */
194                 SetFlag set_record(record_only);
195                 TraversingVisitor::visit(iter);
196         }
197
198         TraversingVisitor::visit(iter);
199
200         if(VariableDeclaration *init_decl = dynamic_cast<VariableDeclaration *>(iter.init_statement.get()))
201                 variable_values.erase(init_decl);
202 }
203
204
205 UnusedVariableLocator::VariableInfo::VariableInfo():
206         local(false),
207         conditionally_assigned(false),
208         referenced(false)
209 { }
210
211
212 UnusedVariableLocator::UnusedVariableLocator():
213         aggregate(0),
214         assignment(0),
215         assignment_target(false),
216         assign_to_subscript(false),
217         global_scope(true)
218 { }
219
220 void UnusedVariableLocator::apply(Stage &s)
221 {
222         variables.push_back(BlockVariableMap());
223         StageVisitor::apply(s);
224         BlockVariableMap &global_variables = variables.back();
225         for(BlockVariableMap::iterator i=global_variables.begin(); i!=global_variables.end(); ++i)
226         {
227                 if(i->first->interface=="out" && (s.type==Stage::FRAGMENT || i->first->linked_declaration || !i->first->name.compare(0, 3, "gl_")))
228                         continue;
229                 if(!i->second.referenced)
230                 {
231                         unused_nodes.insert(i->first);
232                         clear_assignments(i->second, true);
233                 }
234         }
235         variables.pop_back();
236 }
237
238 void UnusedVariableLocator::visit(VariableReference &var)
239 {
240         map<VariableDeclaration *, Node *>::iterator i = aggregates.find(var.declaration);
241         if(i!=aggregates.end())
242                 unused_nodes.erase(i->second);
243
244         if(var.declaration && !assignment_target)
245         {
246                 VariableInfo &var_info = variables.back()[var.declaration];
247                 var_info.assignments.clear();
248                 var_info.referenced = true;
249         }
250 }
251
252 void UnusedVariableLocator::visit(MemberAccess &memacc)
253 {
254         TraversingVisitor::visit(memacc);
255         unused_nodes.erase(memacc.declaration);
256 }
257
258 void UnusedVariableLocator::visit(BinaryExpression &binary)
259 {
260         if(binary.oper=="[")
261         {
262                 if(assignment_target)
263                         assign_to_subscript = true;
264                 binary.left->visit(*this);
265                 SetForScope<bool> set(assignment_target, false);
266                 binary.right->visit(*this);
267         }
268         else
269                 TraversingVisitor::visit(binary);
270 }
271
272 void UnusedVariableLocator::visit(Assignment &assign)
273 {
274         {
275                 assign_to_subscript = false;
276                 SetForScope<bool> set(assignment_target, !assign.self_referencing);
277                 assign.left->visit(*this);
278         }
279         assign.right->visit(*this);
280         assignment = &assign;
281 }
282
283 void UnusedVariableLocator::record_assignment(VariableDeclaration &var, Node &node, bool chained)
284 {
285         VariableInfo &var_info = variables.back()[&var];
286         if(!chained)
287                 clear_assignments(var_info, true);
288         var_info.assignments.push_back(&node);
289         var_info.conditionally_assigned = false;
290 }
291
292 void UnusedVariableLocator::clear_assignments(VariableInfo &var_info, bool mark_unused)
293 {
294         if(mark_unused)
295         {
296                 for(vector<Node *>::iterator i=var_info.assignments.begin(); i!=var_info.assignments.end(); ++i)
297                         unused_nodes.insert(*i);
298         }
299         var_info.assignments.clear();
300 }
301
302 void UnusedVariableLocator::visit(ExpressionStatement &expr)
303 {
304         assignment = 0;
305         TraversingVisitor::visit(expr);
306         if(assignment && assignment->target_declaration)
307                 record_assignment(*assignment->target_declaration, expr, (assignment->self_referencing || assign_to_subscript));
308 }
309
310 void UnusedVariableLocator::visit(StructDeclaration &strct)
311 {
312         SetForScope<Node *> set(aggregate, &strct);
313         unused_nodes.insert(&strct);
314         TraversingVisitor::visit(strct);
315 }
316
317 void UnusedVariableLocator::visit(VariableDeclaration &var)
318 {
319         if(aggregate)
320                 aggregates[&var] = aggregate;
321         else
322         {
323                 variables.back()[&var].local = true;
324                 if(var.init_expression)
325                         record_assignment(var, *var.init_expression, false);
326         }
327         unused_nodes.erase(var.type_declaration);
328         TraversingVisitor::visit(var);
329 }
330
331 void UnusedVariableLocator::visit(InterfaceBlock &iface)
332 {
333         SetForScope<Node *> set(aggregate, &iface);
334         unused_nodes.insert(&iface);
335         TraversingVisitor::visit(iface);
336 }
337
338 void UnusedVariableLocator::visit(FunctionDeclaration &func)
339 {
340         variables.push_back(BlockVariableMap());
341
342         {
343                 SetForScope<bool> set(global_scope, false);
344                 for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
345                         (*i)->visit(*this);
346                 func.body.visit(*this);
347         }
348
349         BlockVariableMap &block_variables = variables.back();
350         for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
351                 i->second.conditionally_assigned = true;
352         for(NodeArray<VariableDeclaration>::iterator i=func.parameters.begin(); i!=func.parameters.end(); ++i)
353                 block_variables[i->get()].referenced = true;
354         merge_down_variables();
355 }
356
357 void UnusedVariableLocator::merge_down_variables()
358 {
359         BlockVariableMap &parent_variables = variables[variables.size()-2];
360         BlockVariableMap &block_variables = variables.back();
361         for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
362         {
363                 if(i->second.local)
364                 {
365                         if(!i->second.referenced)
366                                 unused_nodes.insert(i->first);
367                         clear_assignments(i->second, i->first->interface!="out");
368                         continue;
369                 }
370
371                 BlockVariableMap::iterator j = parent_variables.find(i->first);
372                 if(j==parent_variables.end())
373                         parent_variables.insert(*i);
374                 else
375                 {
376                         if(i->second.referenced || !i->second.conditionally_assigned)
377                                 clear_assignments(j->second, !i->second.referenced);
378                         j->second.conditionally_assigned = i->second.conditionally_assigned;
379                         j->second.referenced |= i->second.referenced;
380                         j->second.assignments.insert(j->second.assignments.end(), i->second.assignments.begin(), i->second.assignments.end());
381                 }
382         }
383         variables.pop_back();
384 }
385
386 void UnusedVariableLocator::visit(Conditional &cond)
387 {
388         cond.condition->visit(*this);
389         variables.push_back(BlockVariableMap());
390         cond.body.visit(*this);
391
392         BlockVariableMap if_variables;
393         swap(variables.back(), if_variables);
394         cond.else_body.visit(*this);
395
396         BlockVariableMap &else_variables = variables.back();
397         for(BlockVariableMap::iterator i=else_variables.begin(); i!=else_variables.end(); ++i)
398         {
399                 BlockVariableMap::iterator j = if_variables.find(i->first);
400                 if(j!=if_variables.end())
401                 {
402                         i->second.assignments.insert(i->second.assignments.end(), j->second.assignments.begin(), j->second.assignments.end());
403                         i->second.conditionally_assigned |= j->second.conditionally_assigned;
404                         if_variables.erase(j);
405                 }
406                 else
407                         i->second.conditionally_assigned = true;
408         }
409
410         for(BlockVariableMap::iterator i=if_variables.begin(); i!=if_variables.end(); ++i)
411         {
412                 i->second.conditionally_assigned = true;
413                 else_variables.insert(*i);
414         }
415
416         merge_down_variables();
417 }
418
419 void UnusedVariableLocator::visit(Iteration &iter)
420 {
421         variables.push_back(BlockVariableMap());
422         TraversingVisitor::visit(iter);
423
424         BlockVariableMap &block_variables = variables.back();
425         for(BlockVariableMap::iterator i=block_variables.begin(); i!=block_variables.end(); ++i)
426                 if(!i->second.local && i->second.referenced)
427                         i->second.assignments.clear();
428
429         merge_down_variables();
430 }
431
432
433 void UnusedFunctionLocator::visit(FunctionCall &call)
434 {
435         TraversingVisitor::visit(call);
436
437         unused_nodes.erase(call.declaration);
438         if(call.declaration && call.declaration->definition!=call.declaration)
439                 used_definitions.insert(call.declaration->definition);
440 }
441
442 void UnusedFunctionLocator::visit(FunctionDeclaration &func)
443 {
444         TraversingVisitor::visit(func);
445
446         if((func.name!="main" || func.body.body.empty()) && !used_definitions.count(&func))
447                 unused_nodes.insert(&func);
448 }
449
450 } // namespace SL
451 } // namespace GL
452 } // namespace Msp