]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/optimize.h
Refactor handling of %, << and >> in ConstantFolder
[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         void set_result(const Variant &, bool = false);
187
188         virtual void visit(RefPtr<Expression> &);
189         virtual void visit(Literal &);
190         virtual void visit(VariableReference &);
191         virtual void visit(MemberAccess &);
192         virtual void visit(Swizzle &);
193         virtual void visit(UnaryExpression &);
194         virtual void visit(BinaryExpression &);
195         virtual void visit(Assignment &);
196         virtual void visit(TernaryExpression &);
197         virtual void visit(FunctionCall &);
198         virtual void visit(VariableDeclaration &);
199         virtual void visit(Iteration &);
200 };
201
202 /** Removes conditional statements and loops where the condition can be
203 determined as constant at compile time. */
204 class ConstantConditionEliminator: private TraversingVisitor
205 {
206 private:
207         enum ConstantStatus
208         {
209                 CONSTANT_FALSE,
210                 CONSTANT_TRUE,
211                 NOT_CONSTANT
212         };
213
214         NodeList<Statement>::iterator insert_point;
215         std::set<Node *> nodes_to_remove;
216         RefPtr<Expression> r_ternary_result;
217
218 public:
219         void apply(Stage &);
220
221 private:
222         ConstantStatus check_constant_condition(const Expression &);
223
224         virtual void visit(Block &);
225         virtual void visit(RefPtr<Expression> &);
226         virtual void visit(TernaryExpression &);
227         virtual void visit(Conditional &);
228         virtual void visit(Iteration &);
229 };
230
231 class UnreachableCodeRemover: private TraversingVisitor
232 {
233 private:
234         bool reachable;
235         std::set<Node *> unreachable_nodes;
236
237 public:
238         UnreachableCodeRemover();
239
240         virtual bool apply(Stage &);
241
242 private:
243         virtual void visit(Block &);
244         virtual void visit(FunctionDeclaration &);
245         virtual void visit(Conditional &);
246         virtual void visit(Iteration &);
247         virtual void visit(Return &) { reachable = false; }
248         virtual void visit(Jump &) { reachable = false; }
249 };
250
251 /** Removes types which are not used anywhere. */
252 class UnusedTypeRemover: private TraversingVisitor
253 {
254 private:
255         std::set<Node *> unused_nodes;
256
257 public:
258         bool apply(Stage &);
259
260 private:
261         virtual void visit(RefPtr<Expression> &);
262         virtual void visit(BasicTypeDeclaration &);
263         virtual void visit(ImageTypeDeclaration &);
264         virtual void visit(StructDeclaration &);
265         virtual void visit(VariableDeclaration &);
266         virtual void visit(InterfaceBlock &);
267         virtual void visit(FunctionDeclaration &);
268 };
269
270 /** Removes variable declarations with no references to them.  Assignment
271 statements where the result is not used are also removed. */
272 class UnusedVariableRemover: private TraversingVisitor
273 {
274 private:
275         struct AssignmentInfo
276         {
277                 Node *node;
278                 Assignment::Target target;
279                 std::vector<Node *> used_by;
280
281                 AssignmentInfo(): node(0) { }
282         };
283
284         struct VariableInfo
285         {
286                 InterfaceBlock *interface_block;
287                 std::vector<AssignmentInfo *> assignments;
288                 bool initialized;
289                 bool output;
290                 bool referenced;
291
292                 VariableInfo(): interface_block(0), initialized(false), output(false), referenced(false) { }
293         };
294
295         typedef std::map<Statement *, VariableInfo> BlockVariableMap;
296
297         Stage *stage;
298         BlockVariableMap variables;
299         std::list<AssignmentInfo> assignments;
300         InterfaceBlock *interface_block;
301         Assignment *r_assignment;
302         bool assignment_target;
303         bool r_side_effects;
304         bool in_struct;
305         bool composite_reference;
306         Assignment::Target r_reference;
307         std::set<Node *> unused_nodes;
308
309 public:
310         UnusedVariableRemover();
311
312         bool apply(Stage &);
313
314 private:
315         void referenced(const Assignment::Target &, Node &);
316         virtual void visit(VariableReference &);
317         virtual void visit(InterfaceBlockReference &);
318         void visit_composite(Expression &);
319         virtual void visit(MemberAccess &);
320         virtual void visit(Swizzle &);
321         virtual void visit(UnaryExpression &);
322         virtual void visit(BinaryExpression &);
323         virtual void visit(Assignment &);
324         virtual void visit(TernaryExpression &);
325         virtual void visit(FunctionCall &);
326         void record_assignment(const Assignment::Target &, Node &);
327         virtual void visit(ExpressionStatement &);
328         virtual void visit(StructDeclaration &);
329         virtual void visit(VariableDeclaration &);
330         virtual void visit(InterfaceBlock &);
331         void merge_variables(const BlockVariableMap &);
332         virtual void visit(FunctionDeclaration &);
333         virtual void visit(Conditional &);
334         virtual void visit(Iteration &);
335 };
336
337 /** Removes function declarations with no references to them. */
338 class UnusedFunctionRemover: private TraversingVisitor
339 {
340 private:
341         std::set<Node *> unused_nodes;
342         std::set<FunctionDeclaration *> used_definitions;
343
344 public:
345         bool apply(Stage &s);
346
347 private:
348         virtual void visit(FunctionCall &);
349         virtual void visit(FunctionDeclaration &);
350 };
351
352 } // namespace SL
353 } // namespace GL
354 } // namespace Msp
355
356 #endif