]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/optimize.h
Use accurate assignment targets in ExpressionInliner
[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 "evaluate.h"
7 #include "visitor.h"
8
9 namespace Msp {
10 namespace GL {
11 namespace SL {
12
13 /** Finds functions which are candidates for inlining.  Currently this means
14 functions which have no parameters, contain no more than one return statement,
15 and are only called once. */
16 class InlineableFunctionLocator: private TraversingVisitor
17 {
18 private:
19         std::map<FunctionDeclaration *, unsigned> refcounts;
20         std::set<FunctionDeclaration *> inlineable;
21         FunctionDeclaration *current_function;
22         unsigned return_count;
23
24 public:
25         InlineableFunctionLocator();
26
27         const std::set<FunctionDeclaration *> &apply(Stage &s) { s.content.visit(*this); return inlineable; }
28
29 private:
30         virtual void visit(FunctionCall &);
31         virtual void visit(FunctionDeclaration &);
32         virtual void visit(Conditional &);
33         virtual void visit(Iteration &);
34         virtual void visit(Return &);
35 };
36
37 /** Injects statements from one function into another.  Local variables are
38 renamed to avoid conflicts.  After inlining, uses NodeReorderer to cause
39 dependencies of the inlined statements to appear before the target function. */
40 class InlineContentInjector: private TraversingVisitor
41 {
42 private:
43         FunctionDeclaration *source_func;
44         Block *target_block;
45         std::map<std::string, VariableDeclaration *> variable_map;
46         bool remap_names;
47         bool deps_only;
48         RefPtr<Statement> r_inlined_statement;
49         std::set<Node *> dependencies;
50         std::string r_result_name;
51
52 public:
53         InlineContentInjector();
54
55         const std::string &apply(Stage &, FunctionDeclaration &, Block &, const NodeList<Statement>::iterator &, FunctionDeclaration &);
56
57 private:
58         std::string create_unused_name(const std::string &, bool);
59
60         virtual void visit(VariableReference &);
61         virtual void visit(InterfaceBlockReference &);
62         virtual void visit(FunctionCall &);
63         virtual void visit(VariableDeclaration &);
64         virtual void visit(Return &);
65 };
66
67 /** Inlines functions.  Internally uses InlineableFunctionLocator to find
68 candidate functions.  Only functions which consist of a single return statement
69 are inlined. */
70 class FunctionInliner: private TraversingVisitor
71 {
72 private:
73         Stage *stage;
74         std::set<FunctionDeclaration *> inlineable;
75         FunctionDeclaration *current_function;
76         NodeList<Statement>::iterator insert_point;
77         RefPtr<Expression> r_inline_result;
78         bool r_any_inlined;
79
80 public:
81         FunctionInliner();
82
83         bool apply(Stage &);
84
85 private:
86         void visit_and_inline(RefPtr<Expression> &);
87
88         virtual void visit(Block &);
89         virtual void visit(UnaryExpression &);
90         virtual void visit(BinaryExpression &);
91         virtual void visit(Assignment &a) { visit(static_cast<BinaryExpression &>(a)); }
92         virtual void visit(MemberAccess &);
93         virtual void visit(Swizzle &);
94         virtual void visit(FunctionCall &);
95         virtual void visit(ExpressionStatement &);
96         virtual void visit(VariableDeclaration &);
97         virtual void visit(FunctionDeclaration &);
98         virtual void visit(Conditional &);
99         virtual void visit(Iteration &);
100         virtual void visit(Return &);
101 };
102
103 /** Inlines variables into expressions.  Variables with trivial values (those
104 consisting of a single literal or variable reference) are always inlined.
105 Variables which are only referenced once are also inlined. */
106 class ExpressionInliner: private TraversingVisitor
107 {
108 private:
109         struct ExpressionInfo
110         {
111                 Expression *expression;
112                 Block *assign_scope;
113                 RefPtr<Expression> *inline_point;
114                 const Operator *inner_oper;
115                 const Operator *outer_oper;
116                 bool inline_on_rhs;
117                 bool trivial;
118                 bool available;
119
120                 ExpressionInfo();
121         };
122
123         std::map<Assignment::Target, ExpressionInfo> expressions;
124         ExpressionInfo *r_ref_info;
125         bool r_any_inlined;
126         bool r_trivial;
127         bool mutating;
128         bool iteration_init;
129         Block *iteration_body;
130         const Operator *r_oper;
131
132 public:
133         ExpressionInliner();
134
135         bool apply(Stage &);
136
137 private:
138         void visit_and_record(RefPtr<Expression> &, const Operator *, bool);
139         void inline_expression(Expression &, RefPtr<Expression> &, const Operator *, const Operator *, bool);
140         virtual void visit(Block &);
141         virtual void visit(VariableReference &);
142         virtual void visit(MemberAccess &);
143         virtual void visit(Swizzle &);
144         virtual void visit(UnaryExpression &);
145         virtual void visit(BinaryExpression &);
146         virtual void visit(Assignment &);
147         virtual void visit(FunctionCall &);
148         virtual void visit(VariableDeclaration &);
149         virtual void visit(Conditional &);
150         virtual void visit(Iteration &);
151         virtual void visit(Return &);
152 };
153
154 /** Removes conditional statements and loops where the condition can be
155 determined as constant at compile time. */
156 class ConstantConditionEliminator: private TraversingVisitor
157 {
158 private:
159         NodeList<Statement>::iterator insert_point;
160         std::set<Node *> nodes_to_remove;
161
162 public:
163         void apply(Stage &);
164
165 private:
166         virtual void visit(Block &);
167         virtual void visit(Conditional &);
168         virtual void visit(Iteration &);
169 };
170
171 /** Removes types which are not used anywhere. */
172 class UnusedTypeRemover: private TraversingVisitor
173 {
174 private:
175         std::set<Node *> unused_nodes;
176
177 public:
178         bool apply(Stage &);
179
180 private:
181         virtual void visit(Literal &);
182         virtual void visit(UnaryExpression &);
183         virtual void visit(BinaryExpression &);
184         virtual void visit(FunctionCall &);
185         virtual void visit(BasicTypeDeclaration &);
186         virtual void visit(ImageTypeDeclaration &);
187         virtual void visit(StructDeclaration &);
188         virtual void visit(VariableDeclaration &);
189         virtual void visit(InterfaceBlock &);
190         virtual void visit(FunctionDeclaration &);
191 };
192
193 /** Removes variable declarations with no references to them.  Assignment
194 statements where the result is not used are also removed. */
195 class UnusedVariableRemover: private TraversingVisitor
196 {
197 private:
198         struct VariableInfo
199         {
200                 std::vector<Node *> assignments;
201                 bool local;
202                 bool output;
203                 bool conditionally_assigned;
204                 bool referenced;
205                 InterfaceBlock *interface_block;
206
207                 VariableInfo();
208         };
209
210         typedef std::map<Assignment::Target, VariableInfo> BlockVariableMap;
211
212         Stage *stage;
213         std::set<Node *> unused_nodes;
214         std::vector<BlockVariableMap> variables;
215         InterfaceBlock *interface_block;
216         Assignment *r_assignment;
217         bool assignment_target;
218         bool r_side_effects;
219
220 public:
221         UnusedVariableRemover();
222
223         bool apply(Stage &);
224
225 private:
226         void reference_used(Statement &);
227         virtual void visit(VariableReference &);
228         virtual void visit(InterfaceBlockReference &);
229         virtual void visit(UnaryExpression &);
230         virtual void visit(BinaryExpression &);
231         virtual void visit(Assignment &);
232         void record_assignment(const Assignment::Target &, Node &, bool);
233         void clear_assignments(VariableInfo &, bool);
234         virtual void visit(FunctionCall &);
235         virtual void visit(ExpressionStatement &);
236         // Ignore structs because their members can't be accessed directly.
237         virtual void visit(StructDeclaration &) { }
238         virtual void visit(VariableDeclaration &);
239         virtual void visit(InterfaceBlock &);
240         virtual void visit(FunctionDeclaration &);
241         void merge_down_variables();
242         virtual void visit(Conditional &);
243         virtual void visit(Iteration &);
244 };
245
246 /** Removes function declarations with no references to them. */
247 class UnusedFunctionRemover: private TraversingVisitor
248 {
249 private:
250         std::set<Node *> unused_nodes;
251         std::set<FunctionDeclaration *> used_definitions;
252
253 public:
254         bool apply(Stage &s);
255
256 private:
257         virtual void visit(FunctionCall &);
258         virtual void visit(FunctionDeclaration &);
259 };
260
261 } // namespace SL
262 } // namespace GL
263 } // namespace Msp
264
265 #endif