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