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