2 * Mesa 3-D graphics library
5 * Copyright (C) 2005-2006 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
26 * \file slang_assemble.c
27 * slang intermediate code assembler
32 #include "slang_assemble.h"
33 #include "slang_compile.h"
34 #include "slang_storage.h"
39 slang_assembly_construct(slang_assembly
* assem
)
41 assem
->type
= slang_asm_none
;
46 slang_assembly_destruct(slang_assembly
* assem
)
55 _slang_assembly_file_ctr(slang_assembly_file
* self
)
63 slang_assembly_file_destruct(slang_assembly_file
* file
)
67 for (i
= 0; i
< file
->count
; i
++)
68 slang_assembly_destruct(&file
->code
[i
]);
69 slang_alloc_free(file
->code
);
73 push_new(slang_assembly_file
* file
)
75 if (file
->count
== file
->capacity
) {
78 if (file
->capacity
== 0)
81 n
= file
->capacity
* 2;
82 file
->code
= (slang_assembly
*)
83 slang_alloc_realloc(file
->code
,
84 file
->capacity
* sizeof(slang_assembly
),
85 n
* sizeof(slang_assembly
));
86 if (file
->code
== NULL
)
90 if (!slang_assembly_construct(&file
->code
[file
->count
]))
97 push_gen(slang_assembly_file
* file
, slang_assembly_type type
,
98 GLfloat literal
, GLuint label
, GLuint size
)
100 slang_assembly
*assem
;
104 assem
= &file
->code
[file
->count
- 1];
106 assem
->literal
= literal
;
107 assem
->param
[0] = label
;
108 assem
->param
[1] = size
;
113 slang_assembly_file_push(slang_assembly_file
* file
, slang_assembly_type type
)
115 return push_gen(file
, type
, (GLfloat
) 0, 0, 0);
119 slang_assembly_file_push_label(slang_assembly_file
* file
,
120 slang_assembly_type type
, GLuint label
)
122 return push_gen(file
, type
, (GLfloat
) 0, label
, 0);
126 slang_assembly_file_push_label2(slang_assembly_file
* file
,
127 slang_assembly_type type
, GLuint label1
,
130 return push_gen(file
, type
, (GLfloat
) 0, label1
, label2
);
134 slang_assembly_file_push_literal(slang_assembly_file
* file
,
135 slang_assembly_type type
, GLfloat literal
)
137 return push_gen(file
, type
, literal
, 0, 0);
140 #define PUSH slang_assembly_file_push
141 #define PLAB slang_assembly_file_push_label
142 #define PLAB2 slang_assembly_file_push_label2
143 #define PLIT slang_assembly_file_push_literal
145 /* slang_assembly_file_restore_point */
148 slang_assembly_file_restore_point_save(slang_assembly_file
* file
,
149 slang_assembly_file_restore_point
*
152 point
->count
= file
->count
;
157 slang_assembly_file_restore_point_load(slang_assembly_file
* file
,
158 slang_assembly_file_restore_point
*
163 for (i
= point
->count
; i
< file
->count
; i
++)
164 slang_assembly_destruct(&file
->code
[i
]);
165 file
->count
= point
->count
;
169 /* utility functions */
172 sizeof_variable(slang_assemble_ctx
* A
, slang_type_specifier
* spec
,
173 slang_type_qualifier qual
, GLuint array_len
, GLuint
* size
)
175 slang_storage_aggregate agg
;
177 /* calculate the size of the variable's aggregate */
178 if (!slang_storage_aggregate_construct(&agg
))
180 if (!_slang_aggregate_variable
181 (&agg
, spec
, array_len
, A
->space
.funcs
, A
->space
.structs
,
182 A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
)) {
183 slang_storage_aggregate_destruct(&agg
);
186 *size
+= _slang_sizeof_aggregate(&agg
);
187 slang_storage_aggregate_destruct(&agg
);
189 /* for reference variables consider the additional address overhead */
190 if (qual
== slang_qual_out
|| qual
== slang_qual_inout
)
197 sizeof_variable2(slang_assemble_ctx
* A
, slang_variable
* var
, GLuint
* size
)
199 var
->address
= *size
;
200 if (var
->type
.qualifier
== slang_qual_out
201 || var
->type
.qualifier
== slang_qual_inout
)
203 return sizeof_variable(A
, &var
->type
.specifier
, var
->type
.qualifier
,
204 var
->array_len
, size
);
208 sizeof_variables(slang_assemble_ctx
* A
, slang_variable_scope
* vars
,
209 GLuint start
, GLuint stop
, GLuint
* size
)
213 for (i
= start
; i
< stop
; i
++)
214 if (!sizeof_variable2(A
, &vars
->variables
[i
], size
))
220 collect_locals(slang_assemble_ctx
* A
, slang_operation
* op
, GLuint
* size
)
224 if (!sizeof_variables(A
, op
->locals
, 0, op
->locals
->num_variables
, size
))
226 for (i
= 0; i
< op
->num_children
; i
++)
227 if (!collect_locals(A
, &op
->children
[i
], size
))
232 /* _slang_locate_function() */
235 _slang_locate_function(const slang_function_scope
* funcs
, slang_atom a_name
,
236 const slang_operation
* params
, GLuint num_params
,
237 const slang_assembly_name_space
* space
,
238 slang_atom_pool
* atoms
)
242 for (i
= 0; i
< funcs
->num_functions
; i
++) {
244 slang_function
*f
= &funcs
->functions
[i
];
246 if (a_name
!= f
->header
.a_name
)
248 if (f
->param_count
!= num_params
)
250 for (j
= 0; j
< num_params
; j
++) {
251 slang_assembly_typeinfo ti
;
253 if (!slang_assembly_typeinfo_construct(&ti
))
255 if (!_slang_typeof_operation_(¶ms
[j
], space
, &ti
, atoms
)) {
256 slang_assembly_typeinfo_destruct(&ti
);
259 if (!slang_type_specifier_equal
260 (&ti
.spec
, &f
->parameters
->variables
[j
].type
.specifier
)) {
261 slang_assembly_typeinfo_destruct(&ti
);
264 slang_assembly_typeinfo_destruct(&ti
);
266 /* "out" and "inout" formal parameter requires the actual parameter to be l-value */
267 if (!ti
.can_be_referenced
&&
268 (f
->parameters
->variables
[j
].type
.qualifier
== slang_qual_out
||
269 f
->parameters
->variables
[j
].type
.qualifier
== slang_qual_inout
))
275 if (funcs
->outer_scope
!= NULL
)
276 return _slang_locate_function(funcs
->outer_scope
, a_name
, params
,
277 num_params
, space
, atoms
);
281 /* _slang_assemble_function() */
284 _slang_assemble_function(slang_assemble_ctx
* A
, slang_function
* fun
)
286 GLuint param_size
, local_size
;
287 GLuint skip
, cleanup
;
289 fun
->address
= A
->file
->count
;
291 if (fun
->body
== NULL
) {
292 /* jump to the actual function body - we do not know it, so add
293 * the instruction to fixup table
295 if (!slang_fixup_save(&fun
->fixups
, fun
->address
))
297 if (!PUSH(A
->file
, slang_asm_jump
))
302 /* resolve all fixup table entries and delete it */
304 for (i
= 0; i
< fun
->fixups
.count
; i
++)
305 A
->file
->code
[fun
->fixups
.table
[i
]].param
[0] = fun
->address
;
306 slang_fixup_table_free(&fun
->fixups
);
309 /* At this point traverse function formal parameters and code to calculate
310 * total memory size to be allocated on the stack.
311 * During this process the variables will be assigned local addresses to
312 * reference them in the code.
313 * No storage optimizations are performed so exclusive scopes are not
314 * detected and shared.
317 /* calculate return value size */
319 if (fun
->header
.type
.specifier
.type
!= slang_spec_void
)
321 (A
, &fun
->header
.type
.specifier
, slang_qual_none
, 0, ¶m_size
))
323 A
->local
.ret_size
= param_size
;
325 /* calculate formal parameter list size */
326 if (!sizeof_variables
327 (A
, fun
->parameters
, 0, fun
->param_count
, ¶m_size
))
330 /* calculate local variables size - take into account the four-byte
331 * return address and temporaries for various tasks (4 for addr and
332 * 16 for swizzle temporaries). these include variables from the
333 * formal parameter scope and from the code
335 A
->local
.addr_tmp
= param_size
+ 4;
336 A
->local
.swizzle_tmp
= param_size
+ 4 + 4;
337 local_size
= param_size
+ 4 + 4 + 16;
338 if (!sizeof_variables
339 (A
, fun
->parameters
, fun
->param_count
, fun
->parameters
->num_variables
,
342 if (!collect_locals(A
, fun
->body
, &local_size
))
345 /* allocate local variable storage */
346 if (!PLAB(A
->file
, slang_asm_local_alloc
, local_size
- param_size
- 4))
349 /* mark a new frame for function variable storage */
350 if (!PLAB(A
->file
, slang_asm_enter
, local_size
))
353 /* jump directly to the actual code */
354 skip
= A
->file
->count
;
355 if (!push_new(A
->file
))
357 A
->file
->code
[skip
].type
= slang_asm_jump
;
359 /* all "return" statements will be directed here */
360 A
->flow
.function_end
= A
->file
->count
;
361 cleanup
= A
->file
->count
;
362 if (!push_new(A
->file
))
364 A
->file
->code
[cleanup
].type
= slang_asm_jump
;
366 /* execute the function body */
367 A
->file
->code
[skip
].param
[0] = A
->file
->count
;
368 if (!_slang_assemble_operation
369 (A
, fun
->body
, /*slang_ref_freelance */ slang_ref_forbid
))
372 /* this is the end of the function - restore the old function frame */
373 A
->file
->code
[cleanup
].param
[0] = A
->file
->count
;
374 if (!PUSH(A
->file
, slang_asm_leave
))
377 /* free local variable storage */
378 if (!PLAB(A
->file
, slang_asm_local_free
, local_size
- param_size
- 4))
381 /* return from the function */
382 if (!PUSH(A
->file
, slang_asm_return
))
389 _slang_cleanup_stack(slang_assemble_ctx
* A
, slang_operation
* op
)
391 slang_assembly_typeinfo ti
;
394 /* get type info of the operation and calculate its size */
395 if (!slang_assembly_typeinfo_construct(&ti
))
397 if (!_slang_typeof_operation(A
, op
, &ti
)) {
398 slang_assembly_typeinfo_destruct(&ti
);
401 if (ti
.spec
.type
!= slang_spec_void
) {
402 if (A
->ref
== slang_ref_force
) {
405 else if (!sizeof_variable(A
, &ti
.spec
, slang_qual_none
, 0, &size
)) {
406 slang_assembly_typeinfo_destruct(&ti
);
410 slang_assembly_typeinfo_destruct(&ti
);
412 /* if nonzero, free it from the stack */
414 if (!PLAB(A
->file
, slang_asm_local_free
, size
))
421 /* _slang_assemble_operation() */
424 dereference_basic(slang_assemble_ctx
* A
, slang_storage_type type
,
425 GLuint
* size
, slang_swizzle
* swz
, GLboolean is_swizzled
)
428 slang_assembly_type ty
;
430 *size
-= _slang_sizeof_type(type
);
432 /* If swizzling is taking place, we are forced to use scalar
433 * operations, even if we have vec4 instructions enabled (this
434 * should be actually done with special vec4 shuffle instructions).
435 * Adjust the size and calculate the offset within source variable
439 src_offset
= swz
->swizzle
[*size
/ 4] * 4;
443 /* dereference data slot of a basic type */
444 if (!PLAB2(A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
446 if (!PUSH(A
->file
, slang_asm_addr_deref
))
448 if (src_offset
!= 0) {
449 if (!PLAB(A
->file
, slang_asm_addr_push
, src_offset
))
451 if (!PUSH(A
->file
, slang_asm_addr_add
))
456 case slang_stor_bool
:
457 ty
= slang_asm_bool_deref
;
460 ty
= slang_asm_int_deref
;
462 case slang_stor_float
:
463 ty
= slang_asm_float_deref
;
465 #if defined(USE_X86_ASM) || defined(SLANG_X86)
466 case slang_stor_vec4
:
467 ty
= slang_asm_vec4_deref
;
471 _mesa_problem(NULL
, "Unexpected arr->type in dereference_basic");
475 return PUSH(A
->file
, ty
);
479 dereference_aggregate(slang_assemble_ctx
* A
,
480 const slang_storage_aggregate
* agg
, GLuint
* size
,
481 slang_swizzle
* swz
, GLboolean is_swizzled
)
485 for (i
= agg
->count
; i
> 0; i
--) {
486 const slang_storage_array
*arr
= &agg
->arrays
[i
- 1];
489 for (j
= arr
->length
; j
> 0; j
--) {
490 if (arr
->type
== slang_stor_aggregate
) {
491 if (!dereference_aggregate
492 (A
, arr
->aggregate
, size
, swz
, is_swizzled
))
496 if (is_swizzled
&& arr
->type
== slang_stor_vec4
) {
497 if (!dereference_basic
498 (A
, slang_stor_float
, size
, swz
, is_swizzled
))
500 if (!dereference_basic
501 (A
, slang_stor_float
, size
, swz
, is_swizzled
))
503 if (!dereference_basic
504 (A
, slang_stor_float
, size
, swz
, is_swizzled
))
506 if (!dereference_basic
507 (A
, slang_stor_float
, size
, swz
, is_swizzled
))
511 if (!dereference_basic(A
, arr
->type
, size
, swz
, is_swizzled
))
522 _slang_dereference(slang_assemble_ctx
* A
, slang_operation
* op
)
524 slang_assembly_typeinfo ti
;
525 GLboolean result
= GL_FALSE
;
526 slang_storage_aggregate agg
;
529 /* get type information of the given operation */
530 if (!slang_assembly_typeinfo_construct(&ti
))
532 if (!_slang_typeof_operation(A
, op
, &ti
))
535 /* construct aggregate from the type info */
536 if (!slang_storage_aggregate_construct(&agg
))
538 if (!_slang_aggregate_variable
539 (&agg
, &ti
.spec
, ti
.array_len
, A
->space
.funcs
, A
->space
.structs
,
540 A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
))
543 /* dereference the resulting aggregate */
544 size
= _slang_sizeof_aggregate(&agg
);
545 result
= dereference_aggregate(A
, &agg
, &size
, &ti
.swz
, ti
.is_swizzled
);
548 slang_storage_aggregate_destruct(&agg
);
550 slang_assembly_typeinfo_destruct(&ti
);
555 _slang_assemble_function_call(slang_assemble_ctx
* A
, slang_function
* fun
,
556 slang_operation
* params
, GLuint param_count
,
557 GLboolean assignment
)
560 slang_swizzle p_swz
[64];
561 slang_ref_type p_ref
[64];
563 /* TODO: fix this, allocate dynamically */
564 if (param_count
> 64)
567 /* make room for the return value, if any */
568 if (fun
->header
.type
.specifier
.type
!= slang_spec_void
) {
572 (A
, &fun
->header
.type
.specifier
, slang_qual_none
, 0, &ret_size
))
574 if (!PLAB(A
->file
, slang_asm_local_alloc
, ret_size
))
578 /* push the actual parameters on the stack */
579 for (i
= 0; i
< param_count
; i
++) {
580 if (fun
->parameters
->variables
[i
].type
.qualifier
== slang_qual_inout
||
581 fun
->parameters
->variables
[i
].type
.qualifier
== slang_qual_out
) {
582 if (!PLAB2(A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
584 /* TODO: optimize the "out" parameter case */
585 if (!_slang_assemble_operation(A
, ¶ms
[i
], slang_ref_force
))
589 if (!PUSH(A
->file
, slang_asm_addr_copy
))
591 if (!PUSH(A
->file
, slang_asm_addr_deref
))
593 if (i
== 0 && assignment
) {
594 /* duplicate the resulting address */
595 if (!PLAB2(A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
597 if (!PUSH(A
->file
, slang_asm_addr_deref
))
600 if (!_slang_dereference(A
, ¶ms
[i
]))
604 if (!_slang_assemble_operation(A
, ¶ms
[i
], slang_ref_forbid
))
611 /* call the function */
612 if (!PLAB(A
->file
, slang_asm_call
, fun
->address
))
615 /* pop the parameters from the stack */
616 for (i
= param_count
; i
> 0; i
--) {
621 if (fun
->parameters
->variables
[j
].type
.qualifier
== slang_qual_inout
||
622 fun
->parameters
->variables
[j
].type
.qualifier
== slang_qual_out
) {
623 /* for output parameter copy the contents of the formal parameter
624 * back to the original actual parameter
626 if (!_slang_assemble_assignment(A
, ¶ms
[j
]))
628 /* pop the actual parameter's address */
629 if (!PLAB(A
->file
, slang_asm_local_free
, 4))
633 /* pop the value of the parameter */
634 if (!_slang_cleanup_stack(A
, ¶ms
[j
]))
643 _slang_assemble_function_call_name(slang_assemble_ctx
* A
, const char *name
,
644 slang_operation
* params
,
645 GLuint param_count
, GLboolean assignment
)
650 atom
= slang_atom_pool_atom(A
->atoms
, name
);
651 if (atom
== SLANG_ATOM_NULL
)
654 _slang_locate_function(A
->space
.funcs
, atom
, params
, param_count
,
655 &A
->space
, A
->atoms
);
658 return _slang_assemble_function_call(A
, fun
, params
, param_count
,
663 assemble_function_call_name_dummyint(slang_assemble_ctx
* A
, const char *name
,
664 slang_operation
* params
)
666 slang_operation p
[2];
670 if (!slang_operation_construct(&p
[1]))
672 p
[1].type
= slang_oper_literal_int
;
673 result
= _slang_assemble_function_call_name(A
, name
, p
, 2, GL_FALSE
);
674 slang_operation_destruct(&p
[1]);
681 slang_assembly_type code1
, code2
;
684 {"float_add", slang_asm_float_add
, slang_asm_float_copy
},
685 {"float_multiply", slang_asm_float_multiply
, slang_asm_float_copy
},
686 {"float_divide", slang_asm_float_divide
, slang_asm_float_copy
},
687 {"float_negate", slang_asm_float_negate
, slang_asm_float_copy
},
688 {"float_less", slang_asm_float_less
, slang_asm_bool_copy
},
689 {"float_equal", slang_asm_float_equal_exp
, slang_asm_bool_copy
},
690 {"float_to_int", slang_asm_float_to_int
, slang_asm_int_copy
},
691 {"float_sine", slang_asm_float_sine
, slang_asm_float_copy
},
692 {"float_arcsine", slang_asm_float_arcsine
, slang_asm_float_copy
},
693 {"float_arctan", slang_asm_float_arctan
, slang_asm_float_copy
},
694 {"float_power", slang_asm_float_power
, slang_asm_float_copy
},
695 {"float_log2", slang_asm_float_log2
, slang_asm_float_copy
},
696 {"float_floor", slang_asm_float_floor
, slang_asm_float_copy
},
697 {"float_ceil", slang_asm_float_ceil
, slang_asm_float_copy
},
698 {"float_noise1", slang_asm_float_noise1
, slang_asm_float_copy
},
699 {"float_noise2", slang_asm_float_noise2
, slang_asm_float_copy
},
700 {"float_noise3", slang_asm_float_noise3
, slang_asm_float_copy
},
701 {"float_noise4", slang_asm_float_noise4
, slang_asm_float_copy
},
702 {"int_to_float", slang_asm_int_to_float
, slang_asm_float_copy
},
703 {"vec4_tex1d", slang_asm_vec4_tex1d
, slang_asm_none
},
704 {"vec4_tex2d", slang_asm_vec4_tex2d
, slang_asm_none
},
705 {"vec4_tex3d", slang_asm_vec4_tex3d
, slang_asm_none
},
706 {"vec4_texcube", slang_asm_vec4_texcube
, slang_asm_none
},
707 {"vec4_shad1d", slang_asm_vec4_shad1d
, slang_asm_none
},
708 {"vec4_shad2d", slang_asm_vec4_shad2d
, slang_asm_none
},
709 /* GL_MESA_shader_debug */
710 {"float_print", slang_asm_float_deref
, slang_asm_float_print
},
711 {"int_print", slang_asm_int_deref
, slang_asm_int_print
},
712 {"bool_print", slang_asm_bool_deref
, slang_asm_bool_print
},
714 {"float_to_vec4", slang_asm_float_to_vec4
, slang_asm_none
},
715 {"vec4_add", slang_asm_vec4_add
, slang_asm_none
},
716 {"vec4_subtract", slang_asm_vec4_subtract
, slang_asm_none
},
717 {"vec4_multiply", slang_asm_vec4_multiply
, slang_asm_none
},
718 {"vec4_divide", slang_asm_vec4_divide
, slang_asm_none
},
719 {"vec4_negate", slang_asm_vec4_negate
, slang_asm_none
},
720 {"vec4_dot", slang_asm_vec4_dot
, slang_asm_none
},
721 {NULL
, slang_asm_none
, slang_asm_none
}
725 call_asm_instruction(slang_assemble_ctx
* A
, slang_atom a_name
)
730 id
= slang_atom_pool_id(A
->atoms
, a_name
);
732 for (i
= 0; inst
[i
].name
!= NULL
; i
++)
733 if (slang_string_compare(id
, inst
[i
].name
) == 0)
735 if (inst
[i
].name
== NULL
)
738 if (!PLAB2(A
->file
, inst
[i
].code1
, 4, 0))
740 if (inst
[i
].code2
!= slang_asm_none
)
741 if (!PLAB2(A
->file
, inst
[i
].code2
, 4, 0))
744 /* clean-up the stack from the remaining dst address */
745 if (!PLAB(A
->file
, slang_asm_local_free
, 4))
752 equality_aggregate(slang_assemble_ctx
* A
,
753 const slang_storage_aggregate
* agg
, GLuint
* index
,
754 GLuint size
, GLuint z_label
)
758 for (i
= 0; i
< agg
->count
; i
++) {
759 const slang_storage_array
*arr
= &agg
->arrays
[i
];
762 for (j
= 0; j
< arr
->length
; j
++) {
763 if (arr
->type
== slang_stor_aggregate
) {
764 if (!equality_aggregate(A
, arr
->aggregate
, index
, size
, z_label
))
768 #if defined(USE_X86_ASM) || defined(SLANG_X86)
769 if (arr
->type
== slang_stor_vec4
) {
771 (A
->file
, slang_asm_vec4_equal_int
, size
+ *index
, *index
))
777 (A
->file
, slang_asm_float_equal_int
, size
+ *index
,
781 *index
+= _slang_sizeof_type(arr
->type
);
782 if (!PLAB(A
->file
, slang_asm_jump_if_zero
, z_label
))
792 equality(slang_assemble_ctx
* A
, slang_operation
* op
, GLboolean equal
)
794 slang_assembly_typeinfo ti
;
795 GLboolean result
= GL_FALSE
;
796 slang_storage_aggregate agg
;
798 GLuint skip_jump
, true_label
, true_jump
, false_label
, false_jump
;
800 /* get type of operation */
801 if (!slang_assembly_typeinfo_construct(&ti
))
803 if (!_slang_typeof_operation(A
, op
, &ti
))
806 /* convert it to an aggregate */
807 if (!slang_storage_aggregate_construct(&agg
))
809 if (!_slang_aggregate_variable
810 (&agg
, &ti
.spec
, 0, A
->space
.funcs
, A
->space
.structs
, A
->space
.vars
,
811 A
->mach
, A
->file
, A
->atoms
))
814 /* compute the size of the agregate - there are two such aggregates on the stack */
815 size
= _slang_sizeof_aggregate(&agg
);
817 /* jump to the actual data-comparison code */
818 skip_jump
= A
->file
->count
;
819 if (!PUSH(A
->file
, slang_asm_jump
))
822 /* pop off the stack the compared data and push 1 */
823 true_label
= A
->file
->count
;
824 if (!PLAB(A
->file
, slang_asm_local_free
, size
* 2))
826 if (!PLIT(A
->file
, slang_asm_bool_push
, (GLfloat
) 1))
828 true_jump
= A
->file
->count
;
829 if (!PUSH(A
->file
, slang_asm_jump
))
832 false_label
= A
->file
->count
;
833 if (!PLAB(A
->file
, slang_asm_local_free
, size
* 2))
835 if (!PLIT(A
->file
, slang_asm_bool_push
, (GLfloat
) 0))
837 false_jump
= A
->file
->count
;
838 if (!PUSH(A
->file
, slang_asm_jump
))
841 A
->file
->code
[skip_jump
].param
[0] = A
->file
->count
;
843 /* compare the data on stack, it will eventually jump either to true or false label */
845 if (!equality_aggregate
846 (A
, &agg
, &index
, size
, equal
? false_label
: true_label
))
848 if (!PLAB(A
->file
, slang_asm_jump
, equal
? true_label
: false_label
))
851 A
->file
->code
[true_jump
].param
[0] = A
->file
->count
;
852 A
->file
->code
[false_jump
].param
[0] = A
->file
->count
;
856 slang_storage_aggregate_destruct(&agg
);
858 slang_assembly_typeinfo_destruct(&ti
);
863 handle_subscript(slang_assemble_ctx
* A
, slang_assembly_typeinfo
* tie
,
864 slang_assembly_typeinfo
* tia
, slang_operation
* op
,
867 GLuint asize
= 0, esize
= 0;
869 /* get type info of the master expression (matrix, vector or an array */
870 if (!_slang_typeof_operation(A
, &op
->children
[0], tia
))
873 (A
, &tia
->spec
, slang_qual_none
, tia
->array_len
, &asize
))
876 /* get type info of the result (matrix column, vector row or array element) */
877 if (!_slang_typeof_operation(A
, op
, tie
))
879 if (!sizeof_variable(A
, &tie
->spec
, slang_qual_none
, 0, &esize
))
882 /* assemble the master expression */
883 if (!_slang_assemble_operation(A
, &op
->children
[0], ref
))
886 /* when indexing an l-value swizzle, push the swizzle_tmp */
887 if (ref
== slang_ref_force
&& tia
->is_swizzled
)
888 if (!PLAB2(A
->file
, slang_asm_local_addr
, A
->local
.swizzle_tmp
, 16))
891 /* assemble the subscript expression */
892 if (!_slang_assemble_operation(A
, &op
->children
[1], slang_ref_forbid
))
895 if (ref
== slang_ref_force
&& tia
->is_swizzled
) {
898 /* copy the swizzle indexes to the swizzle_tmp */
899 for (i
= 0; i
< tia
->swz
.num_components
; i
++) {
900 if (!PLAB2(A
->file
, slang_asm_local_addr
, A
->local
.swizzle_tmp
, 16))
902 if (!PLAB(A
->file
, slang_asm_addr_push
, i
* 4))
904 if (!PUSH(A
->file
, slang_asm_addr_add
))
906 if (!PLAB(A
->file
, slang_asm_addr_push
, tia
->swz
.swizzle
[i
]))
908 if (!PUSH(A
->file
, slang_asm_addr_copy
))
910 if (!PLAB(A
->file
, slang_asm_local_free
, 4))
914 /* offset the pushed swizzle_tmp address and dereference it */
915 if (!PUSH(A
->file
, slang_asm_int_to_addr
))
917 if (!PLAB(A
->file
, slang_asm_addr_push
, 4))
919 if (!PUSH(A
->file
, slang_asm_addr_multiply
))
921 if (!PUSH(A
->file
, slang_asm_addr_add
))
923 if (!PUSH(A
->file
, slang_asm_addr_deref
))
927 /* convert the integer subscript to a relative address */
928 if (!PUSH(A
->file
, slang_asm_int_to_addr
))
932 if (!PLAB(A
->file
, slang_asm_addr_push
, esize
))
934 if (!PUSH(A
->file
, slang_asm_addr_multiply
))
937 if (ref
== slang_ref_force
) {
938 /* offset the base address with the relative address */
939 if (!PUSH(A
->file
, slang_asm_addr_add
))
945 /* move the selected element to the beginning of the master expression */
946 for (i
= 0; i
< esize
; i
+= 4)
948 (A
->file
, slang_asm_float_move
, asize
- esize
+ i
+ 4, i
+ 4))
950 if (!PLAB(A
->file
, slang_asm_local_free
, 4))
953 /* free the rest of the master expression */
954 if (!PLAB(A
->file
, slang_asm_local_free
, asize
- esize
))
962 handle_field(slang_assemble_ctx
* A
, slang_assembly_typeinfo
* tia
,
963 slang_assembly_typeinfo
* tib
, slang_operation
* op
,
966 /* get type info of the result (field or swizzle) */
967 if (!_slang_typeof_operation(A
, op
, tia
))
970 /* get type info of the master expression being accessed (struct or vector) */
971 if (!_slang_typeof_operation(A
, &op
->children
[0], tib
))
974 /* if swizzling a vector in-place, the swizzle temporary is needed */
975 if (ref
== slang_ref_forbid
&& tia
->is_swizzled
)
976 if (!PLAB2(A
->file
, slang_asm_local_addr
, A
->local
.swizzle_tmp
, 16))
979 /* assemble the master expression */
980 if (!_slang_assemble_operation(A
, &op
->children
[0], ref
))
983 /* assemble the field expression */
984 if (tia
->is_swizzled
) {
985 if (ref
== slang_ref_force
) {
987 if (tia
->swz
.num_components
== 1) {
988 /* simple case - adjust the vector's address to point to
989 * the selected component
991 if (!PLAB(file
, slang_asm_addr_push
, tia
->swz
.swizzle
[0] * 4))
993 if (!PUSH(file
, slang_asm_addr_add
))
999 /* two or more vector components are being referenced -
1000 * the so-called write mask must be passed to the upper
1001 * operations and applied when assigning value to this swizzle
1007 /* swizzle the vector in-place using the swizzle temporary */
1008 if (!_slang_assemble_constructor_from_swizzle
1009 (A
, &tia
->swz
, &tia
->spec
, &tib
->spec
))
1014 GLuint i
, struct_size
= 0, field_offset
= 0, field_size
= 0;
1017 * Calculate struct size, field offset and field size.
1019 for (i
= 0; i
< tib
->spec
._struct
->fields
->num_variables
; i
++) {
1020 slang_variable
*field
;
1021 slang_storage_aggregate agg
;
1024 field
= &tib
->spec
._struct
->fields
->variables
[i
];
1025 if (!slang_storage_aggregate_construct(&agg
))
1027 if (!_slang_aggregate_variable
1028 (&agg
, &field
->type
.specifier
, field
->array_len
, A
->space
.funcs
,
1029 A
->space
.structs
, A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
)) {
1030 slang_storage_aggregate_destruct(&agg
);
1033 size
= _slang_sizeof_aggregate(&agg
);
1034 slang_storage_aggregate_destruct(&agg
);
1036 if (op
->a_id
== field
->a_name
) {
1038 field_offset
= struct_size
;
1040 struct_size
+= size
;
1043 if (ref
== slang_ref_force
) {
1047 * OPTIMIZATION: If selecting first field, no address shifting
1050 shift
= (field_offset
!= 0);
1053 if (!PLAB(A
->file
, slang_asm_addr_push
, field_offset
))
1055 if (!PUSH(A
->file
, slang_asm_addr_add
))
1060 GLboolean relocate
, shrink
;
1064 * OPTIMIZATION: If selecting last field, no relocation is needed.
1066 relocate
= (field_offset
!= (struct_size
- field_size
));
1069 * OPTIMIZATION: If field and struct sizes are equal, no partial
1072 shrink
= (field_size
!= struct_size
);
1078 * Move the selected element to the end of the master expression.
1079 * Do it in reverse order to avoid overwriting itself.
1081 if (!PLAB(A
->file
, slang_asm_addr_push
, field_offset
))
1083 for (i
= field_size
; i
> 0; i
-= 4)
1085 (A
->file
, slang_asm_float_move
,
1086 struct_size
- field_size
+ i
, i
))
1092 /* free the rest of the master expression */
1093 free_b
+= struct_size
- field_size
;
1097 if (!PLAB(A
->file
, slang_asm_local_free
, free_b
))
1107 _slang_assemble_operation(slang_assemble_ctx
* A
, slang_operation
* op
,
1110 /* set default results */
1111 A
->ref
= /*(ref == slang_ref_freelance) ? slang_ref_force : */ ref
;
1112 A
->swz
.num_components
= 0;
1115 case slang_oper_block_no_new_scope
:
1116 case slang_oper_block_new_scope
:
1120 for (i
= 0; i
< op
->num_children
; i
++) {
1121 if (!_slang_assemble_operation
1122 (A
, &op
->children
[i
],
1123 slang_ref_forbid
/*slang_ref_freelance */ ))
1125 if (!_slang_cleanup_stack(A
, &op
->children
[i
]))
1130 case slang_oper_variable_decl
:
1133 slang_operation assign
;
1136 /* Construct assignment expression placeholder. */
1137 if (!slang_operation_construct(&assign
))
1139 assign
.type
= slang_oper_assign
;
1141 (slang_operation
*) slang_alloc_malloc(2 *
1142 sizeof(slang_operation
));
1143 if (assign
.children
== NULL
) {
1144 slang_operation_destruct(&assign
);
1147 for (assign
.num_children
= 0; assign
.num_children
< 2;
1148 assign
.num_children
++)
1149 if (!slang_operation_construct
1150 (&assign
.children
[assign
.num_children
])) {
1151 slang_operation_destruct(&assign
);
1156 for (i
= 0; i
< op
->num_children
; i
++) {
1157 slang_variable
*var
;
1160 _slang_locate_variable(op
->children
[i
].locals
,
1161 op
->children
[i
].a_id
, GL_TRUE
);
1166 if (var
->initializer
== NULL
)
1169 if (!slang_operation_copy(&assign
.children
[0], &op
->children
[i
])
1170 || !slang_operation_copy(&assign
.children
[1],
1172 || !_slang_assemble_assign(A
, &assign
, "=", slang_ref_forbid
)
1173 || !_slang_cleanup_stack(A
, &assign
)) {
1178 slang_operation_destruct(&assign
);
1183 case slang_oper_asm
:
1186 if (!_slang_assemble_operation(A
, &op
->children
[0], slang_ref_force
))
1188 for (i
= 1; i
< op
->num_children
; i
++)
1189 if (!_slang_assemble_operation
1190 (A
, &op
->children
[i
], slang_ref_forbid
))
1192 if (!call_asm_instruction(A
, op
->a_id
))
1196 case slang_oper_break
:
1197 if (!PLAB(A
->file
, slang_asm_jump
, A
->flow
.loop_end
))
1200 case slang_oper_continue
:
1201 if (!PLAB(A
->file
, slang_asm_jump
, A
->flow
.loop_start
))
1204 case slang_oper_discard
:
1205 if (!PUSH(A
->file
, slang_asm_discard
))
1207 if (!PUSH(A
->file
, slang_asm_exit
))
1210 case slang_oper_return
:
1211 if (A
->local
.ret_size
!= 0) {
1212 /* push the result's address */
1213 if (!PLAB2(A
->file
, slang_asm_local_addr
, 0, A
->local
.ret_size
))
1215 if (!_slang_assemble_operation
1216 (A
, &op
->children
[0], slang_ref_forbid
))
1219 A
->swz
.num_components
= 0;
1220 /* assign the operation to the function result (it was reserved on the stack) */
1221 if (!_slang_assemble_assignment(A
, op
->children
))
1224 if (!PLAB(A
->file
, slang_asm_local_free
, 4))
1227 if (!PLAB(A
->file
, slang_asm_jump
, A
->flow
.function_end
))
1230 case slang_oper_expression
:
1231 if (ref
== slang_ref_force
)
1233 if (!_slang_assemble_operation(A
, &op
->children
[0], ref
))
1237 if (!_slang_assemble_if(A
, op
))
1240 case slang_oper_while
:
1241 if (!_slang_assemble_while(A
, op
))
1245 if (!_slang_assemble_do(A
, op
))
1248 case slang_oper_for
:
1249 if (!_slang_assemble_for(A
, op
))
1252 case slang_oper_void
:
1254 case slang_oper_literal_bool
:
1255 if (ref
== slang_ref_force
)
1257 if (!PLIT(A
->file
, slang_asm_bool_push
, op
->literal
))
1259 A
->ref
= slang_ref_forbid
;
1261 case slang_oper_literal_int
:
1262 if (ref
== slang_ref_force
)
1264 if (!PLIT(A
->file
, slang_asm_int_push
, op
->literal
))
1266 A
->ref
= slang_ref_forbid
;
1268 case slang_oper_literal_float
:
1269 if (ref
== slang_ref_force
)
1271 if (!PLIT(A
->file
, slang_asm_float_push
, op
->literal
))
1273 A
->ref
= slang_ref_forbid
;
1275 case slang_oper_identifier
:
1277 slang_variable
*var
;
1280 /* find the variable and calculate its size */
1281 var
= _slang_locate_variable(op
->locals
, op
->a_id
, GL_TRUE
);
1285 if (!sizeof_variable
1286 (A
, &var
->type
.specifier
, slang_qual_none
, var
->array_len
,
1290 /* prepare stack for dereferencing */
1291 if (ref
== slang_ref_forbid
)
1292 if (!PLAB2(A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
1295 /* push the variable's address */
1297 if (!PLAB(A
->file
, slang_asm_global_addr
, var
->address
))
1301 if (!PLAB2(A
->file
, slang_asm_local_addr
, var
->address
, size
))
1305 /* perform the dereference */
1306 if (ref
== slang_ref_forbid
) {
1307 if (!PUSH(A
->file
, slang_asm_addr_copy
))
1309 if (!PLAB(A
->file
, slang_asm_local_free
, 4))
1311 if (!_slang_dereference(A
, op
))
1316 case slang_oper_sequence
:
1317 if (ref
== slang_ref_force
)
1319 if (!_slang_assemble_operation(A
, &op
->children
[0],
1320 slang_ref_forbid
/*slang_ref_freelance */ ))
1322 if (!_slang_cleanup_stack(A
, &op
->children
[0]))
1324 if (!_slang_assemble_operation(A
, &op
->children
[1], slang_ref_forbid
))
1326 A
->ref
= slang_ref_forbid
;
1328 case slang_oper_assign
:
1329 if (!_slang_assemble_assign(A
, op
, "=", ref
))
1332 case slang_oper_addassign
:
1333 if (!_slang_assemble_assign(A
, op
, "+=", ref
))
1337 case slang_oper_subassign
:
1338 if (!_slang_assemble_assign(A
, op
, "-=", ref
))
1342 case slang_oper_mulassign
:
1343 if (!_slang_assemble_assign(A
, op
, "*=", ref
))
1347 /*case slang_oper_modassign: */
1348 /*case slang_oper_lshassign: */
1349 /*case slang_oper_rshassign: */
1350 /*case slang_oper_orassign: */
1351 /*case slang_oper_xorassign: */
1352 /*case slang_oper_andassign: */
1353 case slang_oper_divassign
:
1354 if (!_slang_assemble_assign(A
, op
, "/=", ref
))
1358 case slang_oper_select
:
1359 if (!_slang_assemble_select(A
, op
))
1361 A
->ref
= slang_ref_forbid
;
1363 case slang_oper_logicalor
:
1364 if (!_slang_assemble_logicalor(A
, op
))
1366 A
->ref
= slang_ref_forbid
;
1368 case slang_oper_logicaland
:
1369 if (!_slang_assemble_logicaland(A
, op
))
1371 A
->ref
= slang_ref_forbid
;
1373 case slang_oper_logicalxor
:
1374 if (!_slang_assemble_function_call_name(A
, "^^", op
->children
, 2, GL_FALSE
))
1376 A
->ref
= slang_ref_forbid
;
1378 /*case slang_oper_bitor: */
1379 /*case slang_oper_bitxor: */
1380 /*case slang_oper_bitand: */
1381 case slang_oper_less
:
1382 if (!_slang_assemble_function_call_name(A
, "<", op
->children
, 2, GL_FALSE
))
1384 A
->ref
= slang_ref_forbid
;
1386 case slang_oper_greater
:
1387 if (!_slang_assemble_function_call_name(A
, ">", op
->children
, 2, GL_FALSE
))
1389 A
->ref
= slang_ref_forbid
;
1391 case slang_oper_lessequal
:
1392 if (!_slang_assemble_function_call_name(A
, "<=", op
->children
, 2, GL_FALSE
))
1394 A
->ref
= slang_ref_forbid
;
1396 case slang_oper_greaterequal
:
1397 if (!_slang_assemble_function_call_name(A
, ">=", op
->children
, 2, GL_FALSE
))
1399 A
->ref
= slang_ref_forbid
;
1401 /*case slang_oper_lshift: */
1402 /*case slang_oper_rshift: */
1403 case slang_oper_add
:
1404 if (!_slang_assemble_function_call_name(A
, "+", op
->children
, 2, GL_FALSE
))
1406 A
->ref
= slang_ref_forbid
;
1408 case slang_oper_subtract
:
1409 if (!_slang_assemble_function_call_name(A
, "-", op
->children
, 2, GL_FALSE
))
1411 A
->ref
= slang_ref_forbid
;
1413 case slang_oper_multiply
:
1414 if (!_slang_assemble_function_call_name(A
, "*", op
->children
, 2, GL_FALSE
))
1416 A
->ref
= slang_ref_forbid
;
1418 /*case slang_oper_modulus: */
1419 case slang_oper_divide
:
1420 if (!_slang_assemble_function_call_name(A
, "/", op
->children
, 2, GL_FALSE
))
1422 A
->ref
= slang_ref_forbid
;
1424 case slang_oper_equal
:
1425 if (!_slang_assemble_operation(A
, &op
->children
[0], slang_ref_forbid
))
1427 if (!_slang_assemble_operation(A
, &op
->children
[1], slang_ref_forbid
))
1429 if (!equality(A
, op
->children
, GL_TRUE
))
1431 A
->ref
= slang_ref_forbid
;
1433 case slang_oper_notequal
:
1434 if (!_slang_assemble_operation(A
, &op
->children
[0], slang_ref_forbid
))
1436 if (!_slang_assemble_operation(A
, &op
->children
[1], slang_ref_forbid
))
1438 if (!equality(A
, op
->children
, GL_FALSE
))
1440 A
->ref
= slang_ref_forbid
;
1442 case slang_oper_preincrement
:
1443 if (!_slang_assemble_assign(A
, op
, "++", ref
))
1447 case slang_oper_predecrement
:
1448 if (!_slang_assemble_assign(A
, op
, "--", ref
))
1452 case slang_oper_plus
:
1453 if (!_slang_dereference(A
, op
))
1455 A
->ref
= slang_ref_forbid
;
1457 case slang_oper_minus
:
1458 if (!_slang_assemble_function_call_name
1459 (A
, "-", op
->children
, 1, GL_FALSE
))
1461 A
->ref
= slang_ref_forbid
;
1463 /*case slang_oper_complement: */
1464 case slang_oper_not
:
1465 if (!_slang_assemble_function_call_name
1466 (A
, "!", op
->children
, 1, GL_FALSE
))
1468 A
->ref
= slang_ref_forbid
;
1470 case slang_oper_subscript
:
1472 slang_assembly_typeinfo ti_arr
, ti_elem
;
1474 if (!slang_assembly_typeinfo_construct(&ti_arr
))
1476 if (!slang_assembly_typeinfo_construct(&ti_elem
)) {
1477 slang_assembly_typeinfo_destruct(&ti_arr
);
1480 if (!handle_subscript(A
, &ti_elem
, &ti_arr
, op
, ref
)) {
1481 slang_assembly_typeinfo_destruct(&ti_arr
);
1482 slang_assembly_typeinfo_destruct(&ti_elem
);
1485 slang_assembly_typeinfo_destruct(&ti_arr
);
1486 slang_assembly_typeinfo_destruct(&ti_elem
);
1489 case slang_oper_call
:
1491 slang_function
*fun
;
1494 _slang_locate_function(A
->space
.funcs
, op
->a_id
, op
->children
,
1495 op
->num_children
, &A
->space
, A
->atoms
);
1497 if (!_slang_assemble_constructor(A
, op
))
1501 if (!_slang_assemble_function_call
1502 (A
, fun
, op
->children
, op
->num_children
, GL_FALSE
))
1505 A
->ref
= slang_ref_forbid
;
1508 case slang_oper_field
:
1510 slang_assembly_typeinfo ti_after
, ti_before
;
1512 if (!slang_assembly_typeinfo_construct(&ti_after
))
1514 if (!slang_assembly_typeinfo_construct(&ti_before
)) {
1515 slang_assembly_typeinfo_destruct(&ti_after
);
1518 if (!handle_field(A
, &ti_after
, &ti_before
, op
, ref
)) {
1519 slang_assembly_typeinfo_destruct(&ti_after
);
1520 slang_assembly_typeinfo_destruct(&ti_before
);
1523 slang_assembly_typeinfo_destruct(&ti_after
);
1524 slang_assembly_typeinfo_destruct(&ti_before
);
1527 case slang_oper_postincrement
:
1528 if (!assemble_function_call_name_dummyint(A
, "++", op
->children
))
1530 A
->ref
= slang_ref_forbid
;
1532 case slang_oper_postdecrement
:
1533 if (!assemble_function_call_name_dummyint(A
, "--", op
->children
))
1535 A
->ref
= slang_ref_forbid
;