]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/optimize.h
Support inlining GLSL functions with parameters
[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 /** Finds functions which are candidates for inlining.  Currently this means
13 functions which have no flow control statements, no more than one return
14 statement, and are only called once. */
15 class InlineableFunctionLocator: private TraversingVisitor
16 {
17 private:
18         std::map<FunctionDeclaration *, unsigned> refcounts;
19         std::set<FunctionDeclaration *> inlineable;
20         FunctionDeclaration *current_function;
21         unsigned return_count;
22
23 public:
24         InlineableFunctionLocator();
25
26         const std::set<FunctionDeclaration *> &apply(Stage &s) { s.content.visit(*this); return inlineable; }
27
28 private:
29         virtual void visit(FunctionCall &);
30         virtual void visit(FunctionDeclaration &);
31         virtual void visit(Conditional &);
32         virtual void visit(Iteration &);
33         virtual void visit(Return &);
34 };
35
36 /** Injects statements from one function into another.  Local variables are
37 renamed to avoid conflicts.  After inlining, uses NodeReorderer to cause
38 dependencies of the inlined statements to appear before the target function. */
39 class InlineContentInjector: private TraversingVisitor
40 {
41 private:
42         enum Pass
43         {
44                 DEPENDS,
45                 REFERENCED,
46                 INLINE,
47                 RENAME
48         };
49
50         FunctionDeclaration *source_func;
51         Block staging_block;
52         std::string remap_prefix;
53         Pass pass;
54         RefPtr<Statement> r_inlined_statement;
55         std::set<Node *> dependencies;
56         std::set<std::string> referenced_names;
57         std::string r_result_name;
58
59 public:
60         InlineContentInjector();
61
62         const std::string &apply(Stage &, FunctionDeclaration &, Block &, const NodeList<Statement>::iterator &, FunctionCall &);
63
64 private:
65         virtual void visit(VariableReference &);
66         virtual void visit(InterfaceBlockReference &);
67         virtual void visit(FunctionCall &);
68         virtual void visit(VariableDeclaration &);
69         virtual void visit(Return &);
70 };
71
72 /** Inlines functions.  Internally uses InlineableFunctionLocator to find
73 candidate functions.  Only functions which consist of a single return statement
74 are inlined. */
75 class FunctionInliner: private TraversingVisitor
76 {
77 private:
78         Stage *stage;
79         std::set<FunctionDeclaration *> inlineable;
80         FunctionDeclaration *current_function;
81         NodeList<Statement>::iterator insert_point;
82         RefPtr<Expression> r_inline_result;
83         bool r_any_inlined;
84         bool r_inlined_here;
85
86 public:
87         FunctionInliner();
88
89         bool apply(Stage &);
90
91 private:
92         virtual void visit(RefPtr<Expression> &);
93         virtual void visit(Block &);
94         virtual void visit(FunctionCall &);
95         virtual void visit(FunctionDeclaration &);
96         virtual void visit(Iteration &);
97 };
98
99 /** Inlines variables into expressions.  Variables with trivial values (those
100 consisting of a single literal or variable reference) are always inlined.
101 Variables which are only referenced once are also inlined. */
102 class ExpressionInliner: private TraversingVisitor
103 {
104 private:
105         struct ExpressionInfo
106         {
107                 Expression *expression;
108                 Block *assign_scope;
109                 RefPtr<Expression> *inline_point;
110                 bool trivial;
111                 bool available;
112
113                 ExpressionInfo();
114         };
115
116         std::map<Assignment::Target, ExpressionInfo> expressions;
117         ExpressionInfo *r_ref_info;
118         bool r_any_inlined;
119         bool r_trivial;
120         bool mutating;
121         bool iteration_init;
122         Block *iteration_body;
123         const Operator *r_oper;
124
125 public:
126         ExpressionInliner();
127
128         bool apply(Stage &);
129
130 private:
131         void inline_expression(Expression &, RefPtr<Expression> &);
132         virtual void visit(Block &);
133         virtual void visit(RefPtr<Expression> &);
134         virtual void visit(VariableReference &);
135         virtual void visit(MemberAccess &);
136         virtual void visit(Swizzle &);
137         virtual void visit(UnaryExpression &);
138         virtual void visit(BinaryExpression &);
139         virtual void visit(Assignment &);
140         virtual void visit(TernaryExpression &);
141         virtual void visit(FunctionCall &);
142         virtual void visit(VariableDeclaration &);
143         virtual void visit(Iteration &);
144 };
145
146 /** Replaces expressions consisting entirely of literals with the results of
147 evaluating the expression.*/
148 class ConstantFolder: private TraversingVisitor
149 {
150 private:
151         VariableDeclaration *iteration_var;
152         Variant iter_init_value;
153         Variant r_constant_value;
154         bool iteration_init;
155         bool r_constant;
156         bool r_literal;
157         bool r_uses_iter_var;
158         bool r_any_folded;
159
160 public:
161         bool apply(Stage &s) { s.content.visit(*this); return r_any_folded; }
162
163 private:
164         static BasicTypeDeclaration::Kind get_value_kind(const Variant &);
165         template<typename T>
166         static T evaluate_logical(char, T, T);
167         template<typename T>
168         static bool evaluate_relation(const char *, T, T);
169         template<typename T>
170         static T evaluate_arithmetic(char, T, T);
171         void set_result(const Variant &, bool = false);
172
173         virtual void visit(RefPtr<Expression> &);
174         virtual void visit(Literal &);
175         virtual void visit(VariableReference &);
176         virtual void visit(MemberAccess &);
177         virtual void visit(Swizzle &);
178         virtual void visit(UnaryExpression &);
179         virtual void visit(BinaryExpression &);
180         virtual void visit(Assignment &);
181         virtual void visit(TernaryExpression &);
182         virtual void visit(FunctionCall &);
183         virtual void visit(VariableDeclaration &);
184         virtual void visit(Iteration &);
185 };
186
187 /** Removes conditional statements and loops where the condition can be
188 determined as constant at compile time. */
189 class ConstantConditionEliminator: private TraversingVisitor
190 {
191 private:
192         enum ConstantStatus
193         {
194                 CONSTANT_FALSE,
195                 CONSTANT_TRUE,
196                 NOT_CONSTANT
197         };
198
199         NodeList<Statement>::iterator insert_point;
200         std::set<Node *> nodes_to_remove;
201         RefPtr<Expression> r_ternary_result;
202
203 public:
204         void apply(Stage &);
205
206 private:
207         ConstantStatus check_constant_condition(const Expression &);
208
209         virtual void visit(Block &);
210         virtual void visit(RefPtr<Expression> &);
211         virtual void visit(TernaryExpression &);
212         virtual void visit(Conditional &);
213         virtual void visit(Iteration &);
214 };
215
216 /** Removes types which are not used anywhere. */
217 class UnusedTypeRemover: private TraversingVisitor
218 {
219 private:
220         std::set<Node *> unused_nodes;
221
222 public:
223         bool apply(Stage &);
224
225 private:
226         virtual void visit(Literal &);
227         virtual void visit(UnaryExpression &);
228         virtual void visit(BinaryExpression &);
229         virtual void visit(TernaryExpression &);
230         virtual void visit(FunctionCall &);
231         virtual void visit(BasicTypeDeclaration &);
232         virtual void visit(ImageTypeDeclaration &);
233         virtual void visit(StructDeclaration &);
234         virtual void visit(VariableDeclaration &);
235         virtual void visit(InterfaceBlock &);
236         virtual void visit(FunctionDeclaration &);
237 };
238
239 /** Removes variable declarations with no references to them.  Assignment
240 statements where the result is not used are also removed. */
241 class UnusedVariableRemover: private TraversingVisitor
242 {
243 private:
244         struct AssignmentInfo
245         {
246                 Node *node;
247                 Assignment::Target target;
248                 std::vector<Node *> used_by;
249
250                 AssignmentInfo(): node(0) { }
251         };
252
253         struct VariableInfo
254         {
255                 InterfaceBlock *interface_block;
256                 std::vector<AssignmentInfo *> assignments;
257                 bool initialized;
258                 bool output;
259                 bool referenced;
260
261                 VariableInfo(): interface_block(0), initialized(false), output(false), referenced(false) { }
262         };
263
264         typedef std::map<Statement *, VariableInfo> BlockVariableMap;
265
266         Stage *stage;
267         BlockVariableMap variables;
268         std::list<AssignmentInfo> assignments;
269         InterfaceBlock *interface_block;
270         Assignment *r_assignment;
271         bool assignment_target;
272         bool r_side_effects;
273         std::set<Node *> unused_nodes;
274
275 public:
276         UnusedVariableRemover();
277
278         bool apply(Stage &);
279
280 private:
281         void referenced(const Assignment::Target &, Node &);
282         virtual void visit(VariableReference &);
283         virtual void visit(InterfaceBlockReference &);
284         virtual void visit(UnaryExpression &);
285         virtual void visit(BinaryExpression &);
286         virtual void visit(Assignment &);
287         virtual void visit(FunctionCall &);
288         void record_assignment(const Assignment::Target &, Node &);
289         virtual void visit(ExpressionStatement &);
290         // Ignore structs because their members can't be accessed directly.
291         virtual void visit(StructDeclaration &) { }
292         virtual void visit(VariableDeclaration &);
293         virtual void visit(InterfaceBlock &);
294         void merge_variables(const BlockVariableMap &);
295         virtual void visit(FunctionDeclaration &);
296         virtual void visit(Conditional &);
297         virtual void visit(Iteration &);
298 };
299
300 /** Removes function declarations with no references to them. */
301 class UnusedFunctionRemover: private TraversingVisitor
302 {
303 private:
304         std::set<Node *> unused_nodes;
305         std::set<FunctionDeclaration *> used_definitions;
306
307 public:
308         bool apply(Stage &s);
309
310 private:
311         virtual void visit(FunctionCall &);
312         virtual void visit(FunctionDeclaration &);
313 };
314
315 } // namespace SL
316 } // namespace GL
317 } // namespace Msp
318
319 #endif