]> git.tdb.fi Git - libs/gl.git/blob - source/glsl/reflect.cpp
Process loop initialization outside the body in UnusedVariableRemover
[libs/gl.git] / source / glsl / reflect.cpp
1 #include <msp/core/algorithm.h>
2 #include "reflect.h"
3
4 using namespace std;
5
6 namespace Msp {
7 namespace GL {
8 namespace SL {
9
10 bool is_scalar(const BasicTypeDeclaration &type)
11 {
12         return (type.kind==BasicTypeDeclaration::INT || type.kind==BasicTypeDeclaration::FLOAT);
13 }
14
15 bool is_vector_or_matrix(const BasicTypeDeclaration &type)
16 {
17         return (type.kind==BasicTypeDeclaration::VECTOR || type.kind==BasicTypeDeclaration::MATRIX);
18 }
19
20 BasicTypeDeclaration *get_element_type(BasicTypeDeclaration &type)
21 {
22         if(is_vector_or_matrix(type) || type.kind==BasicTypeDeclaration::ARRAY)
23         {
24                 BasicTypeDeclaration *basic_base = dynamic_cast<BasicTypeDeclaration *>(type.base_type);
25                 return (basic_base ? get_element_type(*basic_base) : 0);
26         }
27         else
28                 return &type;
29 }
30
31 bool can_convert(const BasicTypeDeclaration &from, const BasicTypeDeclaration &to)
32 {
33         if(from.kind==BasicTypeDeclaration::INT && to.kind==BasicTypeDeclaration::FLOAT)
34                 return from.size<=to.size;
35         else if(from.kind!=to.kind)
36                 return false;
37         else if(from.kind==BasicTypeDeclaration::INT && from.sign!=to.sign)
38                 return from.sign && from.size<=to.size;
39         else if(is_vector_or_matrix(from) && from.size==to.size)
40         {
41                 BasicTypeDeclaration *from_base = dynamic_cast<BasicTypeDeclaration *>(from.base_type);
42                 BasicTypeDeclaration *to_base = dynamic_cast<BasicTypeDeclaration *>(to.base_type);
43                 return (from_base && to_base && can_convert(*from_base, *to_base));
44         }
45         else
46                 return false;
47 }
48
49
50 unsigned TypeComparer::next_tag = 1;
51
52 void TypeComparer::compare(Node &node1, Node &node2)
53 {
54         if(&node1==&node2)
55                 r_result = true;
56         else
57         {
58                 second = &node2;
59                 node1.visit(*this);
60         }
61 }
62
63 template<typename T>
64 T *TypeComparer::multi_visit(T &node)
65 {
66         static unsigned tag = next_tag++;
67
68         if(second)
69         {
70                 Node *s = second;
71                 first = &node;
72                 first_tag = tag;
73                 second = 0;
74                 s->visit(*this);
75         }
76         else if(!first || tag!=first_tag)
77                 r_result = false;
78         else
79         {
80                 T *f = static_cast<T *>(first);
81                 first = 0;
82                 return f;
83         }
84
85         return 0;
86 }
87
88 void TypeComparer::visit(Literal &literal)
89 {
90         if(Literal *lit1 = multi_visit(literal))
91         {
92                 if(!lit1->type || !literal.type)
93                         r_result = false;
94                 else
95                 {
96                         compare(*lit1->type, *literal.type);
97                         if(r_result)
98                                 r_result = (literal.value.check_type<int>() && lit1->value.value<int>()==literal.value.value<int>());
99                 }
100         }
101 }
102
103 void TypeComparer::visit(VariableReference &var)
104 {
105         if(VariableReference *var1 = multi_visit(var))
106         {
107                 if(!var1->declaration || !var.declaration)
108                         r_result = false;
109                 else if(!var1->declaration->constant || !var.declaration->constant)
110                         r_result = false;
111                 else if(!var1->declaration->init_expression || !var.declaration->init_expression)
112                         r_result = false;
113                 else
114                         compare(*var1->declaration->init_expression, *var.declaration->init_expression);
115         }
116 }
117
118 void TypeComparer::visit(UnaryExpression &unary)
119 {
120         if(UnaryExpression *unary1 = multi_visit(unary))
121         {
122                 if(unary1->oper!=unary.oper)
123                         r_result = false;
124                 else
125                         compare(*unary1->expression, *unary.expression);
126         }
127 }
128
129 void TypeComparer::visit(BinaryExpression &binary)
130 {
131         if(BinaryExpression *binary1 = multi_visit(binary))
132         {
133                 if(binary1->oper!=binary.oper)
134                         r_result = false;
135                 else
136                 {
137                         compare(*binary1->left, *binary.left);
138                         if(r_result)
139                                 compare(*binary1->right, *binary.right);
140                 }
141         }
142 }
143
144 void TypeComparer::visit(TernaryExpression &ternary)
145 {
146         if(TernaryExpression *ternary1 = multi_visit(ternary))
147         {
148                 if(ternary1->oper!=ternary.oper)
149                         r_result = false;
150                 else
151                 {
152                         compare(*ternary1->condition, *ternary.condition);
153                         if(r_result)
154                                 compare(*ternary1->true_expr, *ternary.true_expr);
155                         if(r_result)
156                                 compare(*ternary1->false_expr, *ternary.false_expr);
157                 }
158         }
159 }
160
161 void TypeComparer::visit(BasicTypeDeclaration &basic)
162 {
163         if(BasicTypeDeclaration *basic1 = multi_visit(basic))
164         {
165                 if(basic1->kind!=basic.kind || basic1->size!=basic.size || basic1->sign!=basic.sign)
166                         r_result = false;
167                 else if(basic1->base_type && basic.base_type)
168                         compare(*basic1->base_type, *basic.base_type);
169                 else
170                         r_result = (!basic1->base_type && !basic.base_type);
171         }
172 }
173
174 void TypeComparer::visit(ImageTypeDeclaration &image)
175 {
176         if(ImageTypeDeclaration *image1 = multi_visit(image))
177         {
178                 if(image1->dimensions!=image.dimensions || image1->array!=image.array)
179                         r_result = false;
180                 else if(image1->sampled!=image.sampled || image1->shadow!=image.shadow)
181                         r_result = false;
182                 else if(image1->base_type && image.base_type)
183                         compare(*image1->base_type, *image.base_type);
184                 else
185                         r_result = (!image1->base_type && !image.base_type);
186         }
187 }
188
189 void TypeComparer::visit(StructDeclaration &strct)
190 {
191         if(StructDeclaration *strct1 = multi_visit(strct))
192         {
193                 if(strct1->members.body.size()!=strct.members.body.size())
194                         r_result = false;
195                 else
196                 {
197                         r_result = true;
198                         auto i = strct1->members.body.begin();
199                         auto j = strct.members.body.begin();
200                         for(; (r_result && i!=strct1->members.body.end()); ++i, ++j)
201                                 compare(**i, **j);
202                 }
203         }
204 }
205
206 void TypeComparer::visit(VariableDeclaration &var)
207 {
208         if(VariableDeclaration *var1 = multi_visit(var))
209         {
210                 if(var1->name!=var.name || var1->array!=var.array)
211                         r_result = false;
212                 else if(!var1->type_declaration || !var.type_declaration)
213                         r_result = false;
214                 else
215                 {
216                         if(var1->array)
217                         {
218                                 r_result = false;
219                                 if(var1->array_size && var.array_size)
220                                         compare(*var1->array_size, *var.array_size);
221                         }
222                         if(r_result && var1->type_declaration!=var.type_declaration)
223                                 compare(*var1->type_declaration, *var.type_declaration);
224                         // TODO Compare layout qualifiers for interface block members
225                 }
226         }
227 }
228
229
230 void LocationCounter::visit(BasicTypeDeclaration &basic)
231 {
232         r_count = basic.kind==BasicTypeDeclaration::MATRIX ? basic.size>>16 : 1;
233 }
234
235 void LocationCounter::visit(ImageTypeDeclaration &)
236 {
237         r_count = 1;
238 }
239
240 void LocationCounter::visit(StructDeclaration &strct)
241 {
242         unsigned total = 0;
243         for(const RefPtr<Statement> &s: strct.members.body)
244         {
245                 r_count = 1;
246                 s->visit(*this);
247                 total += r_count;
248         }
249         r_count = total;
250 }
251
252 void LocationCounter::visit(VariableDeclaration &var)
253 {
254         r_count = 1;
255         if(var.type_declaration)
256                 var.type_declaration->visit(*this);
257         if(var.array)
258                 if(const Literal *literal = dynamic_cast<const Literal *>(var.array_size.get()))
259                         if(literal->value.check_type<int>())
260                                 r_count *= literal->value.value<int>();
261 }
262
263
264 void MemoryRequirementsCalculator::visit(BasicTypeDeclaration &basic)
265 {
266         if(basic.kind==BasicTypeDeclaration::BOOL)
267         {
268                 r_size = 1;
269                 r_alignment = 1;
270         }
271         else if(basic.kind==BasicTypeDeclaration::INT || basic.kind==BasicTypeDeclaration::FLOAT)
272         {
273                 r_size = basic.size/8;
274                 r_alignment = r_size;
275         }
276         else if(basic.kind==BasicTypeDeclaration::VECTOR || basic.kind==BasicTypeDeclaration::MATRIX)
277         {
278                 basic.base_type->visit(*this);
279                 unsigned n_elem = basic.size&0xFFFF;
280                 r_size *= n_elem;
281                 if(basic.kind==BasicTypeDeclaration::VECTOR)
282                         r_alignment *= (n_elem==3 ? 4 : n_elem);
283         }
284         else if(basic.kind==BasicTypeDeclaration::ARRAY)
285                 basic.base_type->visit(*this);
286 }
287
288 void MemoryRequirementsCalculator::visit(StructDeclaration &strct)
289 {
290         unsigned total = 0;
291         unsigned max_align = 1;
292         for(const RefPtr<Statement> &s: strct.members.body)
293         {
294                 r_size = 0;
295                 r_alignment = 1;
296                 r_offset = -1;
297                 s->visit(*this);
298                 if(r_offset)
299                         total = r_offset;
300                 total += r_alignment-1;
301                 total -= total%r_alignment;
302                 total += r_size;
303                 max_align = max(max_align, r_alignment);
304         }
305         r_size = total;
306         r_alignment = max_align;
307         r_size += r_alignment-1;
308         r_size -= r_size%r_alignment;
309 }
310
311 void MemoryRequirementsCalculator::visit(VariableDeclaration &var)
312 {
313         if(var.layout)
314         {
315                 auto i = find_member(var.layout->qualifiers, string("offset"), &Layout::Qualifier::name);
316                 if(i!=var.layout->qualifiers.end())
317                         r_offset = i->value;
318         }
319
320         if(var.type_declaration)
321                 var.type_declaration->visit(*this);
322         if(var.array)
323                 if(const Literal *literal = dynamic_cast<const Literal *>(var.array_size.get()))
324                         if(literal->value.check_type<int>())
325                         {
326                                 unsigned aligned_size = r_size+r_alignment-1;
327                                 aligned_size -= aligned_size%r_alignment;
328                                 r_size = aligned_size*literal->value.value<int>();
329                         }
330 }
331
332
333 set<Node *> DependencyCollector::apply(FunctionDeclaration &func)
334 {
335         func.visit(*this);
336         return dependencies;
337 }
338
339 void DependencyCollector::visit(VariableReference &var)
340 {
341         if(var.declaration && !locals.count(var.declaration))
342         {
343                 dependencies.insert(var.declaration);
344                 var.declaration->visit(*this);
345         }
346 }
347
348 void DependencyCollector::visit(InterfaceBlockReference &iface)
349 {
350         if(iface.declaration)
351         {
352                 dependencies.insert(iface.declaration);
353                 iface.declaration->visit(*this);
354         }
355 }
356
357 void DependencyCollector::visit(FunctionCall &call)
358 {
359         if(call.declaration)
360         {
361                 dependencies.insert(call.declaration);
362                 if(call.declaration->definition)
363                         call.declaration->definition->visit(*this);
364         }
365         TraversingVisitor::visit(call);
366 }
367
368 void DependencyCollector::visit(VariableDeclaration &var)
369 {
370         locals.insert(&var);
371         if(var.type_declaration)
372         {
373                 dependencies.insert(var.type_declaration);
374                 var.type_declaration->visit(*this);
375         }
376
377         TraversingVisitor::visit(var);
378 }
379
380 void DependencyCollector::visit(FunctionDeclaration &func)
381 {
382         if(!visited_functions.count(&func))
383         {
384                 visited_functions.insert(&func);
385                 TraversingVisitor::visit(func);
386         }
387 }
388
389
390 set<VariableDeclaration *> AssignmentCollector::apply(Node &node)
391 {
392         node.visit(*this);
393         return assigned_variables;
394 }
395
396 void AssignmentCollector::visit(Assignment &assign)
397 {
398         if(VariableDeclaration *var = dynamic_cast<VariableDeclaration *>(assign.target.declaration))
399                 assigned_variables.insert(var);
400 }
401
402 } // namespace SL
403 } // namespace GL
404 } // namespace Msp