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"
38 static GLboolean
slang_assembly_construct (slang_assembly
*assem
)
40 assem
->type
= slang_asm_none
;
44 static GLvoid
slang_assembly_destruct (slang_assembly
*assem
)
48 /* slang_assembly_file */
50 GLboolean
slang_assembly_file_construct (slang_assembly_file
*file
)
58 GLvoid
slang_assembly_file_destruct (slang_assembly_file
*file
)
62 for (i
= 0; i
< file
->count
; i
++)
63 slang_assembly_destruct (&file
->code
[i
]);
64 slang_alloc_free (file
->code
);
67 static GLboolean
push_new (slang_assembly_file
*file
)
69 if (file
->count
== file
->capacity
)
73 if (file
->capacity
== 0)
76 n
= file
->capacity
* 2;
77 file
->code
= (slang_assembly
*) slang_alloc_realloc (file
->code
,
78 file
->capacity
* sizeof (slang_assembly
), n
* sizeof (slang_assembly
));
79 if (file
->code
== NULL
)
83 if (!slang_assembly_construct (&file
->code
[file
->count
]))
89 static GLboolean
push_gen (slang_assembly_file
*file
, slang_assembly_type type
, GLfloat literal
,
90 GLuint label
, GLuint size
)
92 slang_assembly
*assem
;
96 assem
= &file
->code
[file
->count
- 1];
98 assem
->literal
= literal
;
99 assem
->param
[0] = label
;
100 assem
->param
[1] = size
;
104 GLboolean
slang_assembly_file_push (slang_assembly_file
*file
, slang_assembly_type type
)
106 return push_gen (file
, type
, (GLfloat
) 0, 0, 0);
109 GLboolean
slang_assembly_file_push_label (slang_assembly_file
*file
, slang_assembly_type type
,
112 return push_gen (file
, type
, (GLfloat
) 0, label
, 0);
115 GLboolean
slang_assembly_file_push_label2 (slang_assembly_file
*file
, slang_assembly_type type
,
116 GLuint label1
, GLuint label2
)
118 return push_gen (file
, type
, (GLfloat
) 0, label1
, label2
);
121 GLboolean
slang_assembly_file_push_literal (slang_assembly_file
*file
, slang_assembly_type type
,
124 return push_gen (file
, type
, literal
, 0, 0);
127 #define PUSH slang_assembly_file_push
128 #define PLAB slang_assembly_file_push_label
129 #define PLAB2 slang_assembly_file_push_label2
130 #define PLIT slang_assembly_file_push_literal
132 /* slang_assembly_file_restore_point */
134 GLboolean
slang_assembly_file_restore_point_save (slang_assembly_file
*file
,
135 slang_assembly_file_restore_point
*point
)
137 point
->count
= file
->count
;
141 GLboolean
slang_assembly_file_restore_point_load (slang_assembly_file
*file
,
142 slang_assembly_file_restore_point
*point
)
146 for (i
= point
->count
; i
< file
->count
; i
++)
147 slang_assembly_destruct (&file
->code
[i
]);
148 file
->count
= point
->count
;
152 /* utility functions */
154 static GLboolean
sizeof_variable (slang_assemble_ctx
*A
, slang_type_specifier
*spec
,
155 slang_type_qualifier qual
, GLuint array_len
, GLuint
*size
)
157 slang_storage_aggregate agg
;
159 /* calculate the size of the variable's aggregate */
160 if (!slang_storage_aggregate_construct (&agg
))
162 if (!_slang_aggregate_variable (&agg
, spec
, array_len
, A
->space
.funcs
, A
->space
.structs
,
163 A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
))
165 slang_storage_aggregate_destruct (&agg
);
168 *size
+= _slang_sizeof_aggregate (&agg
);
169 slang_storage_aggregate_destruct (&agg
);
171 /* for reference variables consider the additional address overhead */
172 if (qual
== slang_qual_out
|| qual
== slang_qual_inout
)
178 static GLboolean
sizeof_variable2 (slang_assemble_ctx
*A
, slang_variable
*var
, GLuint
*size
)
180 var
->address
= *size
;
181 if (var
->type
.qualifier
== slang_qual_out
|| var
->type
.qualifier
== slang_qual_inout
)
183 return sizeof_variable (A
, &var
->type
.specifier
, var
->type
.qualifier
, var
->array_len
, size
);
186 static GLboolean
sizeof_variables (slang_assemble_ctx
*A
, slang_variable_scope
*vars
, GLuint start
,
187 GLuint stop
, GLuint
*size
)
191 for (i
= start
; i
< stop
; i
++)
192 if (!sizeof_variable2 (A
, &vars
->variables
[i
], size
))
197 static GLboolean
collect_locals (slang_assemble_ctx
*A
, slang_operation
*op
, GLuint
*size
)
201 if (!sizeof_variables (A
, op
->locals
, 0, op
->locals
->num_variables
, size
))
203 for (i
= 0; i
< op
->num_children
; i
++)
204 if (!collect_locals (A
, &op
->children
[i
], size
))
209 /* _slang_locate_function() */
211 slang_function
*_slang_locate_function (slang_function_scope
*funcs
, slang_atom a_name
,
212 slang_operation
*params
, GLuint num_params
, slang_assembly_name_space
*space
,
213 slang_atom_pool
*atoms
)
217 for (i
= 0; i
< funcs
->num_functions
; i
++)
220 slang_function
*f
= &funcs
->functions
[i
];
222 if (a_name
!= f
->header
.a_name
)
224 if (f
->param_count
!= num_params
)
226 for (j
= 0; j
< num_params
; j
++)
228 slang_assembly_typeinfo ti
;
230 if (!slang_assembly_typeinfo_construct (&ti
))
232 if (!_slang_typeof_operation_ (¶ms
[j
], space
, &ti
, atoms
))
234 slang_assembly_typeinfo_destruct (&ti
);
237 if (!slang_type_specifier_equal (&ti
.spec
, &f
->parameters
->variables
[j
].type
.specifier
))
239 slang_assembly_typeinfo_destruct (&ti
);
242 slang_assembly_typeinfo_destruct (&ti
);
244 /* "out" and "inout" formal parameter requires the actual parameter to be l-value */
245 if (!ti
.can_be_referenced
&&
246 (f
->parameters
->variables
[j
].type
.qualifier
== slang_qual_out
||
247 f
->parameters
->variables
[j
].type
.qualifier
== slang_qual_inout
))
253 if (funcs
->outer_scope
!= NULL
)
254 return _slang_locate_function (funcs
->outer_scope
, a_name
, params
, num_params
, space
, atoms
);
258 /* _slang_assemble_function() */
260 GLboolean
_slang_assemble_function (slang_assemble_ctx
*A
, slang_function
*fun
)
262 GLuint param_size
, local_size
;
263 GLuint skip
, cleanup
;
265 fun
->address
= A
->file
->count
;
267 if (fun
->body
== NULL
)
269 /* jump to the actual function body - we do not know it, so add the instruction
271 fun
->fixups
.table
= (GLuint
*) slang_alloc_realloc (fun
->fixups
.table
,
272 fun
->fixups
.count
* sizeof (GLuint
), (fun
->fixups
.count
+ 1) * sizeof (GLuint
));
273 if (fun
->fixups
.table
== NULL
)
275 fun
->fixups
.table
[fun
->fixups
.count
] = fun
->address
;
277 if (!PUSH (A
->file
, slang_asm_jump
))
285 /* resolve all fixup table entries and delete it */
286 for (i
= 0; i
< fun
->fixups
.count
; i
++)
287 A
->file
->code
[fun
->fixups
.table
[i
]].param
[0] = fun
->address
;
288 slang_fixup_table_free (&fun
->fixups
);
291 /* At this point traverse function formal parameters and code to calculate
292 * total memory size to be allocated on the stack.
293 * During this process the variables will be assigned local addresses to
294 * reference them in the code.
295 * No storage optimizations are performed so exclusive scopes are not detected and shared. */
297 /* calculate return value size */
299 if (fun
->header
.type
.specifier
.type
!= slang_spec_void
)
300 if (!sizeof_variable (A
, &fun
->header
.type
.specifier
, slang_qual_none
, 0, ¶m_size
))
302 A
->local
.ret_size
= param_size
;
304 /* calculate formal parameter list size */
305 if (!sizeof_variables (A
, fun
->parameters
, 0, fun
->param_count
, ¶m_size
))
308 /* calculate local variables size - take into account the four-byte return address and
309 * temporaries for various tasks (4 for addr and 16 for swizzle temporaries).
310 * these include variables from the formal parameter scope and from the code */
311 A
->local
.addr_tmp
= param_size
+ 4;
312 A
->local
.swizzle_tmp
= param_size
+ 4 + 4;
313 local_size
= param_size
+ 4 + 4 + 16;
314 if (!sizeof_variables (A
, fun
->parameters
, fun
->param_count
, fun
->parameters
->num_variables
,
317 if (!collect_locals (A
, fun
->body
, &local_size
))
320 /* allocate local variable storage */
321 if (!PLAB (A
->file
, slang_asm_local_alloc
, local_size
- param_size
- 4))
324 /* mark a new frame for function variable storage */
325 if (!PLAB (A
->file
, slang_asm_enter
, local_size
))
328 /* jump directly to the actual code */
329 skip
= A
->file
->count
;
330 if (!push_new (A
->file
))
332 A
->file
->code
[skip
].type
= slang_asm_jump
;
334 /* all "return" statements will be directed here */
335 A
->flow
.function_end
= A
->file
->count
;
336 cleanup
= A
->file
->count
;
337 if (!push_new (A
->file
))
339 A
->file
->code
[cleanup
].type
= slang_asm_jump
;
341 /* execute the function body */
342 A
->file
->code
[skip
].param
[0] = A
->file
->count
;
343 if (!_slang_assemble_operation (A
, fun
->body
, /*slang_ref_freelance*/slang_ref_forbid
))
346 /* this is the end of the function - restore the old function frame */
347 A
->file
->code
[cleanup
].param
[0] = A
->file
->count
;
348 if (!PUSH (A
->file
, slang_asm_leave
))
351 /* free local variable storage */
352 if (!PLAB (A
->file
, slang_asm_local_free
, local_size
- param_size
- 4))
355 /* return from the function */
356 if (!PUSH (A
->file
, slang_asm_return
))
362 GLboolean
_slang_cleanup_stack (slang_assemble_ctx
*A
, slang_operation
*op
)
364 slang_assembly_typeinfo ti
;
367 /* get type info of the operation and calculate its size */
368 if (!slang_assembly_typeinfo_construct (&ti
))
370 if (!_slang_typeof_operation (A
, op
, &ti
))
372 slang_assembly_typeinfo_destruct (&ti
);
375 if (ti
.spec
.type
!= slang_spec_void
) {
376 if (A
->ref
== slang_ref_force
) {
379 else if (!sizeof_variable (A
, &ti
.spec
, slang_qual_none
, 0, &size
))
381 slang_assembly_typeinfo_destruct (&ti
);
385 slang_assembly_typeinfo_destruct (&ti
);
387 /* if nonzero, free it from the stack */
390 if (!PLAB (A
->file
, slang_asm_local_free
, size
))
397 /* _slang_assemble_operation() */
399 static GLboolean
dereference_aggregate (slang_assemble_ctx
*A
, const slang_storage_aggregate
*agg
,
400 GLuint
*size
, slang_swizzle
*swz
, GLboolean is_swizzled
)
404 for (i
= agg
->count
; i
> 0; i
--)
406 const slang_storage_array
*arr
= &agg
->arrays
[i
- 1];
409 for (j
= arr
->length
; j
> 0; j
--)
411 if (arr
->type
== slang_stor_aggregate
)
413 if (!dereference_aggregate (A
, arr
->aggregate
, size
, swz
, is_swizzled
))
419 slang_assembly_type ty
;
423 /* calculate the offset within source variable to read */
426 /* swizzle the index to get the actual offset */
427 src_offset
= swz
->swizzle
[*size
/ 4] * 4;
431 /* no swizzling - read sequentially */
435 /* dereference data slot of a basic type */
436 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
438 if (!PUSH (A
->file
, slang_asm_addr_deref
))
440 if (!PLAB (A
->file
, slang_asm_addr_push
, src_offset
))
442 if (!PUSH (A
->file
, slang_asm_addr_add
))
447 case slang_stor_bool
:
448 ty
= slang_asm_bool_deref
;
451 ty
= slang_asm_int_deref
;
453 case slang_stor_float
:
454 ty
= slang_asm_float_deref
;
457 _mesa_problem(NULL
, "Unexpected arr->type in dereference_aggregate");
460 if (!PUSH (A
->file
, ty
))
469 GLboolean
_slang_dereference (slang_assemble_ctx
*A
, slang_operation
*op
)
471 slang_assembly_typeinfo ti
;
472 GLboolean result
= GL_FALSE
;
473 slang_storage_aggregate agg
;
476 /* get type information of the given operation */
477 if (!slang_assembly_typeinfo_construct (&ti
))
479 if (!_slang_typeof_operation (A
, op
, &ti
))
482 /* construct aggregate from the type info */
483 if (!slang_storage_aggregate_construct (&agg
))
485 if (!_slang_aggregate_variable (&agg
, &ti
.spec
, ti
.array_len
, A
->space
.funcs
, A
->space
.structs
,
486 A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
))
489 /* dereference the resulting aggregate */
490 size
= _slang_sizeof_aggregate (&agg
);
491 result
= dereference_aggregate (A
, &agg
, &size
, &ti
.swz
, ti
.is_swizzled
);
494 slang_storage_aggregate_destruct (&agg
);
496 slang_assembly_typeinfo_destruct (&ti
);
500 GLboolean
_slang_assemble_function_call (slang_assemble_ctx
*A
, slang_function
*fun
,
501 slang_operation
*params
, GLuint param_count
, GLboolean assignment
)
504 slang_swizzle p_swz
[64];
505 slang_ref_type p_ref
[64];
507 /* TODO: fix this, allocate dynamically */
508 if (param_count
> 64)
511 /* make room for the return value, if any */
512 if (fun
->header
.type
.specifier
.type
!= slang_spec_void
)
516 if (!sizeof_variable (A
, &fun
->header
.type
.specifier
, slang_qual_none
, 0, &ret_size
))
518 if (!PLAB (A
->file
, slang_asm_local_alloc
, ret_size
))
522 /* push the actual parameters on the stack */
523 for (i
= 0; i
< param_count
; i
++)
525 if (fun
->parameters
->variables
[i
].type
.qualifier
== slang_qual_inout
||
526 fun
->parameters
->variables
[i
].type
.qualifier
== slang_qual_out
)
528 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
530 /* TODO: optimize the "out" parameter case */
531 if (!_slang_assemble_operation (A
, ¶ms
[i
], slang_ref_force
))
535 if (!PUSH (A
->file
, slang_asm_addr_copy
))
537 if (!PUSH (A
->file
, slang_asm_addr_deref
))
539 if (i
== 0 && assignment
)
541 /* duplicate the resulting address */
542 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
544 if (!PUSH (A
->file
, slang_asm_addr_deref
))
547 if (!_slang_dereference (A
, ¶ms
[i
]))
552 if (!_slang_assemble_operation (A
, ¶ms
[i
], slang_ref_forbid
))
559 /* call the function */
560 if (!PLAB (A
->file
, slang_asm_call
, fun
->address
))
563 /* pop the parameters from the stack */
564 for (i
= param_count
; i
> 0; i
--)
570 if (fun
->parameters
->variables
[j
].type
.qualifier
== slang_qual_inout
||
571 fun
->parameters
->variables
[j
].type
.qualifier
== slang_qual_out
)
573 /* for output parameter copy the contents of the formal parameter
574 * back to the original actual parameter */
575 if (!_slang_assemble_assignment (A
, ¶ms
[j
]))
577 /* pop the actual parameter's address */
578 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
583 /* pop the value of the parameter */
584 if (!_slang_cleanup_stack (A
, ¶ms
[j
]))
592 GLboolean
_slang_assemble_function_call_name (slang_assemble_ctx
*A
, const char *name
,
593 slang_operation
*params
, GLuint param_count
, GLboolean assignment
)
598 atom
= slang_atom_pool_atom (A
->atoms
, name
);
599 if (atom
== SLANG_ATOM_NULL
)
601 fun
= _slang_locate_function (A
->space
.funcs
, atom
, params
, param_count
, &A
->space
, A
->atoms
);
604 return _slang_assemble_function_call (A
, fun
, params
, param_count
, assignment
);
607 static GLboolean
assemble_function_call_name_dummyint (slang_assemble_ctx
*A
, const char *name
,
608 slang_operation
*params
)
610 slang_operation p
[2];
614 if (!slang_operation_construct (&p
[1]))
616 p
[1].type
= slang_oper_literal_int
;
617 result
= _slang_assemble_function_call_name (A
, name
, p
, 2, GL_FALSE
);
618 slang_operation_destruct (&p
[1]);
625 slang_assembly_type code1
, code2
;
628 { "float_add", slang_asm_float_add
, slang_asm_float_copy
},
629 { "float_multiply", slang_asm_float_multiply
, slang_asm_float_copy
},
630 { "float_divide", slang_asm_float_divide
, slang_asm_float_copy
},
631 { "float_negate", slang_asm_float_negate
, slang_asm_float_copy
},
632 { "float_less", slang_asm_float_less
, slang_asm_bool_copy
},
633 { "float_equal", slang_asm_float_equal_exp
,slang_asm_bool_copy
},
634 { "float_to_int", slang_asm_float_to_int
, slang_asm_int_copy
},
635 { "float_sine", slang_asm_float_sine
, slang_asm_float_copy
},
636 { "float_arcsine", slang_asm_float_arcsine
, slang_asm_float_copy
},
637 { "float_arctan", slang_asm_float_arctan
, slang_asm_float_copy
},
638 { "float_power", slang_asm_float_power
, slang_asm_float_copy
},
639 { "float_log2", slang_asm_float_log2
, slang_asm_float_copy
},
640 { "float_floor", slang_asm_float_floor
, slang_asm_float_copy
},
641 { "float_ceil", slang_asm_float_ceil
, slang_asm_float_copy
},
642 { "float_noise1", slang_asm_float_noise1
, slang_asm_float_copy
},
643 { "float_noise2", slang_asm_float_noise2
, slang_asm_float_copy
},
644 { "float_noise3", slang_asm_float_noise3
, slang_asm_float_copy
},
645 { "float_noise4", slang_asm_float_noise4
, slang_asm_float_copy
},
646 { "int_to_float", slang_asm_int_to_float
, slang_asm_float_copy
},
647 { "vec4_tex2d", slang_asm_vec4_tex2d
, slang_asm_none
},
648 /* mesa-specific extensions */
649 { "float_print", slang_asm_float_deref
, slang_asm_float_print
},
650 { "int_print", slang_asm_int_deref
, slang_asm_int_print
},
651 { "bool_print", slang_asm_bool_deref
, slang_asm_bool_print
},
652 { NULL
, slang_asm_none
, slang_asm_none
}
655 static GLboolean
call_asm_instruction (slang_assemble_ctx
*A
, slang_atom a_name
)
660 id
= slang_atom_pool_id (A
->atoms
, a_name
);
662 for (i
= 0; inst
[i
].name
!= NULL
; i
++)
663 if (slang_string_compare (id
, inst
[i
].name
) == 0)
665 if (inst
[i
].name
== NULL
)
668 if (!PLAB2 (A
->file
, inst
[i
].code1
, 4, 0))
670 if (inst
[i
].code2
!= slang_asm_none
)
671 if (!PLAB2 (A
->file
, inst
[i
].code2
, 4, 0))
674 /* clean-up the stack from the remaining dst address */
675 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
681 static GLboolean
equality_aggregate (slang_assemble_ctx
*A
, const slang_storage_aggregate
*agg
,
682 GLuint
*index
, GLuint size
, GLuint z_label
)
686 for (i
= 0; i
< agg
->count
; i
++)
688 const slang_storage_array
*arr
= &agg
->arrays
[i
];
691 for (j
= 0; j
< arr
->length
; j
++)
693 if (arr
->type
== slang_stor_aggregate
)
695 if (!equality_aggregate (A
, arr
->aggregate
, index
, size
, z_label
))
700 if (!PLAB2 (A
->file
, slang_asm_float_equal_int
, size
+ *index
, *index
))
703 if (!PLAB (A
->file
, slang_asm_jump_if_zero
, z_label
))
712 static GLboolean
equality (slang_assemble_ctx
*A
, slang_operation
*op
, GLboolean equal
)
714 slang_assembly_typeinfo ti
;
715 GLboolean result
= GL_FALSE
;
716 slang_storage_aggregate agg
;
718 GLuint skip_jump
, true_label
, true_jump
, false_label
, false_jump
;
720 /* get type of operation */
721 if (!slang_assembly_typeinfo_construct (&ti
))
723 if (!_slang_typeof_operation (A
, op
, &ti
))
726 /* convert it to an aggregate */
727 if (!slang_storage_aggregate_construct (&agg
))
729 if (!_slang_aggregate_variable (&agg
, &ti
.spec
, 0, A
->space
.funcs
, A
->space
.structs
,
730 A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
))
733 /* compute the size of the agregate - there are two such aggregates on the stack */
734 size
= _slang_sizeof_aggregate (&agg
);
736 /* jump to the actual data-comparison code */
737 skip_jump
= A
->file
->count
;
738 if (!PUSH (A
->file
, slang_asm_jump
))
741 /* pop off the stack the compared data and push 1 */
742 true_label
= A
->file
->count
;
743 if (!PLAB (A
->file
, slang_asm_local_free
, size
* 2))
745 if (!PLIT (A
->file
, slang_asm_bool_push
, (GLfloat
) 1))
747 true_jump
= A
->file
->count
;
748 if (!PUSH (A
->file
, slang_asm_jump
))
751 false_label
= A
->file
->count
;
752 if (!PLAB (A
->file
, slang_asm_local_free
, size
* 2))
754 if (!PLIT (A
->file
, slang_asm_bool_push
, (GLfloat
) 0))
756 false_jump
= A
->file
->count
;
757 if (!PUSH (A
->file
, slang_asm_jump
))
760 A
->file
->code
[skip_jump
].param
[0] = A
->file
->count
;
762 /* compare the data on stack, it will eventually jump either to true or false label */
764 if (!equality_aggregate (A
, &agg
, &index
, size
, equal
? false_label
: true_label
))
766 if (!PLAB (A
->file
, slang_asm_jump
, equal
? true_label
: false_label
))
769 A
->file
->code
[true_jump
].param
[0] = A
->file
->count
;
770 A
->file
->code
[false_jump
].param
[0] = A
->file
->count
;
774 slang_storage_aggregate_destruct (&agg
);
776 slang_assembly_typeinfo_destruct (&ti
);
780 static GLboolean
handle_subscript (slang_assemble_ctx
*A
, slang_assembly_typeinfo
*tie
,
781 slang_assembly_typeinfo
*tia
, slang_operation
*op
, slang_ref_type ref
)
783 GLuint asize
= 0, esize
= 0;
785 /* get type info of the master expression (matrix, vector or an array */
786 if (!_slang_typeof_operation (A
, &op
->children
[0], tia
))
788 if (!sizeof_variable (A
, &tia
->spec
, slang_qual_none
, tia
->array_len
, &asize
))
791 /* get type info of the result (matrix column, vector row or array element) */
792 if (!_slang_typeof_operation (A
, op
, tie
))
794 if (!sizeof_variable (A
, &tie
->spec
, slang_qual_none
, 0, &esize
))
797 /* assemble the master expression */
798 if (!_slang_assemble_operation (A
, &op
->children
[0], ref
))
801 /* when indexing an l-value swizzle, push the swizzle_tmp */
802 if (ref
== slang_ref_force
&& tia
->is_swizzled
)
803 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.swizzle_tmp
, 16))
806 /* assemble the subscript expression */
807 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
810 if (ref
== slang_ref_force
&& tia
->is_swizzled
)
814 /* copy the swizzle indexes to the swizzle_tmp */
815 for (i
= 0; i
< tia
->swz
.num_components
; i
++)
817 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.swizzle_tmp
, 16))
819 if (!PLAB (A
->file
, slang_asm_addr_push
, i
* 4))
821 if (!PUSH (A
->file
, slang_asm_addr_add
))
823 if (!PLAB (A
->file
, slang_asm_addr_push
, tia
->swz
.swizzle
[i
]))
825 if (!PUSH (A
->file
, slang_asm_addr_copy
))
827 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
831 /* offset the pushed swizzle_tmp address and dereference it */
832 if (!PUSH (A
->file
, slang_asm_int_to_addr
))
834 if (!PLAB (A
->file
, slang_asm_addr_push
, 4))
836 if (!PUSH (A
->file
, slang_asm_addr_multiply
))
838 if (!PUSH (A
->file
, slang_asm_addr_add
))
840 if (!PUSH (A
->file
, slang_asm_addr_deref
))
845 /* convert the integer subscript to a relative address */
846 if (!PUSH (A
->file
, slang_asm_int_to_addr
))
850 if (!PLAB (A
->file
, slang_asm_addr_push
, esize
))
852 if (!PUSH (A
->file
, slang_asm_addr_multiply
))
855 if (ref
== slang_ref_force
)
857 /* offset the base address with the relative address */
858 if (!PUSH (A
->file
, slang_asm_addr_add
))
865 /* move the selected element to the beginning of the master expression */
866 for (i
= 0; i
< esize
; i
+= 4)
867 if (!PLAB2 (A
->file
, slang_asm_float_move
, asize
- esize
+ i
+ 4, i
+ 4))
869 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
872 /* free the rest of the master expression */
873 if (!PLAB (A
->file
, slang_asm_local_free
, asize
- esize
))
880 static GLboolean
handle_field (slang_assemble_ctx
*A
, slang_assembly_typeinfo
*tia
,
881 slang_assembly_typeinfo
*tib
, slang_operation
*op
, slang_ref_type ref
)
883 /* get type info of the result (field or swizzle) */
884 if (!_slang_typeof_operation (A
, op
, tia
))
887 /* get type info of the master expression being accessed (struct or vector) */
888 if (!_slang_typeof_operation (A
, &op
->children
[0], tib
))
891 /* if swizzling a vector in-place, the swizzle temporary is needed */
892 if (ref
== slang_ref_forbid
&& tia
->is_swizzled
)
893 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.swizzle_tmp
, 16))
896 /* assemble the master expression */
897 if (!_slang_assemble_operation (A
, &op
->children
[0], ref
))
900 /* assemble the field expression */
901 if (tia
->is_swizzled
)
903 if (ref
== slang_ref_force
)
906 if (tia
->swz
.num_components
== 1)
908 /* simple case - adjust the vector's address to point to the selected component */
909 if (!PLAB (file
, slang_asm_addr_push
, tia
->swz
.swizzle
[0] * 4))
911 if (!PUSH (file
, slang_asm_addr_add
))
917 /* two or more vector components are being referenced - the so-called write mask
918 * must be passed to the upper operations and applied when assigning value
925 /* swizzle the vector in-place using the swizzle temporary */
926 if (!_slang_assemble_constructor_from_swizzle (A
, &tia
->swz
, &tia
->spec
, &tib
->spec
))
932 GLuint i
, struct_size
= 0, field_offset
= 0, field_size
= 0;
934 for (i
= 0; i
< tib
->spec
._struct
->fields
->num_variables
; i
++)
936 slang_variable
*field
;
937 slang_storage_aggregate agg
;
940 field
= &tib
->spec
._struct
->fields
->variables
[i
];
941 if (!slang_storage_aggregate_construct (&agg
))
943 if (!_slang_aggregate_variable (&agg
, &field
->type
.specifier
, field
->array_len
,
944 A
->space
.funcs
, A
->space
.structs
, A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
))
946 slang_storage_aggregate_destruct (&agg
);
949 size
= _slang_sizeof_aggregate (&agg
);
950 slang_storage_aggregate_destruct (&agg
);
952 if (op
->a_id
== field
->a_name
)
955 struct_size
= field_offset
+ size
;
957 else if (struct_size
!= 0)
960 field_offset
+= size
;
963 if (!PLAB (A
->file
, slang_asm_addr_push
, field_offset
))
966 if (ref
== slang_ref_force
)
968 if (!PUSH (A
->file
, slang_asm_addr_add
))
975 /* move the selected element to the beginning of the master expression */
976 for (i
= 0; i
< field_size
; i
+= 4)
977 if (!PLAB2 (A
->file
, slang_asm_float_move
, struct_size
- field_size
+ i
+ 4, i
+ 4))
979 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
982 /* free the rest of the master expression */
983 if (!PLAB (A
->file
, slang_asm_local_free
, struct_size
- field_size
))
991 GLboolean
_slang_assemble_operation (slang_assemble_ctx
*A
, slang_operation
*op
, slang_ref_type ref
)
993 /* set default results */
994 A
->ref
= /*(ref == slang_ref_freelance) ? slang_ref_force : */ref
;
995 A
->swz
.num_components
= 0;
999 case slang_oper_block_no_new_scope
:
1000 case slang_oper_block_new_scope
:
1004 for (i
= 0; i
< op
->num_children
; i
++)
1006 if (!_slang_assemble_operation (A
, &op
->children
[i
], slang_ref_forbid
/*slang_ref_freelance*/))
1008 if (!_slang_cleanup_stack (A
, &op
->children
[i
]))
1013 case slang_oper_variable_decl
:
1017 for (i
= 0; i
< op
->num_children
; i
++)
1019 /* TODO: perform initialization of op->children[i] */
1020 /* TODO: clean-up stack */
1024 case slang_oper_asm
:
1028 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_force
))
1030 for (i
= 1; i
< op
->num_children
; i
++)
1031 if (!_slang_assemble_operation (A
, &op
->children
[i
], slang_ref_forbid
))
1033 if (!call_asm_instruction (A
, op
->a_id
))
1037 case slang_oper_break
:
1038 if (!PLAB (A
->file
, slang_asm_jump
, A
->flow
.loop_end
))
1041 case slang_oper_continue
:
1042 if (!PLAB (A
->file
, slang_asm_jump
, A
->flow
.loop_start
))
1045 case slang_oper_discard
:
1046 if (!PUSH (A
->file
, slang_asm_discard
))
1048 if (!PUSH (A
->file
, slang_asm_exit
))
1051 case slang_oper_return
:
1052 if (A
->local
.ret_size
!= 0)
1054 /* push the result's address */
1055 if (!PLAB2 (A
->file
, slang_asm_local_addr
, 0, A
->local
.ret_size
))
1057 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
))
1060 A
->swz
.num_components
= 0;
1061 /* assign the operation to the function result (it was reserved on the stack) */
1062 if (!_slang_assemble_assignment (A
, op
->children
))
1065 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
1068 if (!PLAB (A
->file
, slang_asm_jump
, A
->flow
.function_end
))
1071 case slang_oper_expression
:
1072 if (ref
== slang_ref_force
)
1074 if (!_slang_assemble_operation (A
, &op
->children
[0], ref
))
1078 if (!_slang_assemble_if (A
, op
))
1081 case slang_oper_while
:
1082 if (!_slang_assemble_while (A
, op
))
1086 if (!_slang_assemble_do (A
, op
))
1089 case slang_oper_for
:
1090 if (!_slang_assemble_for (A
, op
))
1093 case slang_oper_void
:
1095 case slang_oper_literal_bool
:
1096 if (ref
== slang_ref_force
)
1098 if (!PLIT (A
->file
, slang_asm_bool_push
, op
->literal
))
1100 A
->ref
= slang_ref_forbid
;
1102 case slang_oper_literal_int
:
1103 if (ref
== slang_ref_force
)
1105 if (!PLIT (A
->file
, slang_asm_int_push
, op
->literal
))
1107 A
->ref
= slang_ref_forbid
;
1109 case slang_oper_literal_float
:
1110 if (ref
== slang_ref_force
)
1112 if (!PLIT (A
->file
, slang_asm_float_push
, op
->literal
))
1114 A
->ref
= slang_ref_forbid
;
1116 case slang_oper_identifier
:
1118 slang_variable
*var
;
1121 /* find the variable and calculate its size */
1122 var
= _slang_locate_variable (op
->locals
, op
->a_id
, GL_TRUE
);
1126 if (!sizeof_variable (A
, &var
->type
.specifier
, slang_qual_none
, var
->array_len
, &size
))
1129 /* prepare stack for dereferencing */
1130 if (ref
== slang_ref_forbid
)
1131 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
1134 /* push the variable's address */
1137 if (!PLAB (A
->file
, slang_asm_global_addr
, var
->address
))
1142 if (!PLAB2 (A
->file
, slang_asm_local_addr
, var
->address
, size
))
1146 /* perform the dereference */
1147 if (ref
== slang_ref_forbid
)
1149 if (!PUSH (A
->file
, slang_asm_addr_copy
))
1151 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
1153 if (!_slang_dereference (A
, op
))
1158 case slang_oper_sequence
:
1159 if (ref
== slang_ref_force
)
1161 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
/*slang_ref_freelance*/))
1163 if (!_slang_cleanup_stack (A
, &op
->children
[0]))
1165 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
1167 A
->ref
= slang_ref_forbid
;
1169 case slang_oper_assign
:
1170 if (!_slang_assemble_assign (A
, op
, "=", ref
))
1173 case slang_oper_addassign
:
1174 if (!_slang_assemble_assign (A
, op
, "+=", ref
))
1177 case slang_oper_subassign
:
1178 if (!_slang_assemble_assign (A
, op
, "-=", ref
))
1181 case slang_oper_mulassign
:
1182 if (!_slang_assemble_assign (A
, op
, "*=", ref
))
1185 /*case slang_oper_modassign:*/
1186 /*case slang_oper_lshassign:*/
1187 /*case slang_oper_rshassign:*/
1188 /*case slang_oper_orassign:*/
1189 /*case slang_oper_xorassign:*/
1190 /*case slang_oper_andassign:*/
1191 case slang_oper_divassign
:
1192 if (!_slang_assemble_assign (A
, op
, "/=", ref
))
1195 case slang_oper_select
:
1196 if (!_slang_assemble_select (A
, op
))
1198 A
->ref
= slang_ref_forbid
;
1200 case slang_oper_logicalor
:
1201 if (!_slang_assemble_logicalor (A
, op
))
1203 A
->ref
= slang_ref_forbid
;
1205 case slang_oper_logicaland
:
1206 if (!_slang_assemble_logicaland (A
, op
))
1208 A
->ref
= slang_ref_forbid
;
1210 case slang_oper_logicalxor
:
1211 if (!_slang_assemble_function_call_name (A
, "^^", op
->children
, 2, GL_FALSE
))
1213 A
->ref
= slang_ref_forbid
;
1215 /*case slang_oper_bitor:*/
1216 /*case slang_oper_bitxor:*/
1217 /*case slang_oper_bitand:*/
1218 case slang_oper_less
:
1219 if (!_slang_assemble_function_call_name (A
, "<", op
->children
, 2, GL_FALSE
))
1221 A
->ref
= slang_ref_forbid
;
1223 case slang_oper_greater
:
1224 if (!_slang_assemble_function_call_name (A
, ">", op
->children
, 2, GL_FALSE
))
1226 A
->ref
= slang_ref_forbid
;
1228 case slang_oper_lessequal
:
1229 if (!_slang_assemble_function_call_name (A
, "<=", op
->children
, 2, GL_FALSE
))
1231 A
->ref
= slang_ref_forbid
;
1233 case slang_oper_greaterequal
:
1234 if (!_slang_assemble_function_call_name (A
, ">=", op
->children
, 2, GL_FALSE
))
1236 A
->ref
= slang_ref_forbid
;
1238 /*case slang_oper_lshift:*/
1239 /*case slang_oper_rshift:*/
1240 case slang_oper_add
:
1241 if (!_slang_assemble_function_call_name (A
, "+", op
->children
, 2, GL_FALSE
))
1243 A
->ref
= slang_ref_forbid
;
1245 case slang_oper_subtract
:
1246 if (!_slang_assemble_function_call_name (A
, "-", op
->children
, 2, GL_FALSE
))
1248 A
->ref
= slang_ref_forbid
;
1250 case slang_oper_multiply
:
1251 if (!_slang_assemble_function_call_name (A
, "*", op
->children
, 2, GL_FALSE
))
1253 A
->ref
= slang_ref_forbid
;
1255 /*case slang_oper_modulus:*/
1256 case slang_oper_divide
:
1257 if (!_slang_assemble_function_call_name (A
, "/", op
->children
, 2, GL_FALSE
))
1259 A
->ref
= slang_ref_forbid
;
1261 case slang_oper_equal
:
1262 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
))
1264 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
1266 if (!equality (A
, op
->children
, GL_TRUE
))
1268 A
->ref
= slang_ref_forbid
;
1270 case slang_oper_notequal
:
1271 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
))
1273 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
1275 if (!equality (A
, op
->children
, GL_FALSE
))
1277 A
->ref
= slang_ref_forbid
;
1279 case slang_oper_preincrement
:
1280 if (!_slang_assemble_assign (A
, op
, "++", ref
))
1283 case slang_oper_predecrement
:
1284 if (!_slang_assemble_assign (A
, op
, "--", ref
))
1287 case slang_oper_plus
:
1288 if (!_slang_dereference (A
, op
))
1290 A
->ref
= slang_ref_forbid
;
1292 case slang_oper_minus
:
1293 if (!_slang_assemble_function_call_name (A
, "-", op
->children
, 1, GL_FALSE
))
1295 A
->ref
= slang_ref_forbid
;
1297 /*case slang_oper_complement:*/
1298 case slang_oper_not
:
1299 if (!_slang_assemble_function_call_name (A
, "!", op
->children
, 1, GL_FALSE
))
1301 A
->ref
= slang_ref_forbid
;
1303 case slang_oper_subscript
:
1305 slang_assembly_typeinfo ti_arr
, ti_elem
;
1307 if (!slang_assembly_typeinfo_construct (&ti_arr
))
1309 if (!slang_assembly_typeinfo_construct (&ti_elem
))
1311 slang_assembly_typeinfo_destruct (&ti_arr
);
1314 if (!handle_subscript (A
, &ti_elem
, &ti_arr
, op
, ref
))
1316 slang_assembly_typeinfo_destruct (&ti_arr
);
1317 slang_assembly_typeinfo_destruct (&ti_elem
);
1320 slang_assembly_typeinfo_destruct (&ti_arr
);
1321 slang_assembly_typeinfo_destruct (&ti_elem
);
1324 case slang_oper_call
:
1326 slang_function
*fun
;
1328 fun
= _slang_locate_function (A
->space
.funcs
, op
->a_id
, op
->children
, op
->num_children
,
1329 &A
->space
, A
->atoms
);
1332 if (!_slang_assemble_constructor (A
, op
))
1337 if (!_slang_assemble_function_call (A
, fun
, op
->children
, op
->num_children
, GL_FALSE
))
1340 A
->ref
= slang_ref_forbid
;
1343 case slang_oper_field
:
1345 slang_assembly_typeinfo ti_after
, ti_before
;
1347 if (!slang_assembly_typeinfo_construct (&ti_after
))
1349 if (!slang_assembly_typeinfo_construct (&ti_before
))
1351 slang_assembly_typeinfo_destruct (&ti_after
);
1354 if (!handle_field (A
, &ti_after
, &ti_before
, op
, ref
))
1356 slang_assembly_typeinfo_destruct (&ti_after
);
1357 slang_assembly_typeinfo_destruct (&ti_before
);
1360 slang_assembly_typeinfo_destruct (&ti_after
);
1361 slang_assembly_typeinfo_destruct (&ti_before
);
1364 case slang_oper_postincrement
:
1365 if (!assemble_function_call_name_dummyint (A
, "++", op
->children
))
1367 A
->ref
= slang_ref_forbid
;
1369 case slang_oper_postdecrement
:
1370 if (!assemble_function_call_name_dummyint (A
, "--", op
->children
))
1372 A
->ref
= slang_ref_forbid
;