]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/optimize.h
Process loop initialization outside the body in UnusedVariableRemover
[libs/gl.git] / source / glsl / optimize.h
1 #ifndef MSP_GL_SL_OPTIMIZE_H_
2 #define MSP_GL_SL_OPTIMIZE_H_
3
4 #include <map>
5 #include <set>
6 #include "visitor.h"
7
8 namespace Msp {
9 namespace GL {
10 namespace SL {
11
12 /** Assigns values to specialization constants, turning them into normal
13 constants. */
14 class ConstantSpecializer: private TraversingVisitor
15 {
16 private:
17         const std::map<std::string, int> *values = 0;
18
19 public:
20         void apply(Stage &, const std::map<std::string, int> &);
21
22 private:
23         virtual void visit(VariableDeclaration &);
24 };
25
26 /** Finds functions which are candidates for inlining.  Currently this means
27 functions which have no flow control statements, no more than one return
28 statement, and are either builtins or only called once. */
29 class InlineableFunctionLocator: private TraversingVisitor
30 {
31 private:
32         std::map<FunctionDeclaration *, unsigned> refcounts;
33         std::set<FunctionDeclaration *> inlineable;
34         FunctionDeclaration *current_function = 0;
35         unsigned return_count = 0;
36
37 public:
38         std::set<FunctionDeclaration *> apply(Stage &s) { s.content.visit(*this); return inlineable; }
39
40 private:
41         virtual void visit(FunctionCall &);
42         virtual void visit(FunctionDeclaration &);
43         virtual void visit(Conditional &);
44         virtual void visit(Iteration &);
45         virtual void visit(Return &);
46 };
47
48 /** Injects statements from one function into another.  Local variables are
49 renamed to avoid conflicts.  After inlining, uses NodeReorderer to cause
50 dependencies of the inlined statements to appear before the target function. */
51 class InlineContentInjector: private TraversingVisitor
52 {
53 private:
54         enum Pass
55         {
56                 REFERENCED,
57                 INLINE,
58                 RENAME
59         };
60
61         FunctionDeclaration *source_func = 0;
62         Block staging_block;
63         Pass pass = REFERENCED;
64         RefPtr<Statement> r_inlined_statement;
65         std::set<Node *> dependencies;
66         std::set<std::string> referenced_names;
67         std::string r_result_name;
68
69 public:
70         std::string apply(Stage &, FunctionDeclaration &, Block &, const NodeList<Statement>::iterator &, FunctionCall &);
71
72 private:
73         virtual void visit(VariableReference &);
74         virtual void visit(InterfaceBlockReference &);
75         virtual void visit(FunctionCall &);
76         virtual void visit(VariableDeclaration &);
77         virtual void visit(Return &);
78 };
79
80 /** Inlines functions.  Internally uses InlineableFunctionLocator to find
81 candidate functions.  Only functions which consist of a single return statement
82 are inlined. */
83 class FunctionInliner: private TraversingVisitor
84 {
85 private:
86         Stage *stage = 0;
87         std::set<FunctionDeclaration *> inlineable;
88         FunctionDeclaration *current_function = 0;
89         NodeList<Statement>::iterator insert_point;
90         RefPtr<Expression> r_inline_result;
91         bool r_any_inlined = false;
92         bool r_inlined_here = false;
93
94 public:
95         bool apply(Stage &);
96
97 private:
98         virtual void visit(RefPtr<Expression> &);
99         virtual void visit(Block &);
100         virtual void visit(FunctionCall &);
101         virtual void visit(FunctionDeclaration &);
102         virtual void visit(Iteration &);
103 };
104
105 /** Inlines variables into expressions.  Variables with trivial values (those
106 consisting of a single literal or variable reference) are always inlined.
107 Variables which are only referenced once are also inlined. */
108 class ExpressionInliner: private TraversingVisitor
109 {
110 private:
111         struct ExpressionUse
112         {
113                 RefPtr<Expression> *reference = 0;
114                 Block *ref_scope = 0;
115                 bool blocked = false;
116         };
117
118         struct ExpressionInfo
119         {
120                 Assignment::Target target;
121                 RefPtr<Expression> expression;
122                 Block *assign_scope = 0;
123                 std::vector<ExpressionUse> uses;
124                 bool trivial = false;
125         };
126
127         std::list<ExpressionInfo> expressions;
128         std::map<Assignment::Target, ExpressionInfo *> assignments;
129         ExpressionInfo *r_ref_info = 0;
130         bool r_trivial = false;
131         bool access_read = true;
132         bool access_write = false;
133         bool iteration_init = false;
134         Block *iteration_body = 0;
135         const Operator *r_oper = 0;
136
137 public:
138         bool apply(Stage &);
139
140 private:
141         virtual void visit(RefPtr<Expression> &);
142         virtual void visit(VariableReference &);
143         virtual void visit(MemberAccess &);
144         virtual void visit(Swizzle &);
145         virtual void visit(UnaryExpression &);
146         virtual void visit(BinaryExpression &);
147         virtual void visit(Assignment &);
148         virtual void visit(TernaryExpression &);
149         virtual void visit(FunctionCall &);
150         virtual void visit(VariableDeclaration &);
151         virtual void visit(Iteration &);
152 };
153
154 /**
155 Breaks aggregates up into separate variables if only the individual fields are
156 accessed and not the aggregate as a whole.
157 */
158 class AggregateDismantler: public TraversingVisitor
159 {
160 private:
161         struct AggregateMember
162         {
163                 const VariableDeclaration *declaration = 0;
164                 unsigned index = 0;
165                 RefPtr<Expression> initializer;
166                 std::vector<RefPtr<Expression> *> references;
167         };
168
169         struct Aggregate
170         {
171                 VariableDeclaration *declaration = 0;
172                 Block *decl_scope = 0;
173                 NodeList<Statement>::iterator insert_point;
174                 std::vector<AggregateMember> members;
175                 bool referenced = false;
176                 bool members_referenced = false;
177         };
178
179         NodeList<Statement>::iterator insert_point;
180         std::map<Statement *, Aggregate> aggregates;
181         bool composite_reference = false;
182         Assignment::Target r_reference;
183         Aggregate *r_aggregate_ref = 0;
184
185 public:
186         bool apply(Stage &);
187
188 private:
189         virtual void visit(Block &);
190         virtual void visit(RefPtr<Expression> &);
191         virtual void visit(VariableReference &);
192         void visit_composite(RefPtr<Expression> &);
193         virtual void visit(MemberAccess &);
194         virtual void visit(BinaryExpression &);
195         virtual void visit(StructDeclaration &) { }
196         virtual void visit(VariableDeclaration &);
197         virtual void visit(InterfaceBlock &) { }
198         virtual void visit(FunctionDeclaration &);
199 };
200
201 /** Replaces expressions consisting entirely of literals with the results of
202 evaluating the expression.*/
203 class ConstantFolder: private TraversingVisitor
204 {
205 private:
206         VariableDeclaration *iteration_var = 0;
207         Variant iter_init_value;
208         Variant r_constant_value;
209         bool iteration_init = false;
210         bool r_constant = false;
211         bool r_literal = false;
212         bool r_uses_iter_var = false;
213         bool r_any_folded = false;
214
215 public:
216         bool apply(Stage &s) { s.content.visit(*this); return r_any_folded; }
217
218 private:
219         template<typename T>
220         static T evaluate_logical(char, T, T);
221         template<typename T>
222         static bool evaluate_relation(const char *, T, T);
223         template<typename T>
224         static T evaluate_arithmetic(char, T, T);
225         template<typename T>
226         static T evaluate_int_special_op(char, T, T);
227         template<typename T>
228         void convert_to_result(const Variant &);
229         void set_result(const Variant &, bool = false);
230
231         virtual void visit(RefPtr<Expression> &);
232         virtual void visit(Literal &);
233         virtual void visit(VariableReference &);
234         virtual void visit(MemberAccess &);
235         virtual void visit(Swizzle &);
236         virtual void visit(UnaryExpression &);
237         virtual void visit(BinaryExpression &);
238         virtual void visit(Assignment &);
239         virtual void visit(TernaryExpression &);
240         virtual void visit(FunctionCall &);
241         virtual void visit(VariableDeclaration &);
242         virtual void visit(Iteration &);
243 };
244
245 /** Removes conditional statements and loops where the condition can be
246 determined as constant at compile time.  Also removes such statements where
247 the body is empty and the condition has no side effects. */
248 class ConstantConditionEliminator: private TraversingVisitor
249 {
250 private:
251         enum ConstantStatus
252         {
253                 CONSTANT_FALSE,
254                 CONSTANT_TRUE,
255                 NOT_CONSTANT
256         };
257
258         NodeList<Statement>::iterator insert_point;
259         std::set<Node *> nodes_to_remove;
260         RefPtr<Expression> r_ternary_result;
261         bool r_external_side_effects = false;
262
263 public:
264         void apply(Stage &);
265
266 private:
267         ConstantStatus check_constant_condition(const Expression &);
268
269         virtual void visit(Block &);
270         virtual void visit(RefPtr<Expression> &);
271         virtual void visit(UnaryExpression &);
272         virtual void visit(Assignment &);
273         virtual void visit(TernaryExpression &);
274         virtual void visit(FunctionCall &);
275         virtual void visit(Conditional &);
276         virtual void visit(Iteration &);
277 };
278
279 /** Removes code which is never executed due to flow control statements. */
280 class UnreachableCodeRemover: private TraversingVisitor
281 {
282 private:
283         bool reachable = true;
284         std::set<Node *> unreachable_nodes;
285
286 public:
287         virtual bool apply(Stage &);
288
289 private:
290         virtual void visit(Block &);
291         virtual void visit(FunctionDeclaration &);
292         virtual void visit(Conditional &);
293         virtual void visit(Iteration &);
294         virtual void visit(Return &) { reachable = false; }
295         virtual void visit(Jump &) { reachable = false; }
296 };
297
298 /** Removes types which are not used anywhere. */
299 class UnusedTypeRemover: private TraversingVisitor
300 {
301 private:
302         std::set<Node *> unused_nodes;
303
304 public:
305         bool apply(Stage &);
306
307 private:
308         virtual void visit(RefPtr<Expression> &);
309         virtual void visit(BasicTypeDeclaration &);
310         virtual void visit(ImageTypeDeclaration &);
311         virtual void visit(StructDeclaration &);
312         virtual void visit(VariableDeclaration &);
313         virtual void visit(InterfaceBlock &);
314         virtual void visit(FunctionDeclaration &);
315 };
316
317 /** Removes variable declarations with no references to them.  Assignment
318 statements where the result is not used are also removed. */
319 class UnusedVariableRemover: private TraversingVisitor
320 {
321 private:
322         struct AssignmentInfo
323         {
324                 Node *node = 0;
325                 Assignment::Target target;
326                 std::vector<Node *> used_by;
327                 unsigned in_loop = 0;
328         };
329
330         struct VariableInfo
331         {
332                 std::vector<AssignmentInfo *> assignments;
333                 bool initialized = false;
334                 bool output = false;
335                 bool referenced = false;
336         };
337
338         typedef std::map<Statement *, VariableInfo> BlockVariableMap;
339
340         Stage *stage = 0;
341         BlockVariableMap variables;
342         std::list<AssignmentInfo> assignments;
343         Assignment *r_assignment = 0;
344         bool assignment_target = false;
345         bool r_side_effects = false;
346         bool in_struct = false;
347         bool composite_reference = false;
348         unsigned in_loop = 0;
349         std::vector<Node *> loop_ext_refs;
350         Assignment::Target r_reference;
351         std::set<Node *> unused_nodes;
352
353 public:
354         bool apply(Stage &);
355
356 private:
357         void referenced(const Assignment::Target &, Node &);
358         virtual void visit(VariableReference &);
359         virtual void visit(InterfaceBlockReference &);
360         void visit_composite(Expression &);
361         virtual void visit(MemberAccess &);
362         virtual void visit(Swizzle &);
363         virtual void visit(UnaryExpression &);
364         virtual void visit(BinaryExpression &);
365         virtual void visit(Assignment &);
366         virtual void visit(TernaryExpression &);
367         virtual void visit(FunctionCall &);
368         void record_assignment(const Assignment::Target &, Node &);
369         virtual void visit(ExpressionStatement &);
370         virtual void visit(StructDeclaration &);
371         virtual void visit(VariableDeclaration &);
372         virtual void visit(InterfaceBlock &);
373         void merge_variables(const BlockVariableMap &);
374         virtual void visit(FunctionDeclaration &);
375         virtual void visit(Conditional &);
376         virtual void visit(Iteration &);
377 };
378
379 /** Removes function declarations with no references to them. */
380 class UnusedFunctionRemover: private TraversingVisitor
381 {
382 private:
383         std::set<Node *> unused_nodes;
384         std::set<FunctionDeclaration *> used_definitions;
385
386 public:
387         bool apply(Stage &s);
388
389 private:
390         virtual void visit(FunctionCall &);
391         virtual void visit(FunctionDeclaration &);
392 };
393
394 } // namespace SL
395 } // namespace GL
396 } // namespace Msp
397
398 #endif