]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/optimize.h
Check the flat qualifier from the correct member
[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(FunctionCall &);
75         virtual void visit(VariableDeclaration &);
76         virtual void visit(Return &);
77 };
78
79 /** Inlines functions.  Internally uses InlineableFunctionLocator to find
80 candidate functions.  Only functions which consist of a single return statement
81 are inlined. */
82 class FunctionInliner: private TraversingVisitor
83 {
84 private:
85         Stage *stage = 0;
86         std::set<FunctionDeclaration *> inlineable;
87         FunctionDeclaration *current_function = 0;
88         NodeList<Statement>::iterator insert_point;
89         RefPtr<Expression> r_inline_result;
90         bool r_any_inlined = false;
91         bool r_inlined_here = false;
92
93 public:
94         bool apply(Stage &);
95
96 private:
97         virtual void visit(RefPtr<Expression> &);
98         virtual void visit(Block &);
99         virtual void visit(FunctionCall &);
100         virtual void visit(FunctionDeclaration &);
101         virtual void visit(Iteration &);
102 };
103
104 /** Inlines variables into expressions.  Variables with trivial values (those
105 consisting of a single literal or variable reference) are always inlined.
106 Variables which are only referenced once are also inlined. */
107 class ExpressionInliner: private TraversingVisitor
108 {
109 private:
110         struct ExpressionUse
111         {
112                 RefPtr<Expression> *reference = 0;
113                 Block *ref_scope = 0;
114                 bool blocked = false;
115         };
116
117         struct ExpressionInfo
118         {
119                 Assignment::Target target;
120                 RefPtr<Expression> expression;
121                 Block *assign_scope = 0;
122                 std::vector<ExpressionUse> uses;
123                 bool trivial = false;
124                 bool blocked = 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(FunctionDeclaration &);
198 };
199
200 /** Replaces expressions consisting entirely of literals with the results of
201 evaluating the expression.*/
202 class ConstantFolder: private TraversingVisitor
203 {
204 private:
205         VariableDeclaration *iteration_var = 0;
206         Variant iter_init_value;
207         Variant r_constant_value;
208         bool iteration_init = false;
209         bool r_constant = false;
210         bool r_literal = false;
211         bool r_uses_iter_var = false;
212         bool r_any_folded = false;
213
214 public:
215         bool apply(Stage &s) { s.content.visit(*this); return r_any_folded; }
216
217 private:
218         template<typename T>
219         static T evaluate_logical(char, T, T);
220         template<typename T>
221         static bool evaluate_relation(const char *, T, T);
222         template<typename T>
223         static T evaluate_arithmetic(char, T, T);
224         template<typename T>
225         static T evaluate_int_special_op(char, T, T);
226         template<typename T>
227         void convert_to_result(const Variant &);
228         void set_result(const Variant &, bool = false);
229
230         virtual void visit(RefPtr<Expression> &);
231         virtual void visit(Literal &);
232         virtual void visit(VariableReference &);
233         virtual void visit(MemberAccess &);
234         virtual void visit(Swizzle &);
235         virtual void visit(UnaryExpression &);
236         virtual void visit(BinaryExpression &);
237         virtual void visit(Assignment &);
238         virtual void visit(TernaryExpression &);
239         virtual void visit(FunctionCall &);
240         virtual void visit(VariableDeclaration &);
241         virtual void visit(Iteration &);
242 };
243
244 /** Removes conditional statements and loops where the condition can be
245 determined as constant at compile time.  Also removes such statements where
246 the body is empty and the condition has no side effects. */
247 class ConstantConditionEliminator: private TraversingVisitor
248 {
249 private:
250         enum ConstantStatus
251         {
252                 CONSTANT_FALSE,
253                 CONSTANT_TRUE,
254                 NOT_CONSTANT
255         };
256
257         NodeList<Statement>::iterator insert_point;
258         std::set<Node *> nodes_to_remove;
259         RefPtr<Expression> r_ternary_result;
260         bool r_external_side_effects = false;
261
262 public:
263         bool apply(Stage &);
264
265 private:
266         ConstantStatus check_constant_condition(const Expression &);
267
268         virtual void visit(Block &);
269         virtual void visit(RefPtr<Expression> &);
270         virtual void visit(UnaryExpression &);
271         virtual void visit(Assignment &);
272         virtual void visit(TernaryExpression &);
273         virtual void visit(FunctionCall &);
274         virtual void visit(Conditional &);
275         virtual void visit(Iteration &);
276 };
277
278 /** Removes code which is never executed due to flow control statements. */
279 class UnreachableCodeRemover: private TraversingVisitor
280 {
281 private:
282         bool reachable = true;
283         std::set<Node *> unreachable_nodes;
284
285 public:
286         virtual bool apply(Stage &);
287
288 private:
289         virtual void visit(Block &);
290         virtual void visit(FunctionDeclaration &);
291         virtual void visit(Conditional &);
292         virtual void visit(Iteration &);
293         virtual void visit(Return &) { reachable = false; }
294         virtual void visit(Jump &) { reachable = false; }
295 };
296
297 /** Removes types which are not used anywhere. */
298 class UnusedTypeRemover: private TraversingVisitor
299 {
300 private:
301         std::set<Node *> unused_nodes;
302
303 public:
304         bool apply(Stage &);
305
306 private:
307         virtual void visit(RefPtr<Expression> &);
308         virtual void visit(BasicTypeDeclaration &);
309         virtual void visit(ImageTypeDeclaration &);
310         virtual void visit(StructDeclaration &);
311         virtual void visit(VariableDeclaration &);
312         virtual void visit(FunctionDeclaration &);
313 };
314
315 /** Removes variable declarations with no references to them.  Assignment
316 statements where the result is not used are also removed. */
317 class UnusedVariableRemover: private TraversingVisitor
318 {
319 private:
320         struct AssignmentInfo
321         {
322                 Node *node = 0;
323                 Assignment::Target target;
324                 std::vector<Node *> used_by;
325                 unsigned in_loop = 0;
326         };
327
328         struct VariableInfo
329         {
330                 std::vector<AssignmentInfo *> assignments;
331                 bool initialized = false;
332                 bool output = false;
333                 bool referenced = false;
334         };
335
336         typedef std::map<Statement *, VariableInfo> BlockVariableMap;
337
338         Stage *stage = 0;
339         BlockVariableMap variables;
340         std::list<AssignmentInfo> assignments;
341         Assignment *r_assignment = 0;
342         bool assignment_target = false;
343         bool r_side_effects = false;
344         bool in_struct = false;
345         bool composite_reference = false;
346         unsigned in_loop = 0;
347         std::vector<Node *> loop_ext_refs;
348         Assignment::Target r_reference;
349         std::set<Node *> unused_nodes;
350
351 public:
352         bool apply(Stage &);
353
354 private:
355         void referenced(const Assignment::Target &, Node &);
356         virtual void visit(VariableReference &);
357         void visit_composite(Expression &);
358         virtual void visit(MemberAccess &);
359         virtual void visit(Swizzle &);
360         virtual void visit(UnaryExpression &);
361         virtual void visit(BinaryExpression &);
362         virtual void visit(Assignment &);
363         virtual void visit(TernaryExpression &);
364         virtual void visit(FunctionCall &);
365         void record_assignment(const Assignment::Target &, Node &);
366         virtual void visit(ExpressionStatement &);
367         virtual void visit(StructDeclaration &);
368         virtual void visit(VariableDeclaration &);
369         void merge_variables(const BlockVariableMap &);
370         virtual void visit(FunctionDeclaration &);
371         virtual void visit(Conditional &);
372         virtual void visit(Iteration &);
373 };
374
375 /** Removes function declarations with no references to them. */
376 class UnusedFunctionRemover: private TraversingVisitor
377 {
378 private:
379         std::set<Node *> unused_nodes;
380         std::set<FunctionDeclaration *> used_definitions;
381
382 public:
383         bool apply(Stage &s);
384
385 private:
386         virtual void visit(FunctionCall &);
387         virtual void visit(FunctionDeclaration &);
388 };
389
390 } // namespace SL
391 } // namespace GL
392 } // namespace Msp
393
394 #endif