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_compile.h"*/
35 #include "slang_storage.h"
36 /*#include "slang_assemble_constructor.h"*/
37 #include "slang_assemble_typeinfo.h"
38 #include "slang_assemble_conditional.h"
39 #include "slang_assemble_assignment.h"
40 #include "slang_execute.h"
44 static int slang_assembly_construct (slang_assembly
*assem
)
46 assem
->type
= slang_asm_none
;
50 static void slang_assembly_destruct (slang_assembly
*assem
)
54 /* slang_assembly_file */
56 int slang_assembly_file_construct (slang_assembly_file
*file
)
64 void slang_assembly_file_destruct (slang_assembly_file
*file
)
68 for (i
= 0; i
< file
->count
; i
++)
69 slang_assembly_destruct (&file
->code
[i
]);
70 slang_alloc_free (file
->code
);
73 static int push_new (slang_assembly_file
*file
)
75 if (file
->count
== file
->capacity
)
79 if (file
->capacity
== 0)
82 n
= file
->capacity
* 2;
83 file
->code
= (slang_assembly
*) slang_alloc_realloc (file
->code
,
84 file
->capacity
* sizeof (slang_assembly
), n
* sizeof (slang_assembly
));
85 if (file
->code
== NULL
)
89 if (!slang_assembly_construct (&file
->code
[file
->count
]))
95 static int push_gen (slang_assembly_file
*file
, slang_assembly_type type
, GLfloat literal
,
96 GLuint label
, GLuint size
)
98 slang_assembly
*assem
;
100 if (!push_new (file
))
102 assem
= &file
->code
[file
->count
- 1];
104 assem
->literal
= literal
;
105 assem
->param
[0] = label
;
106 assem
->param
[1] = size
;
110 int slang_assembly_file_push (slang_assembly_file
*file
, slang_assembly_type type
)
112 return push_gen (file
, type
, (GLfloat
) 0, 0, 0);
115 int slang_assembly_file_push_label (slang_assembly_file
*file
, slang_assembly_type type
,
118 return push_gen (file
, type
, (GLfloat
) 0, label
, 0);
121 int slang_assembly_file_push_label2 (slang_assembly_file
*file
, slang_assembly_type type
,
122 GLuint label1
, GLuint label2
)
124 return push_gen (file
, type
, (GLfloat
) 0, label1
, label2
);
127 int slang_assembly_file_push_literal (slang_assembly_file
*file
, slang_assembly_type type
,
130 return push_gen (file
, type
, literal
, 0, 0);
133 #define PUSH slang_assembly_file_push
134 #define PLAB slang_assembly_file_push_label
135 #define PLAB2 slang_assembly_file_push_label2
136 #define PLIT slang_assembly_file_push_literal
138 /* slang_assembly_file_restore_point */
140 int slang_assembly_file_restore_point_save (slang_assembly_file
*file
,
141 slang_assembly_file_restore_point
*point
)
143 point
->count
= file
->count
;
147 int slang_assembly_file_restore_point_load (slang_assembly_file
*file
,
148 slang_assembly_file_restore_point
*point
)
152 for (i
= point
->count
; i
< file
->count
; i
++)
153 slang_assembly_destruct (&file
->code
[i
]);
154 file
->count
= point
->count
;
158 /* utility functions */
160 static int sizeof_variable (slang_type_specifier
*spec
, slang_type_qualifier qual
,
161 slang_operation
*array_size
, slang_assembly_name_space
*space
, unsigned int *size
,
162 slang_machine
*mach
, slang_assembly_file
*pfile
, slang_atom_pool
*atoms
)
164 slang_storage_aggregate agg
;
166 /* calculate the size of the variable's aggregate */
167 if (!slang_storage_aggregate_construct (&agg
))
169 if (!_slang_aggregate_variable (&agg
, spec
, array_size
, space
->funcs
, space
->structs
,
170 space
->vars
, mach
, pfile
, atoms
))
172 slang_storage_aggregate_destruct (&agg
);
175 *size
+= _slang_sizeof_aggregate (&agg
);
176 slang_storage_aggregate_destruct (&agg
);
178 /* for reference variables consider the additional address overhead */
179 if (qual
== slang_qual_out
|| qual
== slang_qual_inout
)
184 static int sizeof_variable2 (slang_variable
*var
, slang_assembly_name_space
*space
,
185 unsigned int *size
, slang_machine
*mach
, slang_assembly_file
*pfile
, slang_atom_pool
*atoms
)
187 var
->address
= *size
;
188 if (var
->type
.qualifier
== slang_qual_out
|| var
->type
.qualifier
== slang_qual_inout
)
190 return sizeof_variable (&var
->type
.specifier
, var
->type
.qualifier
, var
->array_size
, space
,
191 size
, mach
, pfile
, atoms
);
194 static int sizeof_variables (slang_variable_scope
*vars
, unsigned int start
, unsigned int stop
,
195 slang_assembly_name_space
*space
, unsigned int *size
, slang_machine
*mach
,
196 slang_assembly_file
*pfile
, slang_atom_pool
*atoms
)
200 for (i
= start
; i
< stop
; i
++)
201 if (!sizeof_variable2 (&vars
->variables
[i
], space
, size
, mach
, pfile
, atoms
))
206 static int collect_locals (slang_operation
*op
, slang_assembly_name_space
*space
,
207 unsigned int *size
, slang_machine
*mach
, slang_assembly_file
*pfile
, slang_atom_pool
*atoms
)
211 if (!sizeof_variables (op
->locals
, 0, op
->locals
->num_variables
, space
, size
, mach
, pfile
,
214 for (i
= 0; i
< op
->num_children
; i
++)
215 if (!collect_locals (&op
->children
[i
], space
, size
, mach
, pfile
, atoms
))
220 /* _slang_locate_function() */
222 slang_function
*_slang_locate_function (slang_function_scope
*funcs
, slang_atom a_name
,
223 slang_operation
*params
, unsigned int num_params
, slang_assembly_name_space
*space
,
224 slang_atom_pool
*atoms
)
228 for (i
= 0; i
< funcs
->num_functions
; i
++)
231 slang_function
*f
= &funcs
->functions
[i
];
233 if (a_name
!= f
->header
.a_name
)
235 if (f
->param_count
!= num_params
)
237 for (j
= 0; j
< num_params
; j
++)
239 slang_assembly_typeinfo ti
;
241 if (!slang_assembly_typeinfo_construct (&ti
))
243 if (!_slang_typeof_operation (¶ms
[j
], space
, &ti
, atoms
))
245 slang_assembly_typeinfo_destruct (&ti
);
248 if (!slang_type_specifier_equal (&ti
.spec
, &f
->parameters
->variables
[j
].type
.specifier
))
250 slang_assembly_typeinfo_destruct (&ti
);
253 slang_assembly_typeinfo_destruct (&ti
);
255 /* "out" and "inout" formal parameter requires the actual parameter to be l-value */
256 if (!ti
.can_be_referenced
&&
257 (f
->parameters
->variables
[j
].type
.qualifier
== slang_qual_out
||
258 f
->parameters
->variables
[j
].type
.qualifier
== slang_qual_inout
))
264 if (funcs
->outer_scope
!= NULL
)
265 return _slang_locate_function (funcs
->outer_scope
, a_name
, params
, num_params
, space
, atoms
);
269 /* _slang_assemble_function() */
271 int _slang_assemble_function (slang_assemble_ctx
*A
, slang_function
*fun
)
273 unsigned int param_size
, local_size
;
274 unsigned int skip
, cleanup
;
276 fun
->address
= A
->file
->count
;
278 if (fun
->body
== NULL
)
280 /* jump to the actual function body - we do not know it, so add the instruction
282 fun
->fixups
.table
= (GLuint
*) slang_alloc_realloc (fun
->fixups
.table
,
283 fun
->fixups
.count
* sizeof (GLuint
), (fun
->fixups
.count
+ 1) * sizeof (GLuint
));
284 if (fun
->fixups
.table
== NULL
)
286 fun
->fixups
.table
[fun
->fixups
.count
] = fun
->address
;
288 if (!PUSH (A
->file
, slang_asm_jump
))
296 /* resolve all fixup table entries and delete it */
297 for (i
= 0; i
< fun
->fixups
.count
; i
++)
298 A
->file
->code
[fun
->fixups
.table
[i
]].param
[0] = fun
->address
;
299 slang_fixup_table_free (&fun
->fixups
);
302 /* At this point traverse function formal parameters and code to calculate
303 * total memory size to be allocated on the stack.
304 * During this process the variables will be assigned local addresses to
305 * reference them in the code.
306 * No storage optimizations are performed so exclusive scopes are not detected and shared. */
308 /* calculate return value size */
310 if (fun
->header
.type
.specifier
.type
!= slang_spec_void
)
311 if (!sizeof_variable (&fun
->header
.type
.specifier
, slang_qual_none
, NULL
, &A
->space
,
312 ¶m_size
, A
->mach
, A
->file
, A
->atoms
))
314 A
->local
.ret_size
= param_size
;
316 /* calculate formal parameter list size */
317 if (!sizeof_variables (fun
->parameters
, 0, fun
->param_count
, &A
->space
, ¶m_size
, A
->mach
, A
->file
,
321 /* calculate local variables size - take into account the four-byte return address and
322 * temporaries for various tasks (4 for addr and 16 for swizzle temporaries).
323 * these include variables from the formal parameter scope and from the code */
324 A
->local
.addr_tmp
= param_size
+ 4;
325 A
->local
.swizzle_tmp
= param_size
+ 4 + 4;
326 local_size
= param_size
+ 4 + 4 + 16;
327 if (!sizeof_variables (fun
->parameters
, fun
->param_count
, fun
->parameters
->num_variables
, &A
->space
,
328 &local_size
, A
->mach
, A
->file
, A
->atoms
))
330 if (!collect_locals (fun
->body
, &A
->space
, &local_size
, A
->mach
, A
->file
, A
->atoms
))
333 /* allocate local variable storage */
334 if (!PLAB (A
->file
, slang_asm_local_alloc
, local_size
- param_size
- 4))
337 /* mark a new frame for function variable storage */
338 if (!PLAB (A
->file
, slang_asm_enter
, local_size
))
341 /* jump directly to the actual code */
342 skip
= A
->file
->count
;
343 if (!push_new (A
->file
))
345 A
->file
->code
[skip
].type
= slang_asm_jump
;
347 /* all "return" statements will be directed here */
348 A
->flow
.function_end
= A
->file
->count
;
349 cleanup
= A
->file
->count
;
350 if (!push_new (A
->file
))
352 A
->file
->code
[cleanup
].type
= slang_asm_jump
;
354 /* execute the function body */
355 A
->file
->code
[skip
].param
[0] = A
->file
->count
;
356 if (!_slang_assemble_operation_ (A
, fun
->body
, slang_ref_freelance
))
359 /* this is the end of the function - restore the old function frame */
360 A
->file
->code
[cleanup
].param
[0] = A
->file
->count
;
361 if (!PUSH (A
->file
, slang_asm_leave
))
364 /* free local variable storage */
365 if (!PLAB (A
->file
, slang_asm_local_free
, local_size
- param_size
- 4))
368 /* return from the function */
369 if (!PUSH (A
->file
, slang_asm_return
))
374 int _slang_cleanup_stack (slang_assembly_file
*file
, slang_operation
*op
, int ref
,
375 slang_assembly_name_space
*space
, struct slang_machine_
*mach
, slang_atom_pool
*atoms
)
377 slang_assemble_ctx A
;
383 return _slang_cleanup_stack_ (&A
, op
);
386 int _slang_cleanup_stack_ (slang_assemble_ctx
*A
, slang_operation
*op
)
388 slang_assembly_typeinfo ti
;
389 unsigned int size
= 0;
391 /* get type info of the operation and calculate its size */
392 if (!slang_assembly_typeinfo_construct (&ti
))
394 if (!_slang_typeof_operation (op
, &A
->space
, &ti
, A
->atoms
))
396 slang_assembly_typeinfo_destruct (&ti
);
399 if (A
->ref
== slang_ref_force
)
401 else if (ti
.spec
.type
!= slang_spec_void
)
402 if (!sizeof_variable (&ti
.spec
, slang_qual_none
, NULL
, &A
->space
, &size
, A
->mach
, A
->file
, A
->atoms
))
404 slang_assembly_typeinfo_destruct (&ti
);
407 slang_assembly_typeinfo_destruct (&ti
);
409 /* if nonzero, free it from the stack */
412 if (!PLAB (A
->file
, slang_asm_local_free
, size
))
418 /* _slang_assemble_operation() */
420 static int dereference_aggregate (slang_assembly_file
*file
, const slang_storage_aggregate
*agg
,
421 unsigned int *size
, slang_assembly_local_info
*info
, slang_swizzle
*swz
, int is_swizzled
)
425 for (i
= agg
->count
; i
> 0; i
--)
427 const slang_storage_array
*arr
= &agg
->arrays
[i
- 1];
430 for (j
= arr
->length
; j
> 0; j
--)
432 if (arr
->type
== slang_stor_aggregate
)
434 if (!dereference_aggregate (file
, arr
->aggregate
, size
, info
, swz
, is_swizzled
))
439 unsigned int src_offset
;
440 slang_assembly_type ty
;
444 /* calculate the offset within source variable to read */
447 /* swizzle the index to get the actual offset */
448 src_offset
= swz
->swizzle
[*size
/ 4] * 4;
452 /* no swizzling - read sequentially */
456 /* dereference data slot of a basic type */
457 if (!PLAB2 (file
, slang_asm_local_addr
, info
->addr_tmp
, 4))
459 if (!PUSH (file
, slang_asm_addr_deref
))
461 if (!PLAB (file
, slang_asm_addr_push
, src_offset
))
463 if (!PUSH (file
, slang_asm_addr_add
))
468 case slang_stor_bool
:
469 ty
= slang_asm_bool_deref
;
472 ty
= slang_asm_int_deref
;
474 case slang_stor_float
:
475 ty
= slang_asm_float_deref
;
478 _mesa_problem(NULL
, "Unexpected arr->type in dereference_aggregate");
481 if (!PUSH (file
, ty
))
489 int _slang_dereference (slang_assembly_file
*file
, slang_operation
*op
,
490 slang_assembly_name_space
*space
, slang_assembly_local_info
*info
, slang_machine
*mach
,
491 slang_atom_pool
*atoms
)
493 slang_assembly_typeinfo ti
;
495 slang_storage_aggregate agg
;
498 /* get type information of the given operation */
499 if (!slang_assembly_typeinfo_construct (&ti
))
501 if (!_slang_typeof_operation (op
, space
, &ti
, atoms
))
503 slang_assembly_typeinfo_destruct (&ti
);
507 /* construct aggregate from the type info */
508 if (!slang_storage_aggregate_construct (&agg
))
510 slang_assembly_typeinfo_destruct (&ti
);
513 if (!_slang_aggregate_variable (&agg
, &ti
.spec
, ti
.array_size
, space
->funcs
, space
->structs
,
514 space
->vars
, mach
, file
, atoms
))
516 slang_storage_aggregate_destruct (&agg
);
517 slang_assembly_typeinfo_destruct (&ti
);
521 /* dereference the resulting aggregate */
522 size
= _slang_sizeof_aggregate (&agg
);
523 result
= dereference_aggregate (file
, &agg
, &size
, info
, &ti
.swz
, ti
.is_swizzled
);
525 slang_storage_aggregate_destruct (&agg
);
526 slang_assembly_typeinfo_destruct (&ti
);
530 int _slang_assemble_function_call (slang_assemble_ctx
*A
, slang_function
*fun
,
531 slang_operation
*params
, GLuint param_count
, GLboolean assignment
)
534 slang_assembly_stack_info p_stk
[64];
536 /* TODO: fix this, allocate dynamically */
537 if (param_count
> 64)
540 /* make room for the return value, if any */
541 if (fun
->header
.type
.specifier
.type
!= slang_spec_void
)
543 unsigned int ret_size
= 0;
545 if (!sizeof_variable (&fun
->header
.type
.specifier
, slang_qual_none
, NULL
, &A
->space
,
546 &ret_size
, A
->mach
, A
->file
, A
->atoms
))
548 if (!PLAB (A
->file
, slang_asm_local_alloc
, ret_size
))
552 /* push the actual parameters on the stack */
553 for (i
= 0; i
< param_count
; i
++)
555 if (fun
->parameters
->variables
[i
].type
.qualifier
== slang_qual_inout
||
556 fun
->parameters
->variables
[i
].type
.qualifier
== slang_qual_out
)
558 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
560 /* TODO: optimize the "out" parameter case */
561 if (!_slang_assemble_operation_ (A
, ¶ms
[i
], slang_ref_force
))
564 if (!PUSH (A
->file
, slang_asm_addr_copy
))
566 if (!PUSH (A
->file
, slang_asm_addr_deref
))
568 if (i
== 0 && assignment
)
570 /* duplicate the resulting address */
571 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
573 if (!PUSH (A
->file
, slang_asm_addr_deref
))
576 if (!_slang_dereference (A
->file
, ¶ms
[i
], &A
->space
, &A
->local
, A
->mach
, A
->atoms
))
581 if (!_slang_assemble_operation_ (A
, ¶ms
[i
], slang_ref_forbid
))
587 /* call the function */
588 if (!PLAB (A
->file
, slang_asm_call
, fun
->address
))
591 /* pop the parameters from the stack */
592 for (i
= param_count
; i
> 0; i
--)
594 unsigned int j
= i
- 1;
596 if (fun
->parameters
->variables
[j
].type
.qualifier
== slang_qual_inout
||
597 fun
->parameters
->variables
[j
].type
.qualifier
== slang_qual_out
)
599 /* for output parameter copy the contents of the formal parameter
600 * back to the original actual parameter */
602 if (!_slang_assemble_assignment (A
, ¶ms
[j
]))
604 /* pop the actual parameter's address */
605 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
610 /* pop the value of the parameter */
611 if (!_slang_cleanup_stack_ (A
, ¶ms
[j
]))
619 int _slang_assemble_function_call_name (slang_assemble_ctx
*A
, const char *name
,
620 slang_operation
*params
, GLuint param_count
, GLboolean assignment
)
625 atom
= slang_atom_pool_atom (A
->atoms
, name
);
626 if (atom
== SLANG_ATOM_NULL
)
628 fun
= _slang_locate_function (A
->space
.funcs
, atom
, params
, param_count
, &A
->space
, A
->atoms
);
631 return _slang_assemble_function_call (A
, fun
, params
, param_count
, assignment
);
634 static int assemble_function_call_name_dummyint (slang_assemble_ctx
*A
, const char *name
,
635 slang_operation
*params
)
637 slang_operation p
[2];
641 if (!slang_operation_construct (&p
[1]))
643 p
[1].type
= slang_oper_literal_int
;
644 result
= _slang_assemble_function_call_name (A
, name
, p
, 2, GL_FALSE
);
645 slang_operation_destruct (&p
[1]);
652 slang_assembly_type code1
, code2
;
655 { "float_add", slang_asm_float_add
, slang_asm_float_copy
},
656 { "float_multiply", slang_asm_float_multiply
, slang_asm_float_copy
},
657 { "float_divide", slang_asm_float_divide
, slang_asm_float_copy
},
658 { "float_negate", slang_asm_float_negate
, slang_asm_float_copy
},
659 { "float_less", slang_asm_float_less
, slang_asm_bool_copy
},
660 { "float_equal", slang_asm_float_equal_exp
,slang_asm_bool_copy
},
661 { "float_to_int", slang_asm_float_to_int
, slang_asm_int_copy
},
662 { "float_sine", slang_asm_float_sine
, slang_asm_float_copy
},
663 { "float_arcsine", slang_asm_float_arcsine
, slang_asm_float_copy
},
664 { "float_arctan", slang_asm_float_arctan
, slang_asm_float_copy
},
665 { "float_power", slang_asm_float_power
, slang_asm_float_copy
},
666 { "float_log2", slang_asm_float_log2
, slang_asm_float_copy
},
667 { "float_floor", slang_asm_float_floor
, slang_asm_float_copy
},
668 { "float_ceil", slang_asm_float_ceil
, slang_asm_float_copy
},
669 { "int_to_float", slang_asm_int_to_float
, slang_asm_float_copy
},
670 /* mesa-specific extensions */
671 { "float_print", slang_asm_float_deref
, slang_asm_float_print
},
672 { "int_print", slang_asm_int_deref
, slang_asm_int_print
},
673 { "bool_print", slang_asm_bool_deref
, slang_asm_bool_print
},
674 { NULL
, slang_asm_none
, slang_asm_none
}
677 static int call_asm_instruction (slang_assembly_file
*file
, slang_atom a_name
, slang_atom_pool
*atoms
)
682 id
= slang_atom_pool_id (atoms
, a_name
);
684 for (i
= 0; inst
[i
].name
!= NULL
; i
++)
685 if (slang_string_compare (id
, inst
[i
].name
) == 0)
687 if (inst
[i
].name
== NULL
)
690 if (!PLAB2 (file
, inst
[i
].code1
, 4, 0))
692 if (inst
[i
].code2
!= slang_asm_none
)
693 if (!PLAB2 (file
, inst
[i
].code2
, 4, 0))
696 /* clean-up the stack from the remaining dst address */
697 if (!PLAB (file
, slang_asm_local_free
, 4))
703 static int equality_aggregate (slang_assembly_file
*file
, const slang_storage_aggregate
*agg
,
704 unsigned int *index
, unsigned int size
, slang_assembly_local_info
*info
, unsigned int z_label
)
708 for (i
= 0; i
< agg
->count
; i
++)
710 const slang_storage_array
*arr
= &agg
->arrays
[i
];
713 for (j
= 0; j
< arr
->length
; j
++)
715 if (arr
->type
== slang_stor_aggregate
)
717 if (!equality_aggregate (file
, arr
->aggregate
, index
, size
, info
, z_label
))
722 if (!PLAB2 (file
, slang_asm_float_equal_int
, size
+ *index
, *index
))
725 if (!PLAB (file
, slang_asm_jump_if_zero
, z_label
))
733 static int equality (slang_assembly_file
*file
, slang_operation
*op
,
734 slang_assembly_name_space
*space
, slang_assembly_local_info
*info
, int equal
,
735 slang_machine
*mach
, slang_atom_pool
*atoms
)
737 slang_assembly_typeinfo ti
;
739 slang_storage_aggregate agg
;
740 unsigned int index
, size
;
741 unsigned int skip_jump
, true_label
, true_jump
, false_label
, false_jump
;
743 /* get type of operation */
744 if (!slang_assembly_typeinfo_construct (&ti
))
746 if (!_slang_typeof_operation (op
, space
, &ti
, atoms
))
749 /* convert it to an aggregate */
750 if (!slang_storage_aggregate_construct (&agg
))
752 if (!_slang_aggregate_variable (&agg
, &ti
.spec
, NULL
, space
->funcs
, space
->structs
,
753 space
->vars
, mach
, file
, atoms
))
756 /* compute the size of the agregate - there are two such aggregates on the stack */
757 size
= _slang_sizeof_aggregate (&agg
);
759 /* jump to the actual data-comparison code */
760 skip_jump
= file
->count
;
761 if (!PUSH (file
, slang_asm_jump
))
764 /* pop off the stack the compared data and push 1 */
765 true_label
= file
->count
;
766 if (!PLAB (file
, slang_asm_local_free
, size
* 2))
768 if (!PLIT (file
, slang_asm_bool_push
, (GLfloat
) 1))
770 true_jump
= file
->count
;
771 if (!PUSH (file
, slang_asm_jump
))
774 false_label
= file
->count
;
775 if (!PLAB (file
, slang_asm_local_free
, size
* 2))
777 if (!PLIT (file
, slang_asm_bool_push
, (GLfloat
) 0))
779 false_jump
= file
->count
;
780 if (!PUSH (file
, slang_asm_jump
))
783 file
->code
[skip_jump
].param
[0] = file
->count
;
785 /* compare the data on stack, it will eventually jump either to true or false label */
787 if (!equality_aggregate (file
, &agg
, &index
, size
, info
, equal
? false_label
: true_label
))
789 if (!PLAB (file
, slang_asm_jump
, equal
? true_label
: false_label
))
792 file
->code
[true_jump
].param
[0] = file
->count
;
793 file
->code
[false_jump
].param
[0] = file
->count
;
797 slang_storage_aggregate_destruct (&agg
);
799 slang_assembly_typeinfo_destruct (&ti
);
803 static int handle_subscript (slang_assembly_typeinfo
*tie
, slang_assembly_typeinfo
*tia
,
804 slang_assembly_file
*file
, slang_operation
*op
, int reference
, slang_assembly_flow_control
*flow
,
805 slang_assembly_name_space
*space
, slang_assembly_local_info
*info
, slang_machine
*mach
,
806 slang_atom_pool
*atoms
)
808 unsigned int asize
= 0, esize
= 0;
809 slang_assembly_stack_info _stk
;
811 /* get type info of the master expression (matrix, vector or an array */
812 if (!_slang_typeof_operation (&op
->children
[0], space
, tia
, atoms
))
814 if (!sizeof_variable (&tia
->spec
, slang_qual_none
, tia
->array_size
, space
, &asize
, mach
, file
,
818 /* get type info of the result (matrix column, vector row or array element) */
819 if (!_slang_typeof_operation (op
, space
, tie
, atoms
))
821 if (!sizeof_variable (&tie
->spec
, slang_qual_none
, NULL
, space
, &esize
, mach
, file
, atoms
))
824 /* assemble the master expression */
825 if (!_slang_assemble_operation (file
, &op
->children
[0], reference
, flow
, space
, info
, &_stk
,
830 /* when indexing an l-value swizzle, push the swizzle_tmp */
831 if (reference
&& tia
->is_swizzled
)
833 if (!PLAB2 (file
, slang_asm_local_addr
, info
->swizzle_tmp
, 16))
837 /* assemble the subscript expression */
838 if (!_slang_assemble_operation (file
, &op
->children
[1], 0, flow
, space
, info
, &_stk
, mach
, atoms
))
840 /* ignore the _stk */
842 if (reference
&& tia
->is_swizzled
)
846 /* copy the swizzle indexes to the swizzle_tmp */
847 for (i
= 0; i
< tia
->swz
.num_components
; i
++)
849 if (!PLAB2 (file
, slang_asm_local_addr
, info
->swizzle_tmp
, 16))
851 if (!PLAB (file
, slang_asm_addr_push
, i
* 4))
853 if (!PUSH (file
, slang_asm_addr_add
))
855 if (!PLAB (file
, slang_asm_addr_push
, tia
->swz
.swizzle
[i
]))
857 if (!PUSH (file
, slang_asm_addr_copy
))
859 if (!PLAB (file
, slang_asm_local_free
, 4))
863 /* offset the pushed swizzle_tmp address and dereference it */
864 if (!PUSH (file
, slang_asm_int_to_addr
))
866 if (!PLAB (file
, slang_asm_addr_push
, 4))
868 if (!PUSH (file
, slang_asm_addr_multiply
))
870 if (!PUSH (file
, slang_asm_addr_add
))
872 if (!PUSH (file
, slang_asm_addr_deref
))
877 /* convert the integer subscript to a relative address */
878 if (!PUSH (file
, slang_asm_int_to_addr
))
882 if (!PLAB (file
, slang_asm_addr_push
, esize
))
884 if (!PUSH (file
, slang_asm_addr_multiply
))
889 /* offset the base address with the relative address */
890 if (!PUSH (file
, slang_asm_addr_add
))
897 /* move the selected element to the beginning of the master expression */
898 for (i
= 0; i
< esize
; i
+= 4)
899 if (!PLAB2 (file
, slang_asm_float_move
, asize
- esize
+ i
+ 4, i
+ 4))
901 if (!PLAB (file
, slang_asm_local_free
, 4))
904 /* free the rest of the master expression */
905 if (!PLAB (file
, slang_asm_local_free
, asize
- esize
))
911 static int handle_field (slang_assembly_typeinfo
*tia
, slang_assembly_typeinfo
*tib
,
912 slang_assembly_file
*file
, slang_operation
*op
, int reference
, slang_assembly_flow_control
*flow
,
913 slang_assembly_name_space
*space
, slang_assembly_local_info
*info
, slang_assembly_stack_info
*stk
,
914 slang_machine
*mach
, slang_atom_pool
*atoms
)
916 slang_assembly_stack_info _stk
;
918 /* get type info of the result (field or swizzle) */
919 if (!_slang_typeof_operation (op
, space
, tia
, atoms
))
922 /* get type info of the master expression being accessed (struct or vector) */
923 if (!_slang_typeof_operation (&op
->children
[0], space
, tib
, atoms
))
926 /* if swizzling a vector in-place, the swizzle temporary is needed */
927 if (!reference
&& tia
->is_swizzled
)
928 if (!PLAB2 (file
, slang_asm_local_addr
, info
->swizzle_tmp
, 16))
931 /* assemble the master expression */
932 if (!_slang_assemble_operation (file
, &op
->children
[0], reference
, flow
, space
, info
, &_stk
,
935 /* ignore _stk.swizzle - we'll have it in tia->swz */
937 /* assemble the field expression */
938 if (tia
->is_swizzled
)
943 if (tia
->swz
.num_components
== 1)
945 /* simple case - adjust the vector's address to point to the selected component */
946 if (!PLAB (file
, slang_asm_addr_push
, tia
->swz
.swizzle
[0] * 4))
948 if (!PUSH (file
, slang_asm_addr_add
))
954 /* two or more vector components are being referenced - the so-called write mask
955 * must be passed to the upper operations and applied when assigning value
957 stk
->swizzle
= tia
->swz
;
962 /* swizzle the vector in-place using the swizzle temporary */
963 if (!_slang_assemble_constructor_from_swizzle (file
, &tia
->swz
, &tia
->spec
, &tib
->spec
,
970 GLuint i
, struct_size
= 0, field_offset
= 0, field_size
= 0;
972 for (i
= 0; i
< tib
->spec
._struct
->fields
->num_variables
; i
++)
974 slang_variable
*field
;
975 slang_storage_aggregate agg
;
978 field
= &tib
->spec
._struct
->fields
->variables
[i
];
979 if (!slang_storage_aggregate_construct (&agg
))
981 if (!_slang_aggregate_variable (&agg
, &field
->type
.specifier
, field
->array_size
,
982 space
->funcs
, space
->structs
, space
->vars
, mach
, file
, atoms
))
984 slang_storage_aggregate_destruct (&agg
);
987 size
= _slang_sizeof_aggregate (&agg
);
988 slang_storage_aggregate_destruct (&agg
);
990 if (op
->a_id
== field
->a_name
)
993 struct_size
= field_offset
+ size
;
995 else if (struct_size
!= 0)
998 field_offset
+= size
;
1001 if (!PLAB (file
, slang_asm_addr_push
, field_offset
))
1006 if (!PUSH (file
, slang_asm_addr_add
))
1013 /* move the selected element to the beginning of the master expression */
1014 for (i
= 0; i
< field_size
; i
+= 4)
1015 if (!PLAB2 (file
, slang_asm_float_move
, struct_size
- field_size
+ i
+ 4, i
+ 4))
1017 if (!PLAB (file
, slang_asm_local_free
, 4))
1020 /* free the rest of the master expression */
1021 if (!PLAB (file
, slang_asm_local_free
, struct_size
- field_size
))
1028 int _slang_assemble_operation (slang_assembly_file
*file
, struct slang_operation_
*op
, int reference
,
1029 slang_assembly_flow_control
*flow
, slang_assembly_name_space
*space
, slang_assembly_local_info
*info
,
1030 slang_assembly_stack_info
*stk
, struct slang_machine_
*mach
, slang_atom_pool
*atoms
)
1032 slang_assemble_ctx A
;
1040 if (!_slang_assemble_operation_ (&A
, op
, reference
? slang_ref_force
: slang_ref_forbid
))
1046 int _slang_assemble_operation_ (slang_assemble_ctx
*A
, slang_operation
*op
, slang_ref_type ref
)
1049 slang_assembly_stack_info swz
;
1051 assem
= A
->file
->count
;
1052 if (!push_new (A
->file
))
1055 if (ref
== slang_ref_freelance
)
1056 ref
= slang_ref_forbid
;
1058 /* set default results */
1059 A
->ref
= (ref
== slang_ref_freelance
) ? slang_ref_force
: ref
;
1060 swz
.swizzle
.num_components
= 0;
1064 case slang_oper_block_no_new_scope
:
1065 case slang_oper_block_new_scope
:
1069 for (i
= 0; i
< op
->num_children
; i
++)
1071 if (!_slang_assemble_operation_ (A
, &op
->children
[i
], slang_ref_freelance
))
1073 if (!_slang_cleanup_stack_ (A
, &op
->children
[i
]))
1078 case slang_oper_variable_decl
:
1082 for (i
= 0; i
< op
->num_children
; i
++)
1084 /* TODO: perform initialization of op->children[i] */
1085 /* TODO: clean-up stack */
1089 case slang_oper_asm
:
1093 if (!_slang_assemble_operation_ (A
, &op
->children
[0], slang_ref_force
))
1095 for (i
= 1; i
< op
->num_children
; i
++)
1096 if (!_slang_assemble_operation_ (A
, &op
->children
[i
], slang_ref_forbid
))
1098 if (!call_asm_instruction (A
->file
, op
->a_id
, A
->atoms
))
1102 case slang_oper_break
:
1103 A
->file
->code
[assem
].type
= slang_asm_jump
;
1104 A
->file
->code
[assem
].param
[0] = A
->flow
.loop_end
;
1106 case slang_oper_continue
:
1107 A
->file
->code
[assem
].type
= slang_asm_jump
;
1108 A
->file
->code
[assem
].param
[0] = A
->flow
.loop_start
;
1110 case slang_oper_discard
:
1111 A
->file
->code
[assem
].type
= slang_asm_discard
;
1112 if (!PUSH (A
->file
, slang_asm_exit
))
1115 case slang_oper_return
:
1116 if (A
->local
.ret_size
!= 0)
1118 /* push the result's address */
1119 if (!PLAB2 (A
->file
, slang_asm_local_addr
, 0, A
->local
.ret_size
))
1121 if (!_slang_assemble_operation_ (A
, &op
->children
[0], slang_ref_forbid
))
1124 A
->swz
.swizzle
.num_components
= 0;
1125 /* assign the operation to the function result (it was reserved on the stack) */
1126 if (!_slang_assemble_assignment (A
, op
->children
))
1129 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
1132 if (!PLAB (A
->file
, slang_asm_jump
, A
->flow
.function_end
))
1135 case slang_oper_expression
:
1136 if (ref
== slang_ref_force
)
1138 if (!_slang_assemble_operation_ (A
, &op
->children
[0], ref
))
1142 if (!_slang_assemble_if (A
->file
, op
, &A
->flow
, &A
->space
, &A
->local
, A
->mach
, A
->atoms
))
1145 case slang_oper_while
:
1146 if (!_slang_assemble_while (A
->file
, op
, &A
->flow
, &A
->space
, &A
->local
, A
->mach
, A
->atoms
))
1150 if (!_slang_assemble_do (A
->file
, op
, &A
->flow
, &A
->space
, &A
->local
, A
->mach
, A
->atoms
))
1153 case slang_oper_for
:
1154 if (!_slang_assemble_for (A
->file
, op
, &A
->flow
, &A
->space
, &A
->local
, A
->mach
, A
->atoms
))
1157 case slang_oper_void
:
1159 case slang_oper_literal_bool
:
1160 if (ref
== slang_ref_force
)
1162 A
->file
->code
[assem
].type
= slang_asm_bool_push
;
1163 A
->file
->code
[assem
].literal
= op
->literal
;
1164 A
->ref
= slang_ref_forbid
;
1166 case slang_oper_literal_int
:
1167 if (ref
== slang_ref_force
)
1169 A
->file
->code
[assem
].type
= slang_asm_int_push
;
1170 A
->file
->code
[assem
].literal
= op
->literal
;
1171 A
->ref
= slang_ref_forbid
;
1173 case slang_oper_literal_float
:
1174 if (ref
== slang_ref_force
)
1176 A
->file
->code
[assem
].type
= slang_asm_float_push
;
1177 A
->file
->code
[assem
].literal
= op
->literal
;
1178 A
->ref
= slang_ref_forbid
;
1180 case slang_oper_identifier
:
1182 slang_variable
*var
;
1185 /* find the variable and calculate its size */
1186 var
= _slang_locate_variable (op
->locals
, op
->a_id
, 1);
1190 if (!sizeof_variable (&var
->type
.specifier
, slang_qual_none
, var
->array_size
, &A
->space
,
1191 &size
, A
->mach
, A
->file
, A
->atoms
))
1194 /* prepare stack for dereferencing */
1195 if (ref
== slang_ref_forbid
)
1196 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
1199 /* push the variable's address */
1202 if (!PLAB (A
->file
, slang_asm_addr_push
, var
->address
))
1207 if (!PLAB2 (A
->file
, slang_asm_local_addr
, var
->address
, size
))
1211 /* perform the dereference */
1212 if (ref
== slang_ref_forbid
)
1214 if (!PUSH (A
->file
, slang_asm_addr_copy
))
1216 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
1218 if (!_slang_dereference (A
->file
, op
, &A
->space
, &A
->local
, A
->mach
, A
->atoms
))
1223 case slang_oper_sequence
:
1224 if (ref
== slang_ref_force
)
1226 if (!_slang_assemble_operation_ (A
, &op
->children
[0], slang_ref_freelance
))
1228 if (!_slang_cleanup_stack_ (A
, &op
->children
[0]))
1230 if (!_slang_assemble_operation_ (A
, &op
->children
[1], slang_ref_forbid
))
1232 A
->ref
= slang_ref_forbid
;
1234 case slang_oper_assign
:
1235 if (!_slang_assemble_assign (A
, op
, "=", ref
))
1238 case slang_oper_addassign
:
1239 if (!_slang_assemble_assign (A
, op
, "+=", ref
))
1242 case slang_oper_subassign
:
1243 if (!_slang_assemble_assign (A
, op
, "-=", ref
))
1246 case slang_oper_mulassign
:
1247 if (!_slang_assemble_assign (A
, op
, "*=", ref
))
1250 /*case slang_oper_modassign:*/
1251 /*case slang_oper_lshassign:*/
1252 /*case slang_oper_rshassign:*/
1253 /*case slang_oper_orassign:*/
1254 /*case slang_oper_xorassign:*/
1255 /*case slang_oper_andassign:*/
1256 case slang_oper_divassign
:
1257 if (!_slang_assemble_assign (A
, op
, "/=", ref
))
1260 case slang_oper_select
:
1261 if (!_slang_assemble_select (A
->file
, op
, &A
->flow
, &A
->space
, &A
->local
, A
->mach
, A
->atoms
))
1263 A
->ref
= slang_ref_forbid
;
1265 case slang_oper_logicalor
:
1266 if (!_slang_assemble_logicalor (A
->file
, op
, &A
->flow
, &A
->space
, &A
->local
, A
->mach
, A
->atoms
))
1268 A
->ref
= slang_ref_forbid
;
1270 case slang_oper_logicaland
:
1271 if (!_slang_assemble_logicaland (A
->file
, op
, &A
->flow
, &A
->space
, &A
->local
, A
->mach
, A
->atoms
))
1273 A
->ref
= slang_ref_forbid
;
1275 case slang_oper_logicalxor
:
1276 if (!_slang_assemble_function_call_name (A
, "^^", op
->children
, 2, GL_FALSE
))
1278 A
->ref
= slang_ref_forbid
;
1280 /*case slang_oper_bitor:*/
1281 /*case slang_oper_bitxor:*/
1282 /*case slang_oper_bitand:*/
1283 case slang_oper_less
:
1284 if (!_slang_assemble_function_call_name (A
, "<", op
->children
, 2, GL_FALSE
))
1286 A
->ref
= slang_ref_forbid
;
1288 case slang_oper_greater
:
1289 if (!_slang_assemble_function_call_name (A
, ">", op
->children
, 2, GL_FALSE
))
1291 A
->ref
= slang_ref_forbid
;
1293 case slang_oper_lessequal
:
1294 if (!_slang_assemble_function_call_name (A
, "<=", op
->children
, 2, GL_FALSE
))
1296 A
->ref
= slang_ref_forbid
;
1298 case slang_oper_greaterequal
:
1299 if (!_slang_assemble_function_call_name (A
, ">=", op
->children
, 2, GL_FALSE
))
1301 A
->ref
= slang_ref_forbid
;
1303 /*case slang_oper_lshift:*/
1304 /*case slang_oper_rshift:*/
1305 case slang_oper_add
:
1306 if (!_slang_assemble_function_call_name (A
, "+", op
->children
, 2, GL_FALSE
))
1308 A
->ref
= slang_ref_forbid
;
1310 case slang_oper_subtract
:
1311 if (!_slang_assemble_function_call_name (A
, "-", op
->children
, 2, GL_FALSE
))
1313 A
->ref
= slang_ref_forbid
;
1315 case slang_oper_multiply
:
1316 if (!_slang_assemble_function_call_name (A
, "*", op
->children
, 2, GL_FALSE
))
1318 A
->ref
= slang_ref_forbid
;
1320 /*case slang_oper_modulus:*/
1321 case slang_oper_divide
:
1322 if (!_slang_assemble_function_call_name (A
, "/", op
->children
, 2, GL_FALSE
))
1324 A
->ref
= slang_ref_forbid
;
1326 case slang_oper_equal
:
1327 if (!_slang_assemble_operation_ (A
, &op
->children
[0], slang_ref_forbid
))
1329 if (!_slang_assemble_operation_ (A
, &op
->children
[1], slang_ref_forbid
))
1331 if (!equality (A
->file
, op
->children
, &A
->space
, &A
->local
, 1, A
->mach
, A
->atoms
))
1333 A
->ref
= slang_ref_forbid
;
1335 case slang_oper_notequal
:
1336 if (!_slang_assemble_operation_ (A
, &op
->children
[0], slang_ref_forbid
))
1338 if (!_slang_assemble_operation_ (A
, &op
->children
[1], slang_ref_forbid
))
1340 if (!equality (A
->file
, op
->children
, &A
->space
, &A
->local
, 0, A
->mach
, A
->atoms
))
1342 A
->ref
= slang_ref_forbid
;
1344 case slang_oper_preincrement
:
1345 if (!_slang_assemble_assign (A
, op
, "++", ref
))
1348 case slang_oper_predecrement
:
1349 if (!_slang_assemble_assign (A
, op
, "--", ref
))
1352 case slang_oper_plus
:
1353 if (!_slang_dereference (A
->file
, op
, &A
->space
, &A
->local
, A
->mach
, A
->atoms
))
1355 A
->ref
= slang_ref_forbid
;
1357 case slang_oper_minus
:
1358 if (!_slang_assemble_function_call_name (A
, "-", op
->children
, 1, GL_FALSE
))
1360 A
->ref
= slang_ref_forbid
;
1362 /*case slang_oper_complement:*/
1363 case slang_oper_not
:
1364 if (!_slang_assemble_function_call_name (A
, "!", op
->children
, 1, GL_FALSE
))
1366 A
->ref
= slang_ref_forbid
;
1368 case slang_oper_subscript
:
1370 slang_assembly_typeinfo ti_arr
, ti_elem
;
1372 if (!slang_assembly_typeinfo_construct (&ti_arr
))
1374 if (!slang_assembly_typeinfo_construct (&ti_elem
))
1376 slang_assembly_typeinfo_destruct (&ti_arr
);
1379 if (!handle_subscript (&ti_elem
, &ti_arr
, A
->file
, op
, ref
!= slang_ref_forbid
, &A
->flow
, &A
->space
, &A
->local
,
1382 slang_assembly_typeinfo_destruct (&ti_arr
);
1383 slang_assembly_typeinfo_destruct (&ti_elem
);
1386 slang_assembly_typeinfo_destruct (&ti_arr
);
1387 slang_assembly_typeinfo_destruct (&ti_elem
);
1390 case slang_oper_call
:
1392 slang_function
*fun
;
1394 fun
= _slang_locate_function (A
->space
.funcs
, op
->a_id
, op
->children
, op
->num_children
,
1395 &A
->space
, A
->atoms
);
1398 /* if (!_slang_assemble_constructor (file, op, flow, space, info, mach))
1403 if (!_slang_assemble_function_call (A
, fun
, op
->children
, op
->num_children
, GL_FALSE
))
1406 A
->ref
= slang_ref_forbid
;
1409 case slang_oper_field
:
1411 slang_assembly_typeinfo ti_after
, ti_before
;
1413 if (!slang_assembly_typeinfo_construct (&ti_after
))
1415 if (!slang_assembly_typeinfo_construct (&ti_before
))
1417 slang_assembly_typeinfo_destruct (&ti_after
);
1420 if (!handle_field (&ti_after
, &ti_before
, A
->file
, op
, ref
!= slang_ref_forbid
, &A
->flow
, &A
->space
, &A
->local
, &swz
,
1423 slang_assembly_typeinfo_destruct (&ti_after
);
1424 slang_assembly_typeinfo_destruct (&ti_before
);
1427 slang_assembly_typeinfo_destruct (&ti_after
);
1428 slang_assembly_typeinfo_destruct (&ti_before
);
1431 case slang_oper_postincrement
:
1432 if (!assemble_function_call_name_dummyint (A
, "++", op
->children
))
1434 A
->ref
= slang_ref_forbid
;
1436 case slang_oper_postdecrement
:
1437 if (!assemble_function_call_name_dummyint (A
, "--", op
->children
))
1439 A
->ref
= slang_ref_forbid
;