]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/optimize.h
Remove conditional and iteration statements with no effect from GLSL
[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 ExpressionUse
120         {
121                 RefPtr<Expression> *reference;
122                 Block *ref_scope;
123                 bool blocked;
124
125                 ExpressionUse(): reference(0), ref_scope(0), blocked(false) { }
126         };
127
128         struct ExpressionInfo
129         {
130                 Assignment::Target target;
131                 RefPtr<Expression> expression;
132                 Block *assign_scope;
133                 std::vector<ExpressionUse> uses;
134                 bool trivial;
135
136                 ExpressionInfo(): expression(0), assign_scope(0), trivial(false) { }
137         };
138
139         std::list<ExpressionInfo> expressions;
140         std::map<Assignment::Target, ExpressionInfo *> assignments;
141         ExpressionInfo *r_ref_info;
142         bool r_trivial;
143         bool access_read;
144         bool access_write;
145         bool iteration_init;
146         Block *iteration_body;
147         const Operator *r_oper;
148
149 public:
150         ExpressionInliner();
151
152         bool apply(Stage &);
153
154 private:
155         virtual void visit(RefPtr<Expression> &);
156         virtual void visit(VariableReference &);
157         virtual void visit(MemberAccess &);
158         virtual void visit(Swizzle &);
159         virtual void visit(UnaryExpression &);
160         virtual void visit(BinaryExpression &);
161         virtual void visit(Assignment &);
162         virtual void visit(TernaryExpression &);
163         virtual void visit(FunctionCall &);
164         virtual void visit(VariableDeclaration &);
165         virtual void visit(Iteration &);
166 };
167
168 /** Replaces expressions consisting entirely of literals with the results of
169 evaluating the expression.*/
170 class ConstantFolder: private TraversingVisitor
171 {
172 private:
173         VariableDeclaration *iteration_var;
174         Variant iter_init_value;
175         Variant r_constant_value;
176         bool iteration_init;
177         bool r_constant;
178         bool r_literal;
179         bool r_uses_iter_var;
180         bool r_any_folded;
181
182 public:
183         bool apply(Stage &s) { s.content.visit(*this); return r_any_folded; }
184
185 private:
186         template<typename T>
187         static T evaluate_logical(char, T, T);
188         template<typename T>
189         static bool evaluate_relation(const char *, T, T);
190         template<typename T>
191         static T evaluate_arithmetic(char, T, T);
192         template<typename T>
193         static T evaluate_int_special_op(char, T, T);
194         template<typename T>
195         void convert_to_result(const Variant &);
196         void set_result(const Variant &, bool = false);
197
198         virtual void visit(RefPtr<Expression> &);
199         virtual void visit(Literal &);
200         virtual void visit(VariableReference &);
201         virtual void visit(MemberAccess &);
202         virtual void visit(Swizzle &);
203         virtual void visit(UnaryExpression &);
204         virtual void visit(BinaryExpression &);
205         virtual void visit(Assignment &);
206         virtual void visit(TernaryExpression &);
207         virtual void visit(FunctionCall &);
208         virtual void visit(VariableDeclaration &);
209         virtual void visit(Iteration &);
210 };
211
212 /** Removes conditional statements and loops where the condition can be
213 determined as constant at compile time.  Also removes such statements where
214 the body is empty and the condition has no side effects. */
215 class ConstantConditionEliminator: private TraversingVisitor
216 {
217 private:
218         enum ConstantStatus
219         {
220                 CONSTANT_FALSE,
221                 CONSTANT_TRUE,
222                 NOT_CONSTANT
223         };
224
225         NodeList<Statement>::iterator insert_point;
226         std::set<Node *> nodes_to_remove;
227         RefPtr<Expression> r_ternary_result;
228         bool r_external_side_effects;
229
230 public:
231         void apply(Stage &);
232
233 private:
234         ConstantStatus check_constant_condition(const Expression &);
235
236         virtual void visit(Block &);
237         virtual void visit(RefPtr<Expression> &);
238         virtual void visit(UnaryExpression &);
239         virtual void visit(Assignment &);
240         virtual void visit(TernaryExpression &);
241         virtual void visit(FunctionCall &);
242         virtual void visit(Conditional &);
243         virtual void visit(Iteration &);
244 };
245
246 class UnreachableCodeRemover: private TraversingVisitor
247 {
248 private:
249         bool reachable;
250         std::set<Node *> unreachable_nodes;
251
252 public:
253         UnreachableCodeRemover();
254
255         virtual bool apply(Stage &);
256
257 private:
258         virtual void visit(Block &);
259         virtual void visit(FunctionDeclaration &);
260         virtual void visit(Conditional &);
261         virtual void visit(Iteration &);
262         virtual void visit(Return &) { reachable = false; }
263         virtual void visit(Jump &) { reachable = false; }
264 };
265
266 /** Removes types which are not used anywhere. */
267 class UnusedTypeRemover: private TraversingVisitor
268 {
269 private:
270         std::set<Node *> unused_nodes;
271
272 public:
273         bool apply(Stage &);
274
275 private:
276         virtual void visit(RefPtr<Expression> &);
277         virtual void visit(BasicTypeDeclaration &);
278         virtual void visit(ImageTypeDeclaration &);
279         virtual void visit(StructDeclaration &);
280         virtual void visit(VariableDeclaration &);
281         virtual void visit(InterfaceBlock &);
282         virtual void visit(FunctionDeclaration &);
283 };
284
285 /** Removes variable declarations with no references to them.  Assignment
286 statements where the result is not used are also removed. */
287 class UnusedVariableRemover: private TraversingVisitor
288 {
289 private:
290         struct AssignmentInfo
291         {
292                 Node *node;
293                 Assignment::Target target;
294                 std::vector<Node *> used_by;
295                 unsigned in_loop;
296
297                 AssignmentInfo(): node(0) { }
298         };
299
300         struct VariableInfo
301         {
302                 InterfaceBlock *interface_block;
303                 std::vector<AssignmentInfo *> assignments;
304                 bool initialized;
305                 bool output;
306                 bool referenced;
307
308                 VariableInfo(): interface_block(0), initialized(false), output(false), referenced(false) { }
309         };
310
311         typedef std::map<Statement *, VariableInfo> BlockVariableMap;
312
313         Stage *stage;
314         BlockVariableMap variables;
315         std::list<AssignmentInfo> assignments;
316         InterfaceBlock *interface_block;
317         Assignment *r_assignment;
318         bool assignment_target;
319         bool r_side_effects;
320         bool in_struct;
321         bool composite_reference;
322         unsigned in_loop;
323         std::vector<Node *> loop_ext_refs;
324         Assignment::Target r_reference;
325         std::set<Node *> unused_nodes;
326
327 public:
328         UnusedVariableRemover();
329
330         bool apply(Stage &);
331
332 private:
333         void referenced(const Assignment::Target &, Node &);
334         virtual void visit(VariableReference &);
335         virtual void visit(InterfaceBlockReference &);
336         void visit_composite(Expression &);
337         virtual void visit(MemberAccess &);
338         virtual void visit(Swizzle &);
339         virtual void visit(UnaryExpression &);
340         virtual void visit(BinaryExpression &);
341         virtual void visit(Assignment &);
342         virtual void visit(TernaryExpression &);
343         virtual void visit(FunctionCall &);
344         void record_assignment(const Assignment::Target &, Node &);
345         virtual void visit(ExpressionStatement &);
346         virtual void visit(StructDeclaration &);
347         virtual void visit(VariableDeclaration &);
348         virtual void visit(InterfaceBlock &);
349         void merge_variables(const BlockVariableMap &);
350         virtual void visit(FunctionDeclaration &);
351         virtual void visit(Conditional &);
352         virtual void visit(Iteration &);
353 };
354
355 /** Removes function declarations with no references to them. */
356 class UnusedFunctionRemover: private TraversingVisitor
357 {
358 private:
359         std::set<Node *> unused_nodes;
360         std::set<FunctionDeclaration *> used_definitions;
361
362 public:
363         bool apply(Stage &s);
364
365 private:
366         virtual void visit(FunctionCall &);
367         virtual void visit(FunctionDeclaration &);
368 };
369
370 } // namespace SL
371 } // namespace GL
372 } // namespace Msp
373
374 #endif