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