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
) {
383 else if (!sizeof_variable (A
, &ti
.spec
, slang_qual_none
, 0, &size
))
385 slang_assembly_typeinfo_destruct (&ti
);
389 slang_assembly_typeinfo_destruct (&ti
);
391 /* if nonzero, free it from the stack */
394 if (!PLAB (A
->file
, slang_asm_local_free
, size
))
401 /* _slang_assemble_operation() */
403 static GLboolean
dereference_aggregate (slang_assemble_ctx
*A
, const slang_storage_aggregate
*agg
,
404 GLuint
*size
, slang_swizzle
*swz
, GLboolean is_swizzled
)
408 for (i
= agg
->count
; i
> 0; i
--)
410 const slang_storage_array
*arr
= &agg
->arrays
[i
- 1];
413 for (j
= arr
->length
; j
> 0; j
--)
415 if (arr
->type
== slang_stor_aggregate
)
417 if (!dereference_aggregate (A
, arr
->aggregate
, size
, swz
, is_swizzled
))
423 slang_assembly_type ty
;
427 /* calculate the offset within source variable to read */
430 /* swizzle the index to get the actual offset */
431 src_offset
= swz
->swizzle
[*size
/ 4] * 4;
435 /* no swizzling - read sequentially */
439 /* dereference data slot of a basic type */
440 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
442 if (!PUSH (A
->file
, slang_asm_addr_deref
))
444 if (!PLAB (A
->file
, slang_asm_addr_push
, src_offset
))
446 if (!PUSH (A
->file
, slang_asm_addr_add
))
451 case slang_stor_bool
:
452 ty
= slang_asm_bool_deref
;
455 ty
= slang_asm_int_deref
;
457 case slang_stor_float
:
458 ty
= slang_asm_float_deref
;
461 _mesa_problem(NULL
, "Unexpected arr->type in dereference_aggregate");
464 if (!PUSH (A
->file
, ty
))
473 GLboolean
_slang_dereference (slang_assemble_ctx
*A
, slang_operation
*op
)
475 slang_assembly_typeinfo ti
;
476 GLboolean result
= GL_FALSE
;
477 slang_storage_aggregate agg
;
480 /* get type information of the given operation */
481 if (!slang_assembly_typeinfo_construct (&ti
))
483 if (!_slang_typeof_operation (A
, op
, &ti
))
486 /* construct aggregate from the type info */
487 if (!slang_storage_aggregate_construct (&agg
))
489 if (!_slang_aggregate_variable (&agg
, &ti
.spec
, ti
.array_len
, A
->space
.funcs
, A
->space
.structs
,
490 A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
))
493 /* dereference the resulting aggregate */
494 size
= _slang_sizeof_aggregate (&agg
);
495 result
= dereference_aggregate (A
, &agg
, &size
, &ti
.swz
, ti
.is_swizzled
);
498 slang_storage_aggregate_destruct (&agg
);
500 slang_assembly_typeinfo_destruct (&ti
);
504 GLboolean
_slang_assemble_function_call (slang_assemble_ctx
*A
, slang_function
*fun
,
505 slang_operation
*params
, GLuint param_count
, GLboolean assignment
)
508 slang_swizzle p_swz
[64];
509 slang_ref_type p_ref
[64];
511 /* TODO: fix this, allocate dynamically */
512 if (param_count
> 64)
515 /* make room for the return value, if any */
516 if (fun
->header
.type
.specifier
.type
!= slang_spec_void
)
520 if (!sizeof_variable (A
, &fun
->header
.type
.specifier
, slang_qual_none
, 0, &ret_size
))
522 if (!PLAB (A
->file
, slang_asm_local_alloc
, ret_size
))
526 /* push the actual parameters on the stack */
527 for (i
= 0; i
< param_count
; i
++)
529 if (fun
->parameters
->variables
[i
].type
.qualifier
== slang_qual_inout
||
530 fun
->parameters
->variables
[i
].type
.qualifier
== slang_qual_out
)
532 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
534 /* TODO: optimize the "out" parameter case */
535 if (!_slang_assemble_operation (A
, ¶ms
[i
], slang_ref_force
))
539 if (!PUSH (A
->file
, slang_asm_addr_copy
))
541 if (!PUSH (A
->file
, slang_asm_addr_deref
))
543 if (i
== 0 && assignment
)
545 /* duplicate the resulting address */
546 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
548 if (!PUSH (A
->file
, slang_asm_addr_deref
))
551 if (!_slang_dereference (A
, ¶ms
[i
]))
556 if (!_slang_assemble_operation (A
, ¶ms
[i
], slang_ref_forbid
))
563 /* call the function */
564 if (!PLAB (A
->file
, slang_asm_call
, fun
->address
))
567 /* pop the parameters from the stack */
568 for (i
= param_count
; i
> 0; i
--)
574 if (fun
->parameters
->variables
[j
].type
.qualifier
== slang_qual_inout
||
575 fun
->parameters
->variables
[j
].type
.qualifier
== slang_qual_out
)
577 /* for output parameter copy the contents of the formal parameter
578 * back to the original actual parameter */
579 if (!_slang_assemble_assignment (A
, ¶ms
[j
]))
581 /* pop the actual parameter's address */
582 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
587 /* pop the value of the parameter */
588 if (!_slang_cleanup_stack (A
, ¶ms
[j
]))
596 GLboolean
_slang_assemble_function_call_name (slang_assemble_ctx
*A
, const char *name
,
597 slang_operation
*params
, GLuint param_count
, GLboolean assignment
)
602 atom
= slang_atom_pool_atom (A
->atoms
, name
);
603 if (atom
== SLANG_ATOM_NULL
)
605 fun
= _slang_locate_function (A
->space
.funcs
, atom
, params
, param_count
, &A
->space
, A
->atoms
);
608 return _slang_assemble_function_call (A
, fun
, params
, param_count
, assignment
);
611 static GLboolean
assemble_function_call_name_dummyint (slang_assemble_ctx
*A
, const char *name
,
612 slang_operation
*params
)
614 slang_operation p
[2];
618 if (!slang_operation_construct (&p
[1]))
620 p
[1].type
= slang_oper_literal_int
;
621 result
= _slang_assemble_function_call_name (A
, name
, p
, 2, GL_FALSE
);
622 slang_operation_destruct (&p
[1]);
629 slang_assembly_type code1
, code2
;
632 { "float_add", slang_asm_float_add
, slang_asm_float_copy
},
633 { "float_multiply", slang_asm_float_multiply
, slang_asm_float_copy
},
634 { "float_divide", slang_asm_float_divide
, slang_asm_float_copy
},
635 { "float_negate", slang_asm_float_negate
, slang_asm_float_copy
},
636 { "float_less", slang_asm_float_less
, slang_asm_bool_copy
},
637 { "float_equal", slang_asm_float_equal_exp
,slang_asm_bool_copy
},
638 { "float_to_int", slang_asm_float_to_int
, slang_asm_int_copy
},
639 { "float_sine", slang_asm_float_sine
, slang_asm_float_copy
},
640 { "float_arcsine", slang_asm_float_arcsine
, slang_asm_float_copy
},
641 { "float_arctan", slang_asm_float_arctan
, slang_asm_float_copy
},
642 { "float_power", slang_asm_float_power
, slang_asm_float_copy
},
643 { "float_log2", slang_asm_float_log2
, slang_asm_float_copy
},
644 { "float_floor", slang_asm_float_floor
, slang_asm_float_copy
},
645 { "float_ceil", slang_asm_float_ceil
, slang_asm_float_copy
},
646 { "float_noise1", slang_asm_float_noise1
, slang_asm_float_copy
},
647 { "float_noise2", slang_asm_float_noise2
, slang_asm_float_copy
},
648 { "float_noise3", slang_asm_float_noise3
, slang_asm_float_copy
},
649 { "float_noise4", slang_asm_float_noise4
, slang_asm_float_copy
},
650 { "int_to_float", slang_asm_int_to_float
, slang_asm_float_copy
},
651 { "vec4_tex2d", slang_asm_vec4_tex2d
, slang_asm_none
},
652 /* mesa-specific extensions */
653 { "float_print", slang_asm_float_deref
, slang_asm_float_print
},
654 { "int_print", slang_asm_int_deref
, slang_asm_int_print
},
655 { "bool_print", slang_asm_bool_deref
, slang_asm_bool_print
},
656 { NULL
, slang_asm_none
, slang_asm_none
}
659 static GLboolean
call_asm_instruction (slang_assemble_ctx
*A
, slang_atom a_name
)
664 id
= slang_atom_pool_id (A
->atoms
, a_name
);
666 for (i
= 0; inst
[i
].name
!= NULL
; i
++)
667 if (slang_string_compare (id
, inst
[i
].name
) == 0)
669 if (inst
[i
].name
== NULL
)
672 if (!PLAB2 (A
->file
, inst
[i
].code1
, 4, 0))
674 if (inst
[i
].code2
!= slang_asm_none
)
675 if (!PLAB2 (A
->file
, inst
[i
].code2
, 4, 0))
678 /* clean-up the stack from the remaining dst address */
679 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
685 static GLboolean
equality_aggregate (slang_assemble_ctx
*A
, const slang_storage_aggregate
*agg
,
686 GLuint
*index
, GLuint size
, GLuint z_label
)
690 for (i
= 0; i
< agg
->count
; i
++)
692 const slang_storage_array
*arr
= &agg
->arrays
[i
];
695 for (j
= 0; j
< arr
->length
; j
++)
697 if (arr
->type
== slang_stor_aggregate
)
699 if (!equality_aggregate (A
, arr
->aggregate
, index
, size
, z_label
))
704 if (!PLAB2 (A
->file
, slang_asm_float_equal_int
, size
+ *index
, *index
))
707 if (!PLAB (A
->file
, slang_asm_jump_if_zero
, z_label
))
716 static GLboolean
equality (slang_assemble_ctx
*A
, slang_operation
*op
, GLboolean equal
)
718 slang_assembly_typeinfo ti
;
719 GLboolean result
= GL_FALSE
;
720 slang_storage_aggregate agg
;
722 GLuint skip_jump
, true_label
, true_jump
, false_label
, false_jump
;
724 /* get type of operation */
725 if (!slang_assembly_typeinfo_construct (&ti
))
727 if (!_slang_typeof_operation (A
, op
, &ti
))
730 /* convert it to an aggregate */
731 if (!slang_storage_aggregate_construct (&agg
))
733 if (!_slang_aggregate_variable (&agg
, &ti
.spec
, 0, A
->space
.funcs
, A
->space
.structs
,
734 A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
))
737 /* compute the size of the agregate - there are two such aggregates on the stack */
738 size
= _slang_sizeof_aggregate (&agg
);
740 /* jump to the actual data-comparison code */
741 skip_jump
= A
->file
->count
;
742 if (!PUSH (A
->file
, slang_asm_jump
))
745 /* pop off the stack the compared data and push 1 */
746 true_label
= A
->file
->count
;
747 if (!PLAB (A
->file
, slang_asm_local_free
, size
* 2))
749 if (!PLIT (A
->file
, slang_asm_bool_push
, (GLfloat
) 1))
751 true_jump
= A
->file
->count
;
752 if (!PUSH (A
->file
, slang_asm_jump
))
755 false_label
= A
->file
->count
;
756 if (!PLAB (A
->file
, slang_asm_local_free
, size
* 2))
758 if (!PLIT (A
->file
, slang_asm_bool_push
, (GLfloat
) 0))
760 false_jump
= A
->file
->count
;
761 if (!PUSH (A
->file
, slang_asm_jump
))
764 A
->file
->code
[skip_jump
].param
[0] = A
->file
->count
;
766 /* compare the data on stack, it will eventually jump either to true or false label */
768 if (!equality_aggregate (A
, &agg
, &index
, size
, equal
? false_label
: true_label
))
770 if (!PLAB (A
->file
, slang_asm_jump
, equal
? true_label
: false_label
))
773 A
->file
->code
[true_jump
].param
[0] = A
->file
->count
;
774 A
->file
->code
[false_jump
].param
[0] = A
->file
->count
;
778 slang_storage_aggregate_destruct (&agg
);
780 slang_assembly_typeinfo_destruct (&ti
);
784 static GLboolean
handle_subscript (slang_assemble_ctx
*A
, slang_assembly_typeinfo
*tie
,
785 slang_assembly_typeinfo
*tia
, slang_operation
*op
, slang_ref_type ref
)
787 GLuint asize
= 0, esize
= 0;
789 /* get type info of the master expression (matrix, vector or an array */
790 if (!_slang_typeof_operation (A
, &op
->children
[0], tia
))
792 if (!sizeof_variable (A
, &tia
->spec
, slang_qual_none
, tia
->array_len
, &asize
))
795 /* get type info of the result (matrix column, vector row or array element) */
796 if (!_slang_typeof_operation (A
, op
, tie
))
798 if (!sizeof_variable (A
, &tie
->spec
, slang_qual_none
, 0, &esize
))
801 /* assemble the master expression */
802 if (!_slang_assemble_operation (A
, &op
->children
[0], ref
))
805 /* when indexing an l-value swizzle, push the swizzle_tmp */
806 if (ref
== slang_ref_force
&& tia
->is_swizzled
)
807 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.swizzle_tmp
, 16))
810 /* assemble the subscript expression */
811 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
814 if (ref
== slang_ref_force
&& tia
->is_swizzled
)
818 /* copy the swizzle indexes to the swizzle_tmp */
819 for (i
= 0; i
< tia
->swz
.num_components
; i
++)
821 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.swizzle_tmp
, 16))
823 if (!PLAB (A
->file
, slang_asm_addr_push
, i
* 4))
825 if (!PUSH (A
->file
, slang_asm_addr_add
))
827 if (!PLAB (A
->file
, slang_asm_addr_push
, tia
->swz
.swizzle
[i
]))
829 if (!PUSH (A
->file
, slang_asm_addr_copy
))
831 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
835 /* offset the pushed swizzle_tmp address and dereference it */
836 if (!PUSH (A
->file
, slang_asm_int_to_addr
))
838 if (!PLAB (A
->file
, slang_asm_addr_push
, 4))
840 if (!PUSH (A
->file
, slang_asm_addr_multiply
))
842 if (!PUSH (A
->file
, slang_asm_addr_add
))
844 if (!PUSH (A
->file
, slang_asm_addr_deref
))
849 /* convert the integer subscript to a relative address */
850 if (!PUSH (A
->file
, slang_asm_int_to_addr
))
854 if (!PLAB (A
->file
, slang_asm_addr_push
, esize
))
856 if (!PUSH (A
->file
, slang_asm_addr_multiply
))
859 if (ref
== slang_ref_force
)
861 /* offset the base address with the relative address */
862 if (!PUSH (A
->file
, slang_asm_addr_add
))
869 /* move the selected element to the beginning of the master expression */
870 for (i
= 0; i
< esize
; i
+= 4)
871 if (!PLAB2 (A
->file
, slang_asm_float_move
, asize
- esize
+ i
+ 4, i
+ 4))
873 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
876 /* free the rest of the master expression */
877 if (!PLAB (A
->file
, slang_asm_local_free
, asize
- esize
))
884 static GLboolean
handle_field (slang_assemble_ctx
*A
, slang_assembly_typeinfo
*tia
,
885 slang_assembly_typeinfo
*tib
, slang_operation
*op
, slang_ref_type ref
)
887 /* get type info of the result (field or swizzle) */
888 if (!_slang_typeof_operation (A
, op
, tia
))
891 /* get type info of the master expression being accessed (struct or vector) */
892 if (!_slang_typeof_operation (A
, &op
->children
[0], tib
))
895 /* if swizzling a vector in-place, the swizzle temporary is needed */
896 if (ref
== slang_ref_forbid
&& tia
->is_swizzled
)
897 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.swizzle_tmp
, 16))
900 /* assemble the master expression */
901 if (!_slang_assemble_operation (A
, &op
->children
[0], ref
))
904 /* assemble the field expression */
905 if (tia
->is_swizzled
)
907 if (ref
== slang_ref_force
)
910 if (tia
->swz
.num_components
== 1)
912 /* simple case - adjust the vector's address to point to the selected component */
913 if (!PLAB (file
, slang_asm_addr_push
, tia
->swz
.swizzle
[0] * 4))
915 if (!PUSH (file
, slang_asm_addr_add
))
921 /* two or more vector components are being referenced - the so-called write mask
922 * must be passed to the upper operations and applied when assigning value
929 /* swizzle the vector in-place using the swizzle temporary */
930 if (!_slang_assemble_constructor_from_swizzle (A
, &tia
->swz
, &tia
->spec
, &tib
->spec
))
936 GLuint i
, struct_size
= 0, field_offset
= 0, field_size
= 0;
938 for (i
= 0; i
< tib
->spec
._struct
->fields
->num_variables
; i
++)
940 slang_variable
*field
;
941 slang_storage_aggregate agg
;
944 field
= &tib
->spec
._struct
->fields
->variables
[i
];
945 if (!slang_storage_aggregate_construct (&agg
))
947 if (!_slang_aggregate_variable (&agg
, &field
->type
.specifier
, field
->array_len
,
948 A
->space
.funcs
, A
->space
.structs
, A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
))
950 slang_storage_aggregate_destruct (&agg
);
953 size
= _slang_sizeof_aggregate (&agg
);
954 slang_storage_aggregate_destruct (&agg
);
956 if (op
->a_id
== field
->a_name
)
959 struct_size
= field_offset
+ size
;
961 else if (struct_size
!= 0)
964 field_offset
+= size
;
967 if (!PLAB (A
->file
, slang_asm_addr_push
, field_offset
))
970 if (ref
== slang_ref_force
)
972 if (!PUSH (A
->file
, slang_asm_addr_add
))
979 /* move the selected element to the beginning of the master expression */
980 for (i
= 0; i
< field_size
; i
+= 4)
981 if (!PLAB2 (A
->file
, slang_asm_float_move
, struct_size
- field_size
+ i
+ 4, i
+ 4))
983 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
986 /* free the rest of the master expression */
987 if (!PLAB (A
->file
, slang_asm_local_free
, struct_size
- field_size
))
995 GLboolean
_slang_assemble_operation (slang_assemble_ctx
*A
, slang_operation
*op
, slang_ref_type ref
)
997 /* set default results */
998 A
->ref
= /*(ref == slang_ref_freelance) ? slang_ref_force : */ref
;
999 A
->swz
.num_components
= 0;
1003 case slang_oper_block_no_new_scope
:
1004 case slang_oper_block_new_scope
:
1008 for (i
= 0; i
< op
->num_children
; i
++)
1010 if (!_slang_assemble_operation (A
, &op
->children
[i
], slang_ref_forbid
/*slang_ref_freelance*/))
1012 if (!_slang_cleanup_stack (A
, &op
->children
[i
]))
1017 case slang_oper_variable_decl
:
1021 for (i
= 0; i
< op
->num_children
; i
++)
1023 /* TODO: perform initialization of op->children[i] */
1024 /* TODO: clean-up stack */
1028 case slang_oper_asm
:
1032 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_force
))
1034 for (i
= 1; i
< op
->num_children
; i
++)
1035 if (!_slang_assemble_operation (A
, &op
->children
[i
], slang_ref_forbid
))
1037 if (!call_asm_instruction (A
, op
->a_id
))
1041 case slang_oper_break
:
1042 if (!PLAB (A
->file
, slang_asm_jump
, A
->flow
.loop_end
))
1045 case slang_oper_continue
:
1046 if (!PLAB (A
->file
, slang_asm_jump
, A
->flow
.loop_start
))
1049 case slang_oper_discard
:
1050 if (!PUSH (A
->file
, slang_asm_discard
))
1052 if (!PUSH (A
->file
, slang_asm_exit
))
1055 case slang_oper_return
:
1056 if (A
->local
.ret_size
!= 0)
1058 /* push the result's address */
1059 if (!PLAB2 (A
->file
, slang_asm_local_addr
, 0, A
->local
.ret_size
))
1061 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
))
1064 A
->swz
.num_components
= 0;
1065 /* assign the operation to the function result (it was reserved on the stack) */
1066 if (!_slang_assemble_assignment (A
, op
->children
))
1069 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
1072 if (!PLAB (A
->file
, slang_asm_jump
, A
->flow
.function_end
))
1075 case slang_oper_expression
:
1076 if (ref
== slang_ref_force
)
1078 if (!_slang_assemble_operation (A
, &op
->children
[0], ref
))
1082 if (!_slang_assemble_if (A
, op
))
1085 case slang_oper_while
:
1086 if (!_slang_assemble_while (A
, op
))
1090 if (!_slang_assemble_do (A
, op
))
1093 case slang_oper_for
:
1094 if (!_slang_assemble_for (A
, op
))
1097 case slang_oper_void
:
1099 case slang_oper_literal_bool
:
1100 if (ref
== slang_ref_force
)
1102 if (!PLIT (A
->file
, slang_asm_bool_push
, op
->literal
))
1104 A
->ref
= slang_ref_forbid
;
1106 case slang_oper_literal_int
:
1107 if (ref
== slang_ref_force
)
1109 if (!PLIT (A
->file
, slang_asm_int_push
, op
->literal
))
1111 A
->ref
= slang_ref_forbid
;
1113 case slang_oper_literal_float
:
1114 if (ref
== slang_ref_force
)
1116 if (!PLIT (A
->file
, slang_asm_float_push
, op
->literal
))
1118 A
->ref
= slang_ref_forbid
;
1120 case slang_oper_identifier
:
1122 slang_variable
*var
;
1125 /* find the variable and calculate its size */
1126 var
= _slang_locate_variable (op
->locals
, op
->a_id
, GL_TRUE
);
1130 if (!sizeof_variable (A
, &var
->type
.specifier
, slang_qual_none
, var
->array_len
, &size
))
1133 /* prepare stack for dereferencing */
1134 if (ref
== slang_ref_forbid
)
1135 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
1138 /* push the variable's address */
1141 if (!PLAB (A
->file
, slang_asm_addr_push
, var
->address
))
1146 if (!PLAB2 (A
->file
, slang_asm_local_addr
, var
->address
, size
))
1150 /* perform the dereference */
1151 if (ref
== slang_ref_forbid
)
1153 if (!PUSH (A
->file
, slang_asm_addr_copy
))
1155 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
1157 if (!_slang_dereference (A
, op
))
1162 case slang_oper_sequence
:
1163 if (ref
== slang_ref_force
)
1165 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
/*slang_ref_freelance*/))
1167 if (!_slang_cleanup_stack (A
, &op
->children
[0]))
1169 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
1171 A
->ref
= slang_ref_forbid
;
1173 case slang_oper_assign
:
1174 if (!_slang_assemble_assign (A
, op
, "=", ref
))
1177 case slang_oper_addassign
:
1178 if (!_slang_assemble_assign (A
, op
, "+=", ref
))
1181 case slang_oper_subassign
:
1182 if (!_slang_assemble_assign (A
, op
, "-=", ref
))
1185 case slang_oper_mulassign
:
1186 if (!_slang_assemble_assign (A
, op
, "*=", ref
))
1189 /*case slang_oper_modassign:*/
1190 /*case slang_oper_lshassign:*/
1191 /*case slang_oper_rshassign:*/
1192 /*case slang_oper_orassign:*/
1193 /*case slang_oper_xorassign:*/
1194 /*case slang_oper_andassign:*/
1195 case slang_oper_divassign
:
1196 if (!_slang_assemble_assign (A
, op
, "/=", ref
))
1199 case slang_oper_select
:
1200 if (!_slang_assemble_select (A
, op
))
1202 A
->ref
= slang_ref_forbid
;
1204 case slang_oper_logicalor
:
1205 if (!_slang_assemble_logicalor (A
, op
))
1207 A
->ref
= slang_ref_forbid
;
1209 case slang_oper_logicaland
:
1210 if (!_slang_assemble_logicaland (A
, op
))
1212 A
->ref
= slang_ref_forbid
;
1214 case slang_oper_logicalxor
:
1215 if (!_slang_assemble_function_call_name (A
, "^^", op
->children
, 2, GL_FALSE
))
1217 A
->ref
= slang_ref_forbid
;
1219 /*case slang_oper_bitor:*/
1220 /*case slang_oper_bitxor:*/
1221 /*case slang_oper_bitand:*/
1222 case slang_oper_less
:
1223 if (!_slang_assemble_function_call_name (A
, "<", op
->children
, 2, GL_FALSE
))
1225 A
->ref
= slang_ref_forbid
;
1227 case slang_oper_greater
:
1228 if (!_slang_assemble_function_call_name (A
, ">", op
->children
, 2, GL_FALSE
))
1230 A
->ref
= slang_ref_forbid
;
1232 case slang_oper_lessequal
:
1233 if (!_slang_assemble_function_call_name (A
, "<=", op
->children
, 2, GL_FALSE
))
1235 A
->ref
= slang_ref_forbid
;
1237 case slang_oper_greaterequal
:
1238 if (!_slang_assemble_function_call_name (A
, ">=", op
->children
, 2, GL_FALSE
))
1240 A
->ref
= slang_ref_forbid
;
1242 /*case slang_oper_lshift:*/
1243 /*case slang_oper_rshift:*/
1244 case slang_oper_add
:
1245 if (!_slang_assemble_function_call_name (A
, "+", op
->children
, 2, GL_FALSE
))
1247 A
->ref
= slang_ref_forbid
;
1249 case slang_oper_subtract
:
1250 if (!_slang_assemble_function_call_name (A
, "-", op
->children
, 2, GL_FALSE
))
1252 A
->ref
= slang_ref_forbid
;
1254 case slang_oper_multiply
:
1255 if (!_slang_assemble_function_call_name (A
, "*", op
->children
, 2, GL_FALSE
))
1257 A
->ref
= slang_ref_forbid
;
1259 /*case slang_oper_modulus:*/
1260 case slang_oper_divide
:
1261 if (!_slang_assemble_function_call_name (A
, "/", op
->children
, 2, GL_FALSE
))
1263 A
->ref
= slang_ref_forbid
;
1265 case slang_oper_equal
:
1266 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
))
1268 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
1270 if (!equality (A
, op
->children
, GL_TRUE
))
1272 A
->ref
= slang_ref_forbid
;
1274 case slang_oper_notequal
:
1275 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
))
1277 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
1279 if (!equality (A
, op
->children
, GL_FALSE
))
1281 A
->ref
= slang_ref_forbid
;
1283 case slang_oper_preincrement
:
1284 if (!_slang_assemble_assign (A
, op
, "++", ref
))
1287 case slang_oper_predecrement
:
1288 if (!_slang_assemble_assign (A
, op
, "--", ref
))
1291 case slang_oper_plus
:
1292 if (!_slang_dereference (A
, op
))
1294 A
->ref
= slang_ref_forbid
;
1296 case slang_oper_minus
:
1297 if (!_slang_assemble_function_call_name (A
, "-", op
->children
, 1, GL_FALSE
))
1299 A
->ref
= slang_ref_forbid
;
1301 /*case slang_oper_complement:*/
1302 case slang_oper_not
:
1303 if (!_slang_assemble_function_call_name (A
, "!", op
->children
, 1, GL_FALSE
))
1305 A
->ref
= slang_ref_forbid
;
1307 case slang_oper_subscript
:
1309 slang_assembly_typeinfo ti_arr
, ti_elem
;
1311 if (!slang_assembly_typeinfo_construct (&ti_arr
))
1313 if (!slang_assembly_typeinfo_construct (&ti_elem
))
1315 slang_assembly_typeinfo_destruct (&ti_arr
);
1318 if (!handle_subscript (A
, &ti_elem
, &ti_arr
, op
, ref
))
1320 slang_assembly_typeinfo_destruct (&ti_arr
);
1321 slang_assembly_typeinfo_destruct (&ti_elem
);
1324 slang_assembly_typeinfo_destruct (&ti_arr
);
1325 slang_assembly_typeinfo_destruct (&ti_elem
);
1328 case slang_oper_call
:
1330 slang_function
*fun
;
1332 fun
= _slang_locate_function (A
->space
.funcs
, op
->a_id
, op
->children
, op
->num_children
,
1333 &A
->space
, A
->atoms
);
1336 if (!_slang_assemble_constructor (A
, op
))
1341 if (!_slang_assemble_function_call (A
, fun
, op
->children
, op
->num_children
, GL_FALSE
))
1344 A
->ref
= slang_ref_forbid
;
1347 case slang_oper_field
:
1349 slang_assembly_typeinfo ti_after
, ti_before
;
1351 if (!slang_assembly_typeinfo_construct (&ti_after
))
1353 if (!slang_assembly_typeinfo_construct (&ti_before
))
1355 slang_assembly_typeinfo_destruct (&ti_after
);
1358 if (!handle_field (A
, &ti_after
, &ti_before
, op
, ref
))
1360 slang_assembly_typeinfo_destruct (&ti_after
);
1361 slang_assembly_typeinfo_destruct (&ti_before
);
1364 slang_assembly_typeinfo_destruct (&ti_after
);
1365 slang_assembly_typeinfo_destruct (&ti_before
);
1368 case slang_oper_postincrement
:
1369 if (!assemble_function_call_name_dummyint (A
, "++", op
->children
))
1371 A
->ref
= slang_ref_forbid
;
1373 case slang_oper_postdecrement
:
1374 if (!assemble_function_call_name_dummyint (A
, "--", op
->children
))
1376 A
->ref
= slang_ref_forbid
;