]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/optimize.h
d434c68a85c1df63594dcda6294c9698573e969f
[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 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         const 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         const 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(Literal &);
241         virtual void visit(UnaryExpression &);
242         virtual void visit(BinaryExpression &);
243         virtual void visit(TernaryExpression &);
244         virtual void visit(FunctionCall &);
245         virtual void visit(BasicTypeDeclaration &);
246         virtual void visit(ImageTypeDeclaration &);
247         virtual void visit(StructDeclaration &);
248         virtual void visit(VariableDeclaration &);
249         virtual void visit(InterfaceBlock &);
250         virtual void visit(FunctionDeclaration &);
251 };
252
253 /** Removes variable declarations with no references to them.  Assignment
254 statements where the result is not used are also removed. */
255 class UnusedVariableRemover: private TraversingVisitor
256 {
257 private:
258         struct AssignmentInfo
259         {
260                 Node *node;
261                 Assignment::Target target;
262                 std::vector<Node *> used_by;
263
264                 AssignmentInfo(): node(0) { }
265         };
266
267         struct VariableInfo
268         {
269                 InterfaceBlock *interface_block;
270                 std::vector<AssignmentInfo *> assignments;
271                 bool initialized;
272                 bool output;
273                 bool referenced;
274
275                 VariableInfo(): interface_block(0), initialized(false), output(false), referenced(false) { }
276         };
277
278         typedef std::map<Statement *, VariableInfo> BlockVariableMap;
279
280         Stage *stage;
281         BlockVariableMap variables;
282         std::list<AssignmentInfo> assignments;
283         InterfaceBlock *interface_block;
284         Assignment *r_assignment;
285         bool assignment_target;
286         bool r_side_effects;
287         std::set<Node *> unused_nodes;
288
289 public:
290         UnusedVariableRemover();
291
292         bool apply(Stage &);
293
294 private:
295         void referenced(const Assignment::Target &, Node &);
296         virtual void visit(VariableReference &);
297         virtual void visit(InterfaceBlockReference &);
298         virtual void visit(UnaryExpression &);
299         virtual void visit(BinaryExpression &);
300         virtual void visit(Assignment &);
301         virtual void visit(FunctionCall &);
302         void record_assignment(const Assignment::Target &, Node &);
303         virtual void visit(ExpressionStatement &);
304         // Ignore structs because their members can't be accessed directly.
305         virtual void visit(StructDeclaration &) { }
306         virtual void visit(VariableDeclaration &);
307         virtual void visit(InterfaceBlock &);
308         void merge_variables(const BlockVariableMap &);
309         virtual void visit(FunctionDeclaration &);
310         virtual void visit(Conditional &);
311         virtual void visit(Iteration &);
312 };
313
314 /** Removes function declarations with no references to them. */
315 class UnusedFunctionRemover: private TraversingVisitor
316 {
317 private:
318         std::set<Node *> unused_nodes;
319         std::set<FunctionDeclaration *> used_definitions;
320
321 public:
322         bool apply(Stage &s);
323
324 private:
325         virtual void visit(FunctionCall &);
326         virtual void visit(FunctionDeclaration &);
327 };
328
329 } // namespace SL
330 } // namespace GL
331 } // namespace Msp
332
333 #endif