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