s/slang_assembly_typeinfo/slang_typeinfo/
[mesa.git] / src / mesa / shader / slang / slang_typeinfo.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 *
5 * Copyright (C) 2005-2006 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /**
26 * \file slang_assemble_typeinfo.c
27 * slang type info
28 * \author Michal Krol
29 */
30
31 #include "imports.h"
32 #include "slang_typeinfo.h"
33 #include "slang_compile.h"
34 #include "slang_error.h"
35 #include "prog_instruction.h"
36
37
38
39
40 /**
41 * Checks if a field selector is a general swizzle (an r-value swizzle
42 * with replicated components or an l-value swizzle mask) for a
43 * vector. Returns GL_TRUE if this is the case, <swz> is filled with
44 * swizzle information. Returns GL_FALSE otherwise.
45 */
46 GLboolean
47 _slang_is_swizzle(const char *field, GLuint rows, slang_swizzle * swz)
48 {
49 GLuint i;
50 GLboolean xyzw = GL_FALSE, rgba = GL_FALSE, stpq = GL_FALSE;
51
52 /* init to undefined.
53 * We rely on undefined/nil values to distinguish between
54 * regular swizzles and writemasks.
55 * For example, the swizzle ".xNNN" is the writemask ".x".
56 * That's different than the swizzle ".xxxx".
57 */
58 for (i = 0; i < 4; i++)
59 swz->swizzle[i] = SWIZZLE_NIL;
60
61 /* the swizzle can be at most 4-component long */
62 swz->num_components = slang_string_length(field);
63 if (swz->num_components > 4)
64 return GL_FALSE;
65
66 for (i = 0; i < swz->num_components; i++) {
67 /* mark which swizzle group is used */
68 switch (field[i]) {
69 case 'x':
70 case 'y':
71 case 'z':
72 case 'w':
73 xyzw = GL_TRUE;
74 break;
75 case 'r':
76 case 'g':
77 case 'b':
78 case 'a':
79 rgba = GL_TRUE;
80 break;
81 case 's':
82 case 't':
83 case 'p':
84 case 'q':
85 stpq = GL_TRUE;
86 break;
87 default:
88 return GL_FALSE;
89 }
90
91 /* collect swizzle component */
92 switch (field[i]) {
93 case 'x':
94 case 'r':
95 case 's':
96 swz->swizzle[i] = 0;
97 break;
98 case 'y':
99 case 'g':
100 case 't':
101 swz->swizzle[i] = 1;
102 break;
103 case 'z':
104 case 'b':
105 case 'p':
106 swz->swizzle[i] = 2;
107 break;
108 case 'w':
109 case 'a':
110 case 'q':
111 swz->swizzle[i] = 3;
112 break;
113 }
114
115 /* check if the component is valid for given vector's row count */
116 if (rows <= swz->swizzle[i])
117 return GL_FALSE;
118 }
119
120 /* only one swizzle group can be used */
121 if ((xyzw && rgba) || (xyzw && stpq) || (rgba && stpq))
122 return GL_FALSE;
123
124 return GL_TRUE;
125 }
126
127
128
129 /**
130 * Checks if a general swizzle is an l-value swizzle - these swizzles
131 * do not have duplicated fields. Returns GL_TRUE if this is a
132 * swizzle mask. Returns GL_FALSE otherwise
133 */
134 GLboolean
135 _slang_is_swizzle_mask(const slang_swizzle * swz, GLuint rows)
136 {
137 GLuint i, c = 0;
138
139 /* the swizzle may not be longer than the vector dim */
140 if (swz->num_components > rows)
141 return GL_FALSE;
142
143 /* the swizzle components cannot be duplicated */
144 for (i = 0; i < swz->num_components; i++) {
145 if ((c & (1 << swz->swizzle[i])) != 0)
146 return GL_FALSE;
147 c |= 1 << swz->swizzle[i];
148 }
149
150 return GL_TRUE;
151 }
152
153
154 GLvoid
155 slang_type_specifier_ctr(slang_type_specifier * self)
156 {
157 self->type = slang_spec_void;
158 self->_struct = NULL;
159 self->_array = NULL;
160 }
161
162 GLvoid
163 slang_type_specifier_dtr(slang_type_specifier * self)
164 {
165 if (self->_struct != NULL) {
166 slang_struct_destruct(self->_struct);
167 slang_alloc_free(self->_struct);
168 }
169 if (self->_array != NULL) {
170 slang_type_specifier_dtr(self->_array);
171 slang_alloc_free(self->_array);
172 }
173 }
174
175 GLboolean
176 slang_type_specifier_copy(slang_type_specifier * x,
177 const slang_type_specifier * y)
178 {
179 slang_type_specifier z;
180
181 slang_type_specifier_ctr(&z);
182 z.type = y->type;
183 if (z.type == slang_spec_struct) {
184 z._struct = (slang_struct *) slang_alloc_malloc(sizeof(slang_struct));
185 if (z._struct == NULL) {
186 slang_type_specifier_dtr(&z);
187 return GL_FALSE;
188 }
189 if (!slang_struct_construct(z._struct)) {
190 slang_alloc_free(z._struct);
191 slang_type_specifier_dtr(&z);
192 return GL_FALSE;
193 }
194 if (!slang_struct_copy(z._struct, y->_struct)) {
195 slang_type_specifier_dtr(&z);
196 return GL_FALSE;
197 }
198 }
199 else if (z.type == slang_spec_array) {
200 z._array =
201 (slang_type_specifier *)
202 slang_alloc_malloc(sizeof(slang_type_specifier));
203 if (z._array == NULL) {
204 slang_type_specifier_dtr(&z);
205 return GL_FALSE;
206 }
207 slang_type_specifier_ctr(z._array);
208 if (!slang_type_specifier_copy(z._array, y->_array)) {
209 slang_type_specifier_dtr(&z);
210 return GL_FALSE;
211 }
212 }
213 slang_type_specifier_dtr(x);
214 *x = z;
215 return GL_TRUE;
216 }
217
218 GLboolean
219 slang_type_specifier_equal(const slang_type_specifier * x,
220 const slang_type_specifier * y)
221 {
222 if (x->type != y->type)
223 return 0;
224 if (x->type == slang_spec_struct)
225 return slang_struct_equal(x->_struct, y->_struct);
226 if (x->type == slang_spec_array)
227 return slang_type_specifier_equal(x->_array, y->_array);
228 return 1;
229 }
230
231
232 GLboolean
233 slang_typeinfo_construct(slang_typeinfo * ti)
234 {
235 slang_type_specifier_ctr(&ti->spec);
236 ti->array_len = 0;
237 return GL_TRUE;
238 }
239
240 GLvoid
241 slang_typeinfo_destruct(slang_typeinfo * ti)
242 {
243 slang_type_specifier_dtr(&ti->spec);
244 }
245
246
247 /**
248 * Determine the return type of a function.
249 * \param name name of the function
250 * \param params array of function parameters
251 * \param num_params number of parameters
252 * \param space namespace to use
253 * \param spec returns the function's type
254 * \param atoms atom pool
255 * \return GL_TRUE for success, GL_FALSE if failure
256 */
257 static GLboolean
258 typeof_existing_function(const char *name, const slang_operation * params,
259 GLuint num_params,
260 const slang_name_space * space,
261 slang_type_specifier * spec,
262 slang_atom_pool * atoms)
263 {
264 slang_atom atom;
265 GLboolean exists;
266
267 atom = slang_atom_pool_atom(atoms, name);
268 if (!_slang_typeof_function(atom, params, num_params, space, spec,
269 &exists, atoms))
270 return GL_FALSE;
271 return exists;
272 }
273
274 GLboolean
275 _slang_typeof_operation(const slang_assemble_ctx * A,
276 const slang_operation * op,
277 slang_typeinfo * ti)
278 {
279 return _slang_typeof_operation_(op, &A->space, ti, A->atoms);
280 }
281
282
283 /**
284 * Determine the return type of an operation.
285 * \param op the operation node
286 * \param space the namespace to use
287 * \param ti the returned type
288 * \param atoms atom pool
289 * \return GL_TRUE for success, GL_FALSE if failure
290 */
291 GLboolean
292 _slang_typeof_operation_(const slang_operation * op,
293 const slang_name_space * space,
294 slang_typeinfo * ti,
295 slang_atom_pool * atoms)
296 {
297 ti->can_be_referenced = GL_FALSE;
298 ti->is_swizzled = GL_FALSE;
299
300 switch (op->type) {
301 case slang_oper_block_no_new_scope:
302 case slang_oper_block_new_scope:
303 case slang_oper_variable_decl:
304 case slang_oper_asm:
305 case slang_oper_break:
306 case slang_oper_continue:
307 case slang_oper_discard:
308 case slang_oper_return:
309 case slang_oper_if:
310 case slang_oper_while:
311 case slang_oper_do:
312 case slang_oper_for:
313 case slang_oper_void:
314 ti->spec.type = slang_spec_void;
315 break;
316 case slang_oper_expression:
317 case slang_oper_assign:
318 case slang_oper_addassign:
319 case slang_oper_subassign:
320 case slang_oper_mulassign:
321 case slang_oper_divassign:
322 case slang_oper_preincrement:
323 case slang_oper_predecrement:
324 if (!_slang_typeof_operation_(op->children, space, ti, atoms))
325 return GL_FALSE;
326 break;
327 case slang_oper_literal_bool:
328 case slang_oper_logicalor:
329 case slang_oper_logicalxor:
330 case slang_oper_logicaland:
331 case slang_oper_equal:
332 case slang_oper_notequal:
333 case slang_oper_less:
334 case slang_oper_greater:
335 case slang_oper_lessequal:
336 case slang_oper_greaterequal:
337 case slang_oper_not:
338 ti->spec.type = slang_spec_bool;
339 break;
340 case slang_oper_literal_int:
341 ti->spec.type = slang_spec_int;
342 break;
343 case slang_oper_literal_float:
344 ti->spec.type = slang_spec_float;
345 break;
346 case slang_oper_identifier:
347 {
348 slang_variable *var;
349 var = _slang_locate_variable(op->locals, op->a_id, GL_TRUE);
350 if (var == NULL)
351 RETURN_ERROR2("undefined variable", (char *) op->a_id, 0);
352 if (!slang_type_specifier_copy(&ti->spec, &var->type.specifier))
353 RETURN_OUT_OF_MEMORY();
354 ti->can_be_referenced = GL_TRUE;
355 ti->array_len = var->array_len;
356 }
357 break;
358 case slang_oper_sequence:
359 /* TODO: check [0] and [1] if they match */
360 if (!_slang_typeof_operation_(&op->children[1], space, ti, atoms))
361 RETURN_NIL();
362 ti->can_be_referenced = GL_FALSE;
363 ti->is_swizzled = GL_FALSE;
364 break;
365 /*case slang_oper_modassign: */
366 /*case slang_oper_lshassign: */
367 /*case slang_oper_rshassign: */
368 /*case slang_oper_orassign: */
369 /*case slang_oper_xorassign: */
370 /*case slang_oper_andassign: */
371 case slang_oper_select:
372 /* TODO: check [1] and [2] if they match */
373 if (!_slang_typeof_operation_(&op->children[1], space, ti, atoms))
374 RETURN_NIL();
375 ti->can_be_referenced = GL_FALSE;
376 ti->is_swizzled = GL_FALSE;
377 break;
378 /*case slang_oper_bitor: */
379 /*case slang_oper_bitxor: */
380 /*case slang_oper_bitand: */
381 /*case slang_oper_lshift: */
382 /*case slang_oper_rshift: */
383 case slang_oper_add:
384 if (!typeof_existing_function("+", op->children, 2, space,
385 &ti->spec, atoms))
386 RETURN_NIL();
387 break;
388 case slang_oper_subtract:
389 if (!typeof_existing_function("-", op->children, 2, space,
390 &ti->spec, atoms))
391 RETURN_NIL();
392 break;
393 case slang_oper_multiply:
394 if (!typeof_existing_function("*", op->children, 2, space,
395 &ti->spec, atoms))
396 RETURN_NIL();
397 break;
398 case slang_oper_divide:
399 if (!typeof_existing_function("/", op->children, 2, space,
400 &ti->spec, atoms))
401 RETURN_NIL();
402 break;
403 /*case slang_oper_modulus: */
404 case slang_oper_plus:
405 if (!_slang_typeof_operation_(op->children, space, ti, atoms))
406 RETURN_NIL();
407 ti->can_be_referenced = GL_FALSE;
408 ti->is_swizzled = GL_FALSE;
409 break;
410 case slang_oper_minus:
411 if (!typeof_existing_function("-", op->children, 1, space,
412 &ti->spec, atoms))
413 RETURN_NIL();
414 break;
415 /*case slang_oper_complement: */
416 case slang_oper_subscript:
417 {
418 slang_typeinfo _ti;
419
420 if (!slang_typeinfo_construct(&_ti))
421 RETURN_NIL();
422 if (!_slang_typeof_operation_(op->children, space, &_ti, atoms)) {
423 slang_typeinfo_destruct(&_ti);
424 RETURN_NIL();
425 }
426 ti->can_be_referenced = _ti.can_be_referenced;
427 if (_ti.spec.type == slang_spec_array) {
428 if (!slang_type_specifier_copy(&ti->spec, _ti.spec._array)) {
429 slang_typeinfo_destruct(&_ti);
430 RETURN_NIL();
431 }
432 }
433 else {
434 if (!_slang_type_is_vector(_ti.spec.type)
435 && !_slang_type_is_matrix(_ti.spec.type)) {
436 slang_typeinfo_destruct(&_ti);
437 RETURN_ERROR("cannot index a non-array type", 0);
438 }
439 ti->spec.type = _slang_type_base(_ti.spec.type);
440 }
441 slang_typeinfo_destruct(&_ti);
442 }
443 break;
444 case slang_oper_call:
445 {
446 GLboolean exists;
447
448 if (!_slang_typeof_function(op->a_id, op->children, op->num_children,
449 space, &ti->spec, &exists, atoms))
450 RETURN_NIL();
451 if (!exists) {
452 slang_struct *s =
453 slang_struct_scope_find(space->structs, op->a_id, GL_TRUE);
454 if (s != NULL) {
455 ti->spec.type = slang_spec_struct;
456 ti->spec._struct =
457 (slang_struct *) slang_alloc_malloc(sizeof(slang_struct));
458 if (ti->spec._struct == NULL)
459 RETURN_NIL();
460 if (!slang_struct_construct(ti->spec._struct)) {
461 slang_alloc_free(ti->spec._struct);
462 ti->spec._struct = NULL;
463 RETURN_NIL();
464 }
465 if (!slang_struct_copy(ti->spec._struct, s))
466 RETURN_NIL();
467 }
468 else {
469 const char *name;
470 slang_type_specifier_type type;
471
472 name = slang_atom_pool_id(atoms, op->a_id);
473 type = slang_type_specifier_type_from_string(name);
474 if (type == slang_spec_void)
475 RETURN_ERROR2("function not found", name, 0);
476 ti->spec.type = type;
477 }
478 }
479 }
480 break;
481 case slang_oper_field:
482 {
483 slang_typeinfo _ti;
484
485 if (!slang_typeinfo_construct(&_ti))
486 RETURN_NIL();
487 if (!_slang_typeof_operation_(op->children, space, &_ti, atoms)) {
488 slang_typeinfo_destruct(&_ti);
489 RETURN_NIL();
490 }
491 if (_ti.spec.type == slang_spec_struct) {
492 slang_variable *field;
493
494 field = _slang_locate_variable(_ti.spec._struct->fields, op->a_id,
495 GL_FALSE);
496 if (field == NULL) {
497 slang_typeinfo_destruct(&_ti);
498 RETURN_NIL();
499 }
500 if (!slang_type_specifier_copy(&ti->spec, &field->type.specifier)) {
501 slang_typeinfo_destruct(&_ti);
502 RETURN_NIL();
503 }
504 ti->can_be_referenced = _ti.can_be_referenced;
505 }
506 else {
507 GLuint rows;
508 const char *swizzle;
509 slang_type_specifier_type base;
510
511 /* determine the swizzle of the field expression */
512 #if 000
513 if (!_slang_type_is_vector(_ti.spec.type)) {
514 slang_typeinfo_destruct(&_ti);
515 RETURN_ERROR("Can't swizzle scalar expression", 0);
516 }
517 #endif
518 rows = _slang_type_dim(_ti.spec.type);
519 swizzle = slang_atom_pool_id(atoms, op->a_id);
520 if (!_slang_is_swizzle(swizzle, rows, &ti->swz)) {
521 slang_typeinfo_destruct(&_ti);
522 RETURN_ERROR("Bad swizzle", 0);
523 }
524 ti->is_swizzled = GL_TRUE;
525 ti->can_be_referenced = _ti.can_be_referenced
526 && _slang_is_swizzle_mask(&ti->swz, rows);
527 if (_ti.is_swizzled) {
528 slang_swizzle swz;
529
530 /* swizzle the swizzle */
531 _slang_multiply_swizzles(&swz, &_ti.swz, &ti->swz);
532 ti->swz = swz;
533 }
534 base = _slang_type_base(_ti.spec.type);
535 switch (ti->swz.num_components) {
536 case 1:
537 ti->spec.type = base;
538 break;
539 case 2:
540 switch (base) {
541 case slang_spec_float:
542 ti->spec.type = slang_spec_vec2;
543 break;
544 case slang_spec_int:
545 ti->spec.type = slang_spec_ivec2;
546 break;
547 case slang_spec_bool:
548 ti->spec.type = slang_spec_bvec2;
549 break;
550 default:
551 break;
552 }
553 break;
554 case 3:
555 switch (base) {
556 case slang_spec_float:
557 ti->spec.type = slang_spec_vec3;
558 break;
559 case slang_spec_int:
560 ti->spec.type = slang_spec_ivec3;
561 break;
562 case slang_spec_bool:
563 ti->spec.type = slang_spec_bvec3;
564 break;
565 default:
566 break;
567 }
568 break;
569 case 4:
570 switch (base) {
571 case slang_spec_float:
572 ti->spec.type = slang_spec_vec4;
573 break;
574 case slang_spec_int:
575 ti->spec.type = slang_spec_ivec4;
576 break;
577 case slang_spec_bool:
578 ti->spec.type = slang_spec_bvec4;
579 break;
580 default:
581 break;
582 }
583 break;
584 default:
585 break;
586 }
587 }
588 slang_typeinfo_destruct(&_ti);
589 }
590 break;
591 case slang_oper_postincrement:
592 case slang_oper_postdecrement:
593 if (!_slang_typeof_operation_(op->children, space, ti, atoms))
594 RETURN_NIL();
595 ti->can_be_referenced = GL_FALSE;
596 ti->is_swizzled = GL_FALSE;
597 break;
598 default:
599 RETURN_NIL();
600 }
601
602 return GL_TRUE;
603 }
604
605
606
607 /**
608 * Determine the return type of a function.
609 * \param a_name the function name
610 * \param param function parameters (overloading)
611 * \param num_params number of parameters to function
612 * \param space namespace to search
613 * \param exists returns GL_TRUE or GL_FALSE to indicate existance of function
614 * \return GL_TRUE for success, GL_FALSE if failure (bad function name)
615 */
616 GLboolean
617 _slang_typeof_function(slang_atom a_name, const slang_operation * params,
618 GLuint num_params,
619 const slang_name_space * space,
620 slang_type_specifier * spec, GLboolean * exists,
621 slang_atom_pool * atoms)
622 {
623 slang_function *fun = _slang_locate_function(space->funcs, a_name, params,
624 num_params, space, atoms);
625 *exists = fun != NULL;
626 if (!fun)
627 return GL_TRUE; /* yes, not false */
628 return slang_type_specifier_copy(spec, &fun->header.type.specifier);
629 }
630
631
632
633 /**
634 * Determine if a type is a matrix.
635 * \return GL_TRUE if is a matrix, GL_FALSE otherwise.
636 */
637 GLboolean
638 _slang_type_is_matrix(slang_type_specifier_type ty)
639 {
640 switch (ty) {
641 case slang_spec_mat2:
642 case slang_spec_mat3:
643 case slang_spec_mat4:
644 return GL_TRUE;
645 default:
646 return GL_FALSE;
647 }
648 }
649
650
651 /**
652 * Determine if a type is a vector.
653 * \return GL_TRUE if is a vector, GL_FALSE otherwise.
654 */
655 GLboolean
656 _slang_type_is_vector(slang_type_specifier_type ty)
657 {
658 switch (ty) {
659 case slang_spec_vec2:
660 case slang_spec_vec3:
661 case slang_spec_vec4:
662 case slang_spec_ivec2:
663 case slang_spec_ivec3:
664 case slang_spec_ivec4:
665 case slang_spec_bvec2:
666 case slang_spec_bvec3:
667 case slang_spec_bvec4:
668 return GL_TRUE;
669 default:
670 return GL_FALSE;
671 }
672 }
673
674
675 /**
676 * Given a vector type, return the type of the vector's elements
677 */
678 slang_type_specifier_type
679 _slang_type_base(slang_type_specifier_type ty)
680 {
681 switch (ty) {
682 case slang_spec_float:
683 case slang_spec_vec2:
684 case slang_spec_vec3:
685 case slang_spec_vec4:
686 return slang_spec_float;
687 case slang_spec_int:
688 case slang_spec_ivec2:
689 case slang_spec_ivec3:
690 case slang_spec_ivec4:
691 return slang_spec_int;
692 case slang_spec_bool:
693 case slang_spec_bvec2:
694 case slang_spec_bvec3:
695 case slang_spec_bvec4:
696 return slang_spec_bool;
697 case slang_spec_mat2:
698 return slang_spec_vec2;
699 case slang_spec_mat3:
700 return slang_spec_vec3;
701 case slang_spec_mat4:
702 return slang_spec_vec4;
703 default:
704 return slang_spec_void;
705 }
706 }
707
708
709 /**
710 * Return the dimensionality of a vector or matrix type.
711 */
712 GLuint
713 _slang_type_dim(slang_type_specifier_type ty)
714 {
715 switch (ty) {
716 case slang_spec_float:
717 case slang_spec_int:
718 case slang_spec_bool:
719 return 1;
720 case slang_spec_vec2:
721 case slang_spec_ivec2:
722 case slang_spec_bvec2:
723 case slang_spec_mat2:
724 return 2;
725 case slang_spec_vec3:
726 case slang_spec_ivec3:
727 case slang_spec_bvec3:
728 case slang_spec_mat3:
729 return 3;
730 case slang_spec_vec4:
731 case slang_spec_ivec4:
732 case slang_spec_bvec4:
733 case slang_spec_mat4:
734 return 4;
735 default:
736 return 0;
737 }
738 }