]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/optimize.h
Recognize unknown index as matching any index
[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                 RefPtr<Expression> initializer;
165                 std::vector<RefPtr<Expression> *> references;
166         };
167
168         struct Aggregate
169         {
170                 VariableDeclaration *declaration = 0;
171                 Block *decl_scope = 0;
172                 NodeList<Statement>::iterator insert_point;
173                 std::vector<AggregateMember> members;
174                 bool referenced = false;
175                 bool members_referenced = false;
176         };
177
178         NodeList<Statement>::iterator insert_point;
179         std::map<Statement *, Aggregate> aggregates;
180         bool composite_reference = false;
181         Assignment::Target r_reference;
182         Aggregate *r_aggregate_ref = 0;
183
184 public:
185         bool apply(Stage &);
186
187 private:
188         virtual void visit(Block &);
189         virtual void visit(RefPtr<Expression> &);
190         virtual void visit(VariableReference &);
191         void visit_composite(RefPtr<Expression> &);
192         virtual void visit(MemberAccess &);
193         virtual void visit(BinaryExpression &);
194         virtual void visit(StructDeclaration &) { }
195         virtual void visit(VariableDeclaration &);
196         virtual void visit(InterfaceBlock &) { }
197 };
198
199 /** Replaces expressions consisting entirely of literals with the results of
200 evaluating the expression.*/
201 class ConstantFolder: private TraversingVisitor
202 {
203 private:
204         VariableDeclaration *iteration_var = 0;
205         Variant iter_init_value;
206         Variant r_constant_value;
207         bool iteration_init = false;
208         bool r_constant = false;
209         bool r_literal = false;
210         bool r_uses_iter_var = false;
211         bool r_any_folded = false;
212
213 public:
214         bool apply(Stage &s) { s.content.visit(*this); return r_any_folded; }
215
216 private:
217         template<typename T>
218         static T evaluate_logical(char, T, T);
219         template<typename T>
220         static bool evaluate_relation(const char *, T, T);
221         template<typename T>
222         static T evaluate_arithmetic(char, T, T);
223         template<typename T>
224         static T evaluate_int_special_op(char, T, T);
225         template<typename T>
226         void convert_to_result(const Variant &);
227         void set_result(const Variant &, bool = false);
228
229         virtual void visit(RefPtr<Expression> &);
230         virtual void visit(Literal &);
231         virtual void visit(VariableReference &);
232         virtual void visit(MemberAccess &);
233         virtual void visit(Swizzle &);
234         virtual void visit(UnaryExpression &);
235         virtual void visit(BinaryExpression &);
236         virtual void visit(Assignment &);
237         virtual void visit(TernaryExpression &);
238         virtual void visit(FunctionCall &);
239         virtual void visit(VariableDeclaration &);
240         virtual void visit(Iteration &);
241 };
242
243 /** Removes conditional statements and loops where the condition can be
244 determined as constant at compile time.  Also removes such statements where
245 the body is empty and the condition has no side effects. */
246 class ConstantConditionEliminator: private TraversingVisitor
247 {
248 private:
249         enum ConstantStatus
250         {
251                 CONSTANT_FALSE,
252                 CONSTANT_TRUE,
253                 NOT_CONSTANT
254         };
255
256         NodeList<Statement>::iterator insert_point;
257         std::set<Node *> nodes_to_remove;
258         RefPtr<Expression> r_ternary_result;
259         bool r_external_side_effects = false;
260
261 public:
262         void apply(Stage &);
263
264 private:
265         ConstantStatus check_constant_condition(const Expression &);
266
267         virtual void visit(Block &);
268         virtual void visit(RefPtr<Expression> &);
269         virtual void visit(UnaryExpression &);
270         virtual void visit(Assignment &);
271         virtual void visit(TernaryExpression &);
272         virtual void visit(FunctionCall &);
273         virtual void visit(Conditional &);
274         virtual void visit(Iteration &);
275 };
276
277 class UnreachableCodeRemover: private TraversingVisitor
278 {
279 private:
280         bool reachable = true;
281         std::set<Node *> unreachable_nodes;
282
283 public:
284         virtual bool apply(Stage &);
285
286 private:
287         virtual void visit(Block &);
288         virtual void visit(FunctionDeclaration &);
289         virtual void visit(Conditional &);
290         virtual void visit(Iteration &);
291         virtual void visit(Return &) { reachable = false; }
292         virtual void visit(Jump &) { reachable = false; }
293 };
294
295 /** Removes types which are not used anywhere. */
296 class UnusedTypeRemover: private TraversingVisitor
297 {
298 private:
299         std::set<Node *> unused_nodes;
300
301 public:
302         bool apply(Stage &);
303
304 private:
305         virtual void visit(RefPtr<Expression> &);
306         virtual void visit(BasicTypeDeclaration &);
307         virtual void visit(ImageTypeDeclaration &);
308         virtual void visit(StructDeclaration &);
309         virtual void visit(VariableDeclaration &);
310         virtual void visit(InterfaceBlock &);
311         virtual void visit(FunctionDeclaration &);
312 };
313
314 /** Removes variable declarations with no references to them.  Assignment
315 statements where the result is not used are also removed. */
316 class UnusedVariableRemover: private TraversingVisitor
317 {
318 private:
319         struct AssignmentInfo
320         {
321                 Node *node = 0;
322                 Assignment::Target target;
323                 std::vector<Node *> used_by;
324                 unsigned in_loop = 0;
325         };
326
327         struct VariableInfo
328         {
329                 InterfaceBlock *interface_block = 0;
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         InterfaceBlock *interface_block = 0;
342         Assignment *r_assignment = 0;
343         bool assignment_target = false;
344         bool r_side_effects = false;
345         bool in_struct = false;
346         bool composite_reference = false;
347         unsigned in_loop = 0;
348         std::vector<Node *> loop_ext_refs;
349         Assignment::Target r_reference;
350         std::set<Node *> unused_nodes;
351
352 public:
353         bool apply(Stage &);
354
355 private:
356         void referenced(const Assignment::Target &, Node &);
357         virtual void visit(VariableReference &);
358         virtual void visit(InterfaceBlockReference &);
359         void visit_composite(Expression &);
360         virtual void visit(MemberAccess &);
361         virtual void visit(Swizzle &);
362         virtual void visit(UnaryExpression &);
363         virtual void visit(BinaryExpression &);
364         virtual void visit(Assignment &);
365         virtual void visit(TernaryExpression &);
366         virtual void visit(FunctionCall &);
367         void record_assignment(const Assignment::Target &, Node &);
368         virtual void visit(ExpressionStatement &);
369         virtual void visit(StructDeclaration &);
370         virtual void visit(VariableDeclaration &);
371         virtual void visit(InterfaceBlock &);
372         void merge_variables(const BlockVariableMap &);
373         virtual void visit(FunctionDeclaration &);
374         virtual void visit(Conditional &);
375         virtual void visit(Iteration &);
376 };
377
378 /** Removes function declarations with no references to them. */
379 class UnusedFunctionRemover: private TraversingVisitor
380 {
381 private:
382         std::set<Node *> unused_nodes;
383         std::set<FunctionDeclaration *> used_definitions;
384
385 public:
386         bool apply(Stage &s);
387
388 private:
389         virtual void visit(FunctionCall &);
390         virtual void visit(FunctionDeclaration &);
391 };
392
393 } // namespace SL
394 } // namespace GL
395 } // namespace Msp
396
397 #endif