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_utility.h"
33 #include "slang_assemble.h"
34 #include "slang_storage.h"
35 #include "slang_assemble_typeinfo.h"
36 #include "slang_assemble_conditional.h"
37 #include "slang_assemble_assignment.h"
38 #include "slang_execute.h"
42 static GLboolean
slang_assembly_construct (slang_assembly
*assem
)
44 assem
->type
= slang_asm_none
;
48 static GLvoid
slang_assembly_destruct (slang_assembly
*assem
)
52 /* slang_assembly_file */
54 GLboolean
slang_assembly_file_construct (slang_assembly_file
*file
)
62 GLvoid
slang_assembly_file_destruct (slang_assembly_file
*file
)
66 for (i
= 0; i
< file
->count
; i
++)
67 slang_assembly_destruct (&file
->code
[i
]);
68 slang_alloc_free (file
->code
);
71 static GLboolean
push_new (slang_assembly_file
*file
)
73 if (file
->count
== file
->capacity
)
77 if (file
->capacity
== 0)
80 n
= file
->capacity
* 2;
81 file
->code
= (slang_assembly
*) slang_alloc_realloc (file
->code
,
82 file
->capacity
* sizeof (slang_assembly
), n
* sizeof (slang_assembly
));
83 if (file
->code
== NULL
)
87 if (!slang_assembly_construct (&file
->code
[file
->count
]))
93 static GLboolean
push_gen (slang_assembly_file
*file
, slang_assembly_type type
, GLfloat literal
,
94 GLuint label
, GLuint size
)
96 slang_assembly
*assem
;
100 assem
= &file
->code
[file
->count
- 1];
102 assem
->literal
= literal
;
103 assem
->param
[0] = label
;
104 assem
->param
[1] = size
;
108 GLboolean
slang_assembly_file_push (slang_assembly_file
*file
, slang_assembly_type type
)
110 return push_gen (file
, type
, (GLfloat
) 0, 0, 0);
113 GLboolean
slang_assembly_file_push_label (slang_assembly_file
*file
, slang_assembly_type type
,
116 return push_gen (file
, type
, (GLfloat
) 0, label
, 0);
119 GLboolean
slang_assembly_file_push_label2 (slang_assembly_file
*file
, slang_assembly_type type
,
120 GLuint label1
, GLuint label2
)
122 return push_gen (file
, type
, (GLfloat
) 0, label1
, label2
);
125 GLboolean
slang_assembly_file_push_literal (slang_assembly_file
*file
, slang_assembly_type type
,
128 return push_gen (file
, type
, literal
, 0, 0);
131 #define PUSH slang_assembly_file_push
132 #define PLAB slang_assembly_file_push_label
133 #define PLAB2 slang_assembly_file_push_label2
134 #define PLIT slang_assembly_file_push_literal
136 /* slang_assembly_file_restore_point */
138 GLboolean
slang_assembly_file_restore_point_save (slang_assembly_file
*file
,
139 slang_assembly_file_restore_point
*point
)
141 point
->count
= file
->count
;
145 GLboolean
slang_assembly_file_restore_point_load (slang_assembly_file
*file
,
146 slang_assembly_file_restore_point
*point
)
150 for (i
= point
->count
; i
< file
->count
; i
++)
151 slang_assembly_destruct (&file
->code
[i
]);
152 file
->count
= point
->count
;
156 /* utility functions */
158 static GLboolean
sizeof_variable (slang_assemble_ctx
*A
, slang_type_specifier
*spec
,
159 slang_type_qualifier qual
, GLuint array_len
, GLuint
*size
)
161 slang_storage_aggregate agg
;
163 /* calculate the size of the variable's aggregate */
164 if (!slang_storage_aggregate_construct (&agg
))
166 if (!_slang_aggregate_variable (&agg
, spec
, array_len
, A
->space
.funcs
, A
->space
.structs
,
167 A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
))
169 slang_storage_aggregate_destruct (&agg
);
172 *size
+= _slang_sizeof_aggregate (&agg
);
173 slang_storage_aggregate_destruct (&agg
);
175 /* for reference variables consider the additional address overhead */
176 if (qual
== slang_qual_out
|| qual
== slang_qual_inout
)
182 static GLboolean
sizeof_variable2 (slang_assemble_ctx
*A
, slang_variable
*var
, GLuint
*size
)
184 var
->address
= *size
;
185 if (var
->type
.qualifier
== slang_qual_out
|| var
->type
.qualifier
== slang_qual_inout
)
187 return sizeof_variable (A
, &var
->type
.specifier
, var
->type
.qualifier
, var
->array_len
, size
);
190 static GLboolean
sizeof_variables (slang_assemble_ctx
*A
, slang_variable_scope
*vars
, GLuint start
,
191 GLuint stop
, GLuint
*size
)
195 for (i
= start
; i
< stop
; i
++)
196 if (!sizeof_variable2 (A
, &vars
->variables
[i
], size
))
201 static GLboolean
collect_locals (slang_assemble_ctx
*A
, slang_operation
*op
, GLuint
*size
)
205 if (!sizeof_variables (A
, op
->locals
, 0, op
->locals
->num_variables
, size
))
207 for (i
= 0; i
< op
->num_children
; i
++)
208 if (!collect_locals (A
, &op
->children
[i
], size
))
213 /* _slang_locate_function() */
215 slang_function
*_slang_locate_function (slang_function_scope
*funcs
, slang_atom a_name
,
216 slang_operation
*params
, GLuint num_params
, slang_assembly_name_space
*space
,
217 slang_atom_pool
*atoms
)
221 for (i
= 0; i
< funcs
->num_functions
; i
++)
224 slang_function
*f
= &funcs
->functions
[i
];
226 if (a_name
!= f
->header
.a_name
)
228 if (f
->param_count
!= num_params
)
230 for (j
= 0; j
< num_params
; j
++)
232 slang_assembly_typeinfo ti
;
234 if (!slang_assembly_typeinfo_construct (&ti
))
236 if (!_slang_typeof_operation_ (¶ms
[j
], space
, &ti
, atoms
))
238 slang_assembly_typeinfo_destruct (&ti
);
241 if (!slang_type_specifier_equal (&ti
.spec
, &f
->parameters
->variables
[j
].type
.specifier
))
243 slang_assembly_typeinfo_destruct (&ti
);
246 slang_assembly_typeinfo_destruct (&ti
);
248 /* "out" and "inout" formal parameter requires the actual parameter to be l-value */
249 if (!ti
.can_be_referenced
&&
250 (f
->parameters
->variables
[j
].type
.qualifier
== slang_qual_out
||
251 f
->parameters
->variables
[j
].type
.qualifier
== slang_qual_inout
))
257 if (funcs
->outer_scope
!= NULL
)
258 return _slang_locate_function (funcs
->outer_scope
, a_name
, params
, num_params
, space
, atoms
);
262 /* _slang_assemble_function() */
264 GLboolean
_slang_assemble_function (slang_assemble_ctx
*A
, slang_function
*fun
)
266 GLuint param_size
, local_size
;
267 GLuint skip
, cleanup
;
269 fun
->address
= A
->file
->count
;
271 if (fun
->body
== NULL
)
273 /* jump to the actual function body - we do not know it, so add the instruction
275 fun
->fixups
.table
= (GLuint
*) slang_alloc_realloc (fun
->fixups
.table
,
276 fun
->fixups
.count
* sizeof (GLuint
), (fun
->fixups
.count
+ 1) * sizeof (GLuint
));
277 if (fun
->fixups
.table
== NULL
)
279 fun
->fixups
.table
[fun
->fixups
.count
] = fun
->address
;
281 if (!PUSH (A
->file
, slang_asm_jump
))
289 /* resolve all fixup table entries and delete it */
290 for (i
= 0; i
< fun
->fixups
.count
; i
++)
291 A
->file
->code
[fun
->fixups
.table
[i
]].param
[0] = fun
->address
;
292 slang_fixup_table_free (&fun
->fixups
);
295 /* At this point traverse function formal parameters and code to calculate
296 * total memory size to be allocated on the stack.
297 * During this process the variables will be assigned local addresses to
298 * reference them in the code.
299 * No storage optimizations are performed so exclusive scopes are not detected and shared. */
301 /* calculate return value size */
303 if (fun
->header
.type
.specifier
.type
!= slang_spec_void
)
304 if (!sizeof_variable (A
, &fun
->header
.type
.specifier
, slang_qual_none
, 0, ¶m_size
))
306 A
->local
.ret_size
= param_size
;
308 /* calculate formal parameter list size */
309 if (!sizeof_variables (A
, fun
->parameters
, 0, fun
->param_count
, ¶m_size
))
312 /* calculate local variables size - take into account the four-byte return address and
313 * temporaries for various tasks (4 for addr and 16 for swizzle temporaries).
314 * these include variables from the formal parameter scope and from the code */
315 A
->local
.addr_tmp
= param_size
+ 4;
316 A
->local
.swizzle_tmp
= param_size
+ 4 + 4;
317 local_size
= param_size
+ 4 + 4 + 16;
318 if (!sizeof_variables (A
, fun
->parameters
, fun
->param_count
, fun
->parameters
->num_variables
,
321 if (!collect_locals (A
, fun
->body
, &local_size
))
324 /* allocate local variable storage */
325 if (!PLAB (A
->file
, slang_asm_local_alloc
, local_size
- param_size
- 4))
328 /* mark a new frame for function variable storage */
329 if (!PLAB (A
->file
, slang_asm_enter
, local_size
))
332 /* jump directly to the actual code */
333 skip
= A
->file
->count
;
334 if (!push_new (A
->file
))
336 A
->file
->code
[skip
].type
= slang_asm_jump
;
338 /* all "return" statements will be directed here */
339 A
->flow
.function_end
= A
->file
->count
;
340 cleanup
= A
->file
->count
;
341 if (!push_new (A
->file
))
343 A
->file
->code
[cleanup
].type
= slang_asm_jump
;
345 /* execute the function body */
346 A
->file
->code
[skip
].param
[0] = A
->file
->count
;
347 if (!_slang_assemble_operation (A
, fun
->body
, /*slang_ref_freelance*/slang_ref_forbid
))
350 /* this is the end of the function - restore the old function frame */
351 A
->file
->code
[cleanup
].param
[0] = A
->file
->count
;
352 if (!PUSH (A
->file
, slang_asm_leave
))
355 /* free local variable storage */
356 if (!PLAB (A
->file
, slang_asm_local_free
, local_size
- param_size
- 4))
359 /* return from the function */
360 if (!PUSH (A
->file
, slang_asm_return
))
366 GLboolean
_slang_cleanup_stack (slang_assemble_ctx
*A
, slang_operation
*op
)
368 slang_assembly_typeinfo ti
;
371 /* get type info of the operation and calculate its size */
372 if (!slang_assembly_typeinfo_construct (&ti
))
374 if (!_slang_typeof_operation (A
, op
, &ti
))
376 slang_assembly_typeinfo_destruct (&ti
);
379 if (ti
.spec
.type
!= slang_spec_void
)
380 if (A
->ref
== slang_ref_force
)
382 else if (!sizeof_variable (A
, &ti
.spec
, slang_qual_none
, 0, &size
))
384 slang_assembly_typeinfo_destruct (&ti
);
387 slang_assembly_typeinfo_destruct (&ti
);
389 /* if nonzero, free it from the stack */
392 if (!PLAB (A
->file
, slang_asm_local_free
, size
))
399 /* _slang_assemble_operation() */
401 static GLboolean
dereference_aggregate (slang_assemble_ctx
*A
, const slang_storage_aggregate
*agg
,
402 GLuint
*size
, slang_swizzle
*swz
, GLboolean is_swizzled
)
406 for (i
= agg
->count
; i
> 0; i
--)
408 const slang_storage_array
*arr
= &agg
->arrays
[i
- 1];
411 for (j
= arr
->length
; j
> 0; j
--)
413 if (arr
->type
== slang_stor_aggregate
)
415 if (!dereference_aggregate (A
, arr
->aggregate
, size
, swz
, is_swizzled
))
421 slang_assembly_type ty
;
425 /* calculate the offset within source variable to read */
428 /* swizzle the index to get the actual offset */
429 src_offset
= swz
->swizzle
[*size
/ 4] * 4;
433 /* no swizzling - read sequentially */
437 /* dereference data slot of a basic type */
438 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
440 if (!PUSH (A
->file
, slang_asm_addr_deref
))
442 if (!PLAB (A
->file
, slang_asm_addr_push
, src_offset
))
444 if (!PUSH (A
->file
, slang_asm_addr_add
))
449 case slang_stor_bool
:
450 ty
= slang_asm_bool_deref
;
453 ty
= slang_asm_int_deref
;
455 case slang_stor_float
:
456 ty
= slang_asm_float_deref
;
459 _mesa_problem(NULL
, "Unexpected arr->type in dereference_aggregate");
462 if (!PUSH (A
->file
, ty
))
471 GLboolean
_slang_dereference (slang_assemble_ctx
*A
, slang_operation
*op
)
473 slang_assembly_typeinfo ti
;
474 GLboolean result
= GL_FALSE
;
475 slang_storage_aggregate agg
;
478 /* get type information of the given operation */
479 if (!slang_assembly_typeinfo_construct (&ti
))
481 if (!_slang_typeof_operation (A
, op
, &ti
))
484 /* construct aggregate from the type info */
485 if (!slang_storage_aggregate_construct (&agg
))
487 if (!_slang_aggregate_variable (&agg
, &ti
.spec
, ti
.array_len
, A
->space
.funcs
, A
->space
.structs
,
488 A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
))
491 /* dereference the resulting aggregate */
492 size
= _slang_sizeof_aggregate (&agg
);
493 result
= dereference_aggregate (A
, &agg
, &size
, &ti
.swz
, ti
.is_swizzled
);
496 slang_storage_aggregate_destruct (&agg
);
498 slang_assembly_typeinfo_destruct (&ti
);
502 GLboolean
_slang_assemble_function_call (slang_assemble_ctx
*A
, slang_function
*fun
,
503 slang_operation
*params
, GLuint param_count
, GLboolean assignment
)
506 slang_swizzle p_swz
[64];
507 slang_ref_type p_ref
[64];
509 /* TODO: fix this, allocate dynamically */
510 if (param_count
> 64)
513 /* make room for the return value, if any */
514 if (fun
->header
.type
.specifier
.type
!= slang_spec_void
)
518 if (!sizeof_variable (A
, &fun
->header
.type
.specifier
, slang_qual_none
, 0, &ret_size
))
520 if (!PLAB (A
->file
, slang_asm_local_alloc
, ret_size
))
524 /* push the actual parameters on the stack */
525 for (i
= 0; i
< param_count
; i
++)
527 if (fun
->parameters
->variables
[i
].type
.qualifier
== slang_qual_inout
||
528 fun
->parameters
->variables
[i
].type
.qualifier
== slang_qual_out
)
530 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
532 /* TODO: optimize the "out" parameter case */
533 if (!_slang_assemble_operation (A
, ¶ms
[i
], slang_ref_force
))
537 if (!PUSH (A
->file
, slang_asm_addr_copy
))
539 if (!PUSH (A
->file
, slang_asm_addr_deref
))
541 if (i
== 0 && assignment
)
543 /* duplicate the resulting address */
544 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
546 if (!PUSH (A
->file
, slang_asm_addr_deref
))
549 if (!_slang_dereference (A
, ¶ms
[i
]))
554 if (!_slang_assemble_operation (A
, ¶ms
[i
], slang_ref_forbid
))
561 /* call the function */
562 if (!PLAB (A
->file
, slang_asm_call
, fun
->address
))
565 /* pop the parameters from the stack */
566 for (i
= param_count
; i
> 0; i
--)
572 if (fun
->parameters
->variables
[j
].type
.qualifier
== slang_qual_inout
||
573 fun
->parameters
->variables
[j
].type
.qualifier
== slang_qual_out
)
575 /* for output parameter copy the contents of the formal parameter
576 * back to the original actual parameter */
577 if (!_slang_assemble_assignment (A
, ¶ms
[j
]))
579 /* pop the actual parameter's address */
580 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
585 /* pop the value of the parameter */
586 if (!_slang_cleanup_stack (A
, ¶ms
[j
]))
594 GLboolean
_slang_assemble_function_call_name (slang_assemble_ctx
*A
, const char *name
,
595 slang_operation
*params
, GLuint param_count
, GLboolean assignment
)
600 atom
= slang_atom_pool_atom (A
->atoms
, name
);
601 if (atom
== SLANG_ATOM_NULL
)
603 fun
= _slang_locate_function (A
->space
.funcs
, atom
, params
, param_count
, &A
->space
, A
->atoms
);
606 return _slang_assemble_function_call (A
, fun
, params
, param_count
, assignment
);
609 static GLboolean
assemble_function_call_name_dummyint (slang_assemble_ctx
*A
, const char *name
,
610 slang_operation
*params
)
612 slang_operation p
[2];
616 if (!slang_operation_construct (&p
[1]))
618 p
[1].type
= slang_oper_literal_int
;
619 result
= _slang_assemble_function_call_name (A
, name
, p
, 2, GL_FALSE
);
620 slang_operation_destruct (&p
[1]);
627 slang_assembly_type code1
, code2
;
630 { "float_add", slang_asm_float_add
, slang_asm_float_copy
},
631 { "float_multiply", slang_asm_float_multiply
, slang_asm_float_copy
},
632 { "float_divide", slang_asm_float_divide
, slang_asm_float_copy
},
633 { "float_negate", slang_asm_float_negate
, slang_asm_float_copy
},
634 { "float_less", slang_asm_float_less
, slang_asm_bool_copy
},
635 { "float_equal", slang_asm_float_equal_exp
,slang_asm_bool_copy
},
636 { "float_to_int", slang_asm_float_to_int
, slang_asm_int_copy
},
637 { "float_sine", slang_asm_float_sine
, slang_asm_float_copy
},
638 { "float_arcsine", slang_asm_float_arcsine
, slang_asm_float_copy
},
639 { "float_arctan", slang_asm_float_arctan
, slang_asm_float_copy
},
640 { "float_power", slang_asm_float_power
, slang_asm_float_copy
},
641 { "float_log2", slang_asm_float_log2
, slang_asm_float_copy
},
642 { "float_floor", slang_asm_float_floor
, slang_asm_float_copy
},
643 { "float_ceil", slang_asm_float_ceil
, slang_asm_float_copy
},
644 { "float_noise1", slang_asm_float_noise1
, slang_asm_float_copy
},
645 { "float_noise2", slang_asm_float_noise2
, slang_asm_float_copy
},
646 { "float_noise3", slang_asm_float_noise3
, slang_asm_float_copy
},
647 { "float_noise4", slang_asm_float_noise4
, slang_asm_float_copy
},
648 { "int_to_float", slang_asm_int_to_float
, slang_asm_float_copy
},
649 { "vec4_tex2d", slang_asm_vec4_tex2d
, slang_asm_none
},
650 /* mesa-specific extensions */
651 { "float_print", slang_asm_float_deref
, slang_asm_float_print
},
652 { "int_print", slang_asm_int_deref
, slang_asm_int_print
},
653 { "bool_print", slang_asm_bool_deref
, slang_asm_bool_print
},
654 { NULL
, slang_asm_none
, slang_asm_none
}
657 static GLboolean
call_asm_instruction (slang_assemble_ctx
*A
, slang_atom a_name
)
662 id
= slang_atom_pool_id (A
->atoms
, a_name
);
664 for (i
= 0; inst
[i
].name
!= NULL
; i
++)
665 if (slang_string_compare (id
, inst
[i
].name
) == 0)
667 if (inst
[i
].name
== NULL
)
670 if (!PLAB2 (A
->file
, inst
[i
].code1
, 4, 0))
672 if (inst
[i
].code2
!= slang_asm_none
)
673 if (!PLAB2 (A
->file
, inst
[i
].code2
, 4, 0))
676 /* clean-up the stack from the remaining dst address */
677 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
683 static GLboolean
equality_aggregate (slang_assemble_ctx
*A
, const slang_storage_aggregate
*agg
,
684 GLuint
*index
, GLuint size
, GLuint z_label
)
688 for (i
= 0; i
< agg
->count
; i
++)
690 const slang_storage_array
*arr
= &agg
->arrays
[i
];
693 for (j
= 0; j
< arr
->length
; j
++)
695 if (arr
->type
== slang_stor_aggregate
)
697 if (!equality_aggregate (A
, arr
->aggregate
, index
, size
, z_label
))
702 if (!PLAB2 (A
->file
, slang_asm_float_equal_int
, size
+ *index
, *index
))
705 if (!PLAB (A
->file
, slang_asm_jump_if_zero
, z_label
))
714 static GLboolean
equality (slang_assemble_ctx
*A
, slang_operation
*op
, GLboolean equal
)
716 slang_assembly_typeinfo ti
;
717 GLboolean result
= GL_FALSE
;
718 slang_storage_aggregate agg
;
720 GLuint skip_jump
, true_label
, true_jump
, false_label
, false_jump
;
722 /* get type of operation */
723 if (!slang_assembly_typeinfo_construct (&ti
))
725 if (!_slang_typeof_operation (A
, op
, &ti
))
728 /* convert it to an aggregate */
729 if (!slang_storage_aggregate_construct (&agg
))
731 if (!_slang_aggregate_variable (&agg
, &ti
.spec
, 0, A
->space
.funcs
, A
->space
.structs
,
732 A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
))
735 /* compute the size of the agregate - there are two such aggregates on the stack */
736 size
= _slang_sizeof_aggregate (&agg
);
738 /* jump to the actual data-comparison code */
739 skip_jump
= A
->file
->count
;
740 if (!PUSH (A
->file
, slang_asm_jump
))
743 /* pop off the stack the compared data and push 1 */
744 true_label
= A
->file
->count
;
745 if (!PLAB (A
->file
, slang_asm_local_free
, size
* 2))
747 if (!PLIT (A
->file
, slang_asm_bool_push
, (GLfloat
) 1))
749 true_jump
= A
->file
->count
;
750 if (!PUSH (A
->file
, slang_asm_jump
))
753 false_label
= A
->file
->count
;
754 if (!PLAB (A
->file
, slang_asm_local_free
, size
* 2))
756 if (!PLIT (A
->file
, slang_asm_bool_push
, (GLfloat
) 0))
758 false_jump
= A
->file
->count
;
759 if (!PUSH (A
->file
, slang_asm_jump
))
762 A
->file
->code
[skip_jump
].param
[0] = A
->file
->count
;
764 /* compare the data on stack, it will eventually jump either to true or false label */
766 if (!equality_aggregate (A
, &agg
, &index
, size
, equal
? false_label
: true_label
))
768 if (!PLAB (A
->file
, slang_asm_jump
, equal
? true_label
: false_label
))
771 A
->file
->code
[true_jump
].param
[0] = A
->file
->count
;
772 A
->file
->code
[false_jump
].param
[0] = A
->file
->count
;
776 slang_storage_aggregate_destruct (&agg
);
778 slang_assembly_typeinfo_destruct (&ti
);
782 static GLboolean
handle_subscript (slang_assemble_ctx
*A
, slang_assembly_typeinfo
*tie
,
783 slang_assembly_typeinfo
*tia
, slang_operation
*op
, slang_ref_type ref
)
785 GLuint asize
= 0, esize
= 0;
787 /* get type info of the master expression (matrix, vector or an array */
788 if (!_slang_typeof_operation (A
, &op
->children
[0], tia
))
790 if (!sizeof_variable (A
, &tia
->spec
, slang_qual_none
, tia
->array_len
, &asize
))
793 /* get type info of the result (matrix column, vector row or array element) */
794 if (!_slang_typeof_operation (A
, op
, tie
))
796 if (!sizeof_variable (A
, &tie
->spec
, slang_qual_none
, 0, &esize
))
799 /* assemble the master expression */
800 if (!_slang_assemble_operation (A
, &op
->children
[0], ref
))
803 /* when indexing an l-value swizzle, push the swizzle_tmp */
804 if (ref
== slang_ref_force
&& tia
->is_swizzled
)
805 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.swizzle_tmp
, 16))
808 /* assemble the subscript expression */
809 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
812 if (ref
== slang_ref_force
&& tia
->is_swizzled
)
816 /* copy the swizzle indexes to the swizzle_tmp */
817 for (i
= 0; i
< tia
->swz
.num_components
; i
++)
819 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.swizzle_tmp
, 16))
821 if (!PLAB (A
->file
, slang_asm_addr_push
, i
* 4))
823 if (!PUSH (A
->file
, slang_asm_addr_add
))
825 if (!PLAB (A
->file
, slang_asm_addr_push
, tia
->swz
.swizzle
[i
]))
827 if (!PUSH (A
->file
, slang_asm_addr_copy
))
829 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
833 /* offset the pushed swizzle_tmp address and dereference it */
834 if (!PUSH (A
->file
, slang_asm_int_to_addr
))
836 if (!PLAB (A
->file
, slang_asm_addr_push
, 4))
838 if (!PUSH (A
->file
, slang_asm_addr_multiply
))
840 if (!PUSH (A
->file
, slang_asm_addr_add
))
842 if (!PUSH (A
->file
, slang_asm_addr_deref
))
847 /* convert the integer subscript to a relative address */
848 if (!PUSH (A
->file
, slang_asm_int_to_addr
))
852 if (!PLAB (A
->file
, slang_asm_addr_push
, esize
))
854 if (!PUSH (A
->file
, slang_asm_addr_multiply
))
857 if (ref
== slang_ref_force
)
859 /* offset the base address with the relative address */
860 if (!PUSH (A
->file
, slang_asm_addr_add
))
867 /* move the selected element to the beginning of the master expression */
868 for (i
= 0; i
< esize
; i
+= 4)
869 if (!PLAB2 (A
->file
, slang_asm_float_move
, asize
- esize
+ i
+ 4, i
+ 4))
871 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
874 /* free the rest of the master expression */
875 if (!PLAB (A
->file
, slang_asm_local_free
, asize
- esize
))
882 static GLboolean
handle_field (slang_assemble_ctx
*A
, slang_assembly_typeinfo
*tia
,
883 slang_assembly_typeinfo
*tib
, slang_operation
*op
, slang_ref_type ref
)
885 /* get type info of the result (field or swizzle) */
886 if (!_slang_typeof_operation (A
, op
, tia
))
889 /* get type info of the master expression being accessed (struct or vector) */
890 if (!_slang_typeof_operation (A
, &op
->children
[0], tib
))
893 /* if swizzling a vector in-place, the swizzle temporary is needed */
894 if (ref
== slang_ref_forbid
&& tia
->is_swizzled
)
895 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.swizzle_tmp
, 16))
898 /* assemble the master expression */
899 if (!_slang_assemble_operation (A
, &op
->children
[0], ref
))
902 /* assemble the field expression */
903 if (tia
->is_swizzled
)
905 if (ref
== slang_ref_force
)
908 if (tia
->swz
.num_components
== 1)
910 /* simple case - adjust the vector's address to point to the selected component */
911 if (!PLAB (file
, slang_asm_addr_push
, tia
->swz
.swizzle
[0] * 4))
913 if (!PUSH (file
, slang_asm_addr_add
))
919 /* two or more vector components are being referenced - the so-called write mask
920 * must be passed to the upper operations and applied when assigning value
927 /* swizzle the vector in-place using the swizzle temporary */
928 if (!_slang_assemble_constructor_from_swizzle (A
, &tia
->swz
, &tia
->spec
, &tib
->spec
))
934 GLuint i
, struct_size
= 0, field_offset
= 0, field_size
= 0;
936 for (i
= 0; i
< tib
->spec
._struct
->fields
->num_variables
; i
++)
938 slang_variable
*field
;
939 slang_storage_aggregate agg
;
942 field
= &tib
->spec
._struct
->fields
->variables
[i
];
943 if (!slang_storage_aggregate_construct (&agg
))
945 if (!_slang_aggregate_variable (&agg
, &field
->type
.specifier
, field
->array_len
,
946 A
->space
.funcs
, A
->space
.structs
, A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
))
948 slang_storage_aggregate_destruct (&agg
);
951 size
= _slang_sizeof_aggregate (&agg
);
952 slang_storage_aggregate_destruct (&agg
);
954 if (op
->a_id
== field
->a_name
)
957 struct_size
= field_offset
+ size
;
959 else if (struct_size
!= 0)
962 field_offset
+= size
;
965 if (!PLAB (A
->file
, slang_asm_addr_push
, field_offset
))
968 if (ref
== slang_ref_force
)
970 if (!PUSH (A
->file
, slang_asm_addr_add
))
977 /* move the selected element to the beginning of the master expression */
978 for (i
= 0; i
< field_size
; i
+= 4)
979 if (!PLAB2 (A
->file
, slang_asm_float_move
, struct_size
- field_size
+ i
+ 4, i
+ 4))
981 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
984 /* free the rest of the master expression */
985 if (!PLAB (A
->file
, slang_asm_local_free
, struct_size
- field_size
))
993 GLboolean
_slang_assemble_operation (slang_assemble_ctx
*A
, slang_operation
*op
, slang_ref_type ref
)
995 /* set default results */
996 A
->ref
= /*(ref == slang_ref_freelance) ? slang_ref_force : */ref
;
997 A
->swz
.num_components
= 0;
1001 case slang_oper_block_no_new_scope
:
1002 case slang_oper_block_new_scope
:
1006 for (i
= 0; i
< op
->num_children
; i
++)
1008 if (!_slang_assemble_operation (A
, &op
->children
[i
], slang_ref_forbid
/*slang_ref_freelance*/))
1010 if (!_slang_cleanup_stack (A
, &op
->children
[i
]))
1015 case slang_oper_variable_decl
:
1019 for (i
= 0; i
< op
->num_children
; i
++)
1021 /* TODO: perform initialization of op->children[i] */
1022 /* TODO: clean-up stack */
1026 case slang_oper_asm
:
1030 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_force
))
1032 for (i
= 1; i
< op
->num_children
; i
++)
1033 if (!_slang_assemble_operation (A
, &op
->children
[i
], slang_ref_forbid
))
1035 if (!call_asm_instruction (A
, op
->a_id
))
1039 case slang_oper_break
:
1040 if (!PLAB (A
->file
, slang_asm_jump
, A
->flow
.loop_end
))
1043 case slang_oper_continue
:
1044 if (!PLAB (A
->file
, slang_asm_jump
, A
->flow
.loop_start
))
1047 case slang_oper_discard
:
1048 if (!PUSH (A
->file
, slang_asm_discard
))
1050 if (!PUSH (A
->file
, slang_asm_exit
))
1053 case slang_oper_return
:
1054 if (A
->local
.ret_size
!= 0)
1056 /* push the result's address */
1057 if (!PLAB2 (A
->file
, slang_asm_local_addr
, 0, A
->local
.ret_size
))
1059 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
))
1062 A
->swz
.num_components
= 0;
1063 /* assign the operation to the function result (it was reserved on the stack) */
1064 if (!_slang_assemble_assignment (A
, op
->children
))
1067 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
1070 if (!PLAB (A
->file
, slang_asm_jump
, A
->flow
.function_end
))
1073 case slang_oper_expression
:
1074 if (ref
== slang_ref_force
)
1076 if (!_slang_assemble_operation (A
, &op
->children
[0], ref
))
1080 if (!_slang_assemble_if (A
, op
))
1083 case slang_oper_while
:
1084 if (!_slang_assemble_while (A
, op
))
1088 if (!_slang_assemble_do (A
, op
))
1091 case slang_oper_for
:
1092 if (!_slang_assemble_for (A
, op
))
1095 case slang_oper_void
:
1097 case slang_oper_literal_bool
:
1098 if (ref
== slang_ref_force
)
1100 if (!PLIT (A
->file
, slang_asm_bool_push
, op
->literal
))
1102 A
->ref
= slang_ref_forbid
;
1104 case slang_oper_literal_int
:
1105 if (ref
== slang_ref_force
)
1107 if (!PLIT (A
->file
, slang_asm_int_push
, op
->literal
))
1109 A
->ref
= slang_ref_forbid
;
1111 case slang_oper_literal_float
:
1112 if (ref
== slang_ref_force
)
1114 if (!PLIT (A
->file
, slang_asm_float_push
, op
->literal
))
1116 A
->ref
= slang_ref_forbid
;
1118 case slang_oper_identifier
:
1120 slang_variable
*var
;
1123 /* find the variable and calculate its size */
1124 var
= _slang_locate_variable (op
->locals
, op
->a_id
, GL_TRUE
);
1128 if (!sizeof_variable (A
, &var
->type
.specifier
, slang_qual_none
, var
->array_len
, &size
))
1131 /* prepare stack for dereferencing */
1132 if (ref
== slang_ref_forbid
)
1133 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
1136 /* push the variable's address */
1139 if (!PLAB (A
->file
, slang_asm_addr_push
, var
->address
))
1144 if (!PLAB2 (A
->file
, slang_asm_local_addr
, var
->address
, size
))
1148 /* perform the dereference */
1149 if (ref
== slang_ref_forbid
)
1151 if (!PUSH (A
->file
, slang_asm_addr_copy
))
1153 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
1155 if (!_slang_dereference (A
, op
))
1160 case slang_oper_sequence
:
1161 if (ref
== slang_ref_force
)
1163 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
/*slang_ref_freelance*/))
1165 if (!_slang_cleanup_stack (A
, &op
->children
[0]))
1167 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
1169 A
->ref
= slang_ref_forbid
;
1171 case slang_oper_assign
:
1172 if (!_slang_assemble_assign (A
, op
, "=", ref
))
1175 case slang_oper_addassign
:
1176 if (!_slang_assemble_assign (A
, op
, "+=", ref
))
1179 case slang_oper_subassign
:
1180 if (!_slang_assemble_assign (A
, op
, "-=", ref
))
1183 case slang_oper_mulassign
:
1184 if (!_slang_assemble_assign (A
, op
, "*=", ref
))
1187 /*case slang_oper_modassign:*/
1188 /*case slang_oper_lshassign:*/
1189 /*case slang_oper_rshassign:*/
1190 /*case slang_oper_orassign:*/
1191 /*case slang_oper_xorassign:*/
1192 /*case slang_oper_andassign:*/
1193 case slang_oper_divassign
:
1194 if (!_slang_assemble_assign (A
, op
, "/=", ref
))
1197 case slang_oper_select
:
1198 if (!_slang_assemble_select (A
, op
))
1200 A
->ref
= slang_ref_forbid
;
1202 case slang_oper_logicalor
:
1203 if (!_slang_assemble_logicalor (A
, op
))
1205 A
->ref
= slang_ref_forbid
;
1207 case slang_oper_logicaland
:
1208 if (!_slang_assemble_logicaland (A
, op
))
1210 A
->ref
= slang_ref_forbid
;
1212 case slang_oper_logicalxor
:
1213 if (!_slang_assemble_function_call_name (A
, "^^", op
->children
, 2, GL_FALSE
))
1215 A
->ref
= slang_ref_forbid
;
1217 /*case slang_oper_bitor:*/
1218 /*case slang_oper_bitxor:*/
1219 /*case slang_oper_bitand:*/
1220 case slang_oper_less
:
1221 if (!_slang_assemble_function_call_name (A
, "<", op
->children
, 2, GL_FALSE
))
1223 A
->ref
= slang_ref_forbid
;
1225 case slang_oper_greater
:
1226 if (!_slang_assemble_function_call_name (A
, ">", op
->children
, 2, GL_FALSE
))
1228 A
->ref
= slang_ref_forbid
;
1230 case slang_oper_lessequal
:
1231 if (!_slang_assemble_function_call_name (A
, "<=", op
->children
, 2, GL_FALSE
))
1233 A
->ref
= slang_ref_forbid
;
1235 case slang_oper_greaterequal
:
1236 if (!_slang_assemble_function_call_name (A
, ">=", op
->children
, 2, GL_FALSE
))
1238 A
->ref
= slang_ref_forbid
;
1240 /*case slang_oper_lshift:*/
1241 /*case slang_oper_rshift:*/
1242 case slang_oper_add
:
1243 if (!_slang_assemble_function_call_name (A
, "+", op
->children
, 2, GL_FALSE
))
1245 A
->ref
= slang_ref_forbid
;
1247 case slang_oper_subtract
:
1248 if (!_slang_assemble_function_call_name (A
, "-", op
->children
, 2, GL_FALSE
))
1250 A
->ref
= slang_ref_forbid
;
1252 case slang_oper_multiply
:
1253 if (!_slang_assemble_function_call_name (A
, "*", op
->children
, 2, GL_FALSE
))
1255 A
->ref
= slang_ref_forbid
;
1257 /*case slang_oper_modulus:*/
1258 case slang_oper_divide
:
1259 if (!_slang_assemble_function_call_name (A
, "/", op
->children
, 2, GL_FALSE
))
1261 A
->ref
= slang_ref_forbid
;
1263 case slang_oper_equal
:
1264 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
))
1266 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
1268 if (!equality (A
, op
->children
, GL_TRUE
))
1270 A
->ref
= slang_ref_forbid
;
1272 case slang_oper_notequal
:
1273 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
))
1275 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
1277 if (!equality (A
, op
->children
, GL_FALSE
))
1279 A
->ref
= slang_ref_forbid
;
1281 case slang_oper_preincrement
:
1282 if (!_slang_assemble_assign (A
, op
, "++", ref
))
1285 case slang_oper_predecrement
:
1286 if (!_slang_assemble_assign (A
, op
, "--", ref
))
1289 case slang_oper_plus
:
1290 if (!_slang_dereference (A
, op
))
1292 A
->ref
= slang_ref_forbid
;
1294 case slang_oper_minus
:
1295 if (!_slang_assemble_function_call_name (A
, "-", op
->children
, 1, GL_FALSE
))
1297 A
->ref
= slang_ref_forbid
;
1299 /*case slang_oper_complement:*/
1300 case slang_oper_not
:
1301 if (!_slang_assemble_function_call_name (A
, "!", op
->children
, 1, GL_FALSE
))
1303 A
->ref
= slang_ref_forbid
;
1305 case slang_oper_subscript
:
1307 slang_assembly_typeinfo ti_arr
, ti_elem
;
1309 if (!slang_assembly_typeinfo_construct (&ti_arr
))
1311 if (!slang_assembly_typeinfo_construct (&ti_elem
))
1313 slang_assembly_typeinfo_destruct (&ti_arr
);
1316 if (!handle_subscript (A
, &ti_elem
, &ti_arr
, op
, ref
))
1318 slang_assembly_typeinfo_destruct (&ti_arr
);
1319 slang_assembly_typeinfo_destruct (&ti_elem
);
1322 slang_assembly_typeinfo_destruct (&ti_arr
);
1323 slang_assembly_typeinfo_destruct (&ti_elem
);
1326 case slang_oper_call
:
1328 slang_function
*fun
;
1330 fun
= _slang_locate_function (A
->space
.funcs
, op
->a_id
, op
->children
, op
->num_children
,
1331 &A
->space
, A
->atoms
);
1334 if (!_slang_assemble_constructor (A
, op
))
1339 if (!_slang_assemble_function_call (A
, fun
, op
->children
, op
->num_children
, GL_FALSE
))
1342 A
->ref
= slang_ref_forbid
;
1345 case slang_oper_field
:
1347 slang_assembly_typeinfo ti_after
, ti_before
;
1349 if (!slang_assembly_typeinfo_construct (&ti_after
))
1351 if (!slang_assembly_typeinfo_construct (&ti_before
))
1353 slang_assembly_typeinfo_destruct (&ti_after
);
1356 if (!handle_field (A
, &ti_after
, &ti_before
, op
, ref
))
1358 slang_assembly_typeinfo_destruct (&ti_after
);
1359 slang_assembly_typeinfo_destruct (&ti_before
);
1362 slang_assembly_typeinfo_destruct (&ti_after
);
1363 slang_assembly_typeinfo_destruct (&ti_before
);
1366 case slang_oper_postincrement
:
1367 if (!assemble_function_call_name_dummyint (A
, "++", op
->children
))
1369 A
->ref
= slang_ref_forbid
;
1371 case slang_oper_postdecrement
:
1372 if (!assemble_function_call_name_dummyint (A
, "--", op
->children
))
1374 A
->ref
= slang_ref_forbid
;