]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/optimize.h
Fold type conversions of constants
[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
283                 AssignmentInfo(): node(0) { }
284         };
285
286         struct VariableInfo
287         {
288                 InterfaceBlock *interface_block;
289                 std::vector<AssignmentInfo *> assignments;
290                 bool initialized;
291                 bool output;
292                 bool referenced;
293
294                 VariableInfo(): interface_block(0), initialized(false), output(false), referenced(false) { }
295         };
296
297         typedef std::map<Statement *, VariableInfo> BlockVariableMap;
298
299         Stage *stage;
300         BlockVariableMap variables;
301         std::list<AssignmentInfo> assignments;
302         InterfaceBlock *interface_block;
303         Assignment *r_assignment;
304         bool assignment_target;
305         bool r_side_effects;
306         bool in_struct;
307         bool composite_reference;
308         Assignment::Target r_reference;
309         std::set<Node *> unused_nodes;
310
311 public:
312         UnusedVariableRemover();
313
314         bool apply(Stage &);
315
316 private:
317         void referenced(const Assignment::Target &, Node &);
318         virtual void visit(VariableReference &);
319         virtual void visit(InterfaceBlockReference &);
320         void visit_composite(Expression &);
321         virtual void visit(MemberAccess &);
322         virtual void visit(Swizzle &);
323         virtual void visit(UnaryExpression &);
324         virtual void visit(BinaryExpression &);
325         virtual void visit(Assignment &);
326         virtual void visit(TernaryExpression &);
327         virtual void visit(FunctionCall &);
328         void record_assignment(const Assignment::Target &, Node &);
329         virtual void visit(ExpressionStatement &);
330         virtual void visit(StructDeclaration &);
331         virtual void visit(VariableDeclaration &);
332         virtual void visit(InterfaceBlock &);
333         void merge_variables(const BlockVariableMap &);
334         virtual void visit(FunctionDeclaration &);
335         virtual void visit(Conditional &);
336         virtual void visit(Iteration &);
337 };
338
339 /** Removes function declarations with no references to them. */
340 class UnusedFunctionRemover: private TraversingVisitor
341 {
342 private:
343         std::set<Node *> unused_nodes;
344         std::set<FunctionDeclaration *> used_definitions;
345
346 public:
347         bool apply(Stage &s);
348
349 private:
350         virtual void visit(FunctionCall &);
351         virtual void visit(FunctionDeclaration &);
352 };
353
354 } // namespace SL
355 } // namespace GL
356 } // namespace Msp
357
358 #endif