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_tex1d", slang_asm_vec4_tex1d
, slang_asm_none
},
648 { "vec4_tex2d", slang_asm_vec4_tex2d
, slang_asm_none
},
649 { "vec4_tex3d", slang_asm_vec4_tex3d
, slang_asm_none
},
650 { "vec4_texcube", slang_asm_vec4_texcube
, slang_asm_none
},
651 { "vec4_shad1d", slang_asm_vec4_shad1d
, slang_asm_none
},
652 { "vec4_shad2d", slang_asm_vec4_shad2d
, slang_asm_none
},
653 /* mesa-specific extensions */
654 { "float_print", slang_asm_float_deref
, slang_asm_float_print
},
655 { "int_print", slang_asm_int_deref
, slang_asm_int_print
},
656 { "bool_print", slang_asm_bool_deref
, slang_asm_bool_print
},
657 { NULL
, slang_asm_none
, slang_asm_none
}
660 static GLboolean
call_asm_instruction (slang_assemble_ctx
*A
, slang_atom a_name
)
665 id
= slang_atom_pool_id (A
->atoms
, a_name
);
667 for (i
= 0; inst
[i
].name
!= NULL
; i
++)
668 if (slang_string_compare (id
, inst
[i
].name
) == 0)
670 if (inst
[i
].name
== NULL
)
673 if (!PLAB2 (A
->file
, inst
[i
].code1
, 4, 0))
675 if (inst
[i
].code2
!= slang_asm_none
)
676 if (!PLAB2 (A
->file
, inst
[i
].code2
, 4, 0))
679 /* clean-up the stack from the remaining dst address */
680 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
686 static GLboolean
equality_aggregate (slang_assemble_ctx
*A
, const slang_storage_aggregate
*agg
,
687 GLuint
*index
, GLuint size
, GLuint z_label
)
691 for (i
= 0; i
< agg
->count
; i
++)
693 const slang_storage_array
*arr
= &agg
->arrays
[i
];
696 for (j
= 0; j
< arr
->length
; j
++)
698 if (arr
->type
== slang_stor_aggregate
)
700 if (!equality_aggregate (A
, arr
->aggregate
, index
, size
, z_label
))
705 if (!PLAB2 (A
->file
, slang_asm_float_equal_int
, size
+ *index
, *index
))
708 if (!PLAB (A
->file
, slang_asm_jump_if_zero
, z_label
))
717 static GLboolean
equality (slang_assemble_ctx
*A
, slang_operation
*op
, GLboolean equal
)
719 slang_assembly_typeinfo ti
;
720 GLboolean result
= GL_FALSE
;
721 slang_storage_aggregate agg
;
723 GLuint skip_jump
, true_label
, true_jump
, false_label
, false_jump
;
725 /* get type of operation */
726 if (!slang_assembly_typeinfo_construct (&ti
))
728 if (!_slang_typeof_operation (A
, op
, &ti
))
731 /* convert it to an aggregate */
732 if (!slang_storage_aggregate_construct (&agg
))
734 if (!_slang_aggregate_variable (&agg
, &ti
.spec
, 0, A
->space
.funcs
, A
->space
.structs
,
735 A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
))
738 /* compute the size of the agregate - there are two such aggregates on the stack */
739 size
= _slang_sizeof_aggregate (&agg
);
741 /* jump to the actual data-comparison code */
742 skip_jump
= A
->file
->count
;
743 if (!PUSH (A
->file
, slang_asm_jump
))
746 /* pop off the stack the compared data and push 1 */
747 true_label
= A
->file
->count
;
748 if (!PLAB (A
->file
, slang_asm_local_free
, size
* 2))
750 if (!PLIT (A
->file
, slang_asm_bool_push
, (GLfloat
) 1))
752 true_jump
= A
->file
->count
;
753 if (!PUSH (A
->file
, slang_asm_jump
))
756 false_label
= A
->file
->count
;
757 if (!PLAB (A
->file
, slang_asm_local_free
, size
* 2))
759 if (!PLIT (A
->file
, slang_asm_bool_push
, (GLfloat
) 0))
761 false_jump
= A
->file
->count
;
762 if (!PUSH (A
->file
, slang_asm_jump
))
765 A
->file
->code
[skip_jump
].param
[0] = A
->file
->count
;
767 /* compare the data on stack, it will eventually jump either to true or false label */
769 if (!equality_aggregate (A
, &agg
, &index
, size
, equal
? false_label
: true_label
))
771 if (!PLAB (A
->file
, slang_asm_jump
, equal
? true_label
: false_label
))
774 A
->file
->code
[true_jump
].param
[0] = A
->file
->count
;
775 A
->file
->code
[false_jump
].param
[0] = A
->file
->count
;
779 slang_storage_aggregate_destruct (&agg
);
781 slang_assembly_typeinfo_destruct (&ti
);
785 static GLboolean
handle_subscript (slang_assemble_ctx
*A
, slang_assembly_typeinfo
*tie
,
786 slang_assembly_typeinfo
*tia
, slang_operation
*op
, slang_ref_type ref
)
788 GLuint asize
= 0, esize
= 0;
790 /* get type info of the master expression (matrix, vector or an array */
791 if (!_slang_typeof_operation (A
, &op
->children
[0], tia
))
793 if (!sizeof_variable (A
, &tia
->spec
, slang_qual_none
, tia
->array_len
, &asize
))
796 /* get type info of the result (matrix column, vector row or array element) */
797 if (!_slang_typeof_operation (A
, op
, tie
))
799 if (!sizeof_variable (A
, &tie
->spec
, slang_qual_none
, 0, &esize
))
802 /* assemble the master expression */
803 if (!_slang_assemble_operation (A
, &op
->children
[0], ref
))
806 /* when indexing an l-value swizzle, push the swizzle_tmp */
807 if (ref
== slang_ref_force
&& tia
->is_swizzled
)
808 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.swizzle_tmp
, 16))
811 /* assemble the subscript expression */
812 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
815 if (ref
== slang_ref_force
&& tia
->is_swizzled
)
819 /* copy the swizzle indexes to the swizzle_tmp */
820 for (i
= 0; i
< tia
->swz
.num_components
; i
++)
822 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.swizzle_tmp
, 16))
824 if (!PLAB (A
->file
, slang_asm_addr_push
, i
* 4))
826 if (!PUSH (A
->file
, slang_asm_addr_add
))
828 if (!PLAB (A
->file
, slang_asm_addr_push
, tia
->swz
.swizzle
[i
]))
830 if (!PUSH (A
->file
, slang_asm_addr_copy
))
832 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
836 /* offset the pushed swizzle_tmp address and dereference it */
837 if (!PUSH (A
->file
, slang_asm_int_to_addr
))
839 if (!PLAB (A
->file
, slang_asm_addr_push
, 4))
841 if (!PUSH (A
->file
, slang_asm_addr_multiply
))
843 if (!PUSH (A
->file
, slang_asm_addr_add
))
845 if (!PUSH (A
->file
, slang_asm_addr_deref
))
850 /* convert the integer subscript to a relative address */
851 if (!PUSH (A
->file
, slang_asm_int_to_addr
))
855 if (!PLAB (A
->file
, slang_asm_addr_push
, esize
))
857 if (!PUSH (A
->file
, slang_asm_addr_multiply
))
860 if (ref
== slang_ref_force
)
862 /* offset the base address with the relative address */
863 if (!PUSH (A
->file
, slang_asm_addr_add
))
870 /* move the selected element to the beginning of the master expression */
871 for (i
= 0; i
< esize
; i
+= 4)
872 if (!PLAB2 (A
->file
, slang_asm_float_move
, asize
- esize
+ i
+ 4, i
+ 4))
874 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
877 /* free the rest of the master expression */
878 if (!PLAB (A
->file
, slang_asm_local_free
, asize
- esize
))
885 static GLboolean
handle_field (slang_assemble_ctx
*A
, slang_assembly_typeinfo
*tia
,
886 slang_assembly_typeinfo
*tib
, slang_operation
*op
, slang_ref_type ref
)
888 /* get type info of the result (field or swizzle) */
889 if (!_slang_typeof_operation (A
, op
, tia
))
892 /* get type info of the master expression being accessed (struct or vector) */
893 if (!_slang_typeof_operation (A
, &op
->children
[0], tib
))
896 /* if swizzling a vector in-place, the swizzle temporary is needed */
897 if (ref
== slang_ref_forbid
&& tia
->is_swizzled
)
898 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.swizzle_tmp
, 16))
901 /* assemble the master expression */
902 if (!_slang_assemble_operation (A
, &op
->children
[0], ref
))
905 /* assemble the field expression */
906 if (tia
->is_swizzled
)
908 if (ref
== slang_ref_force
)
911 if (tia
->swz
.num_components
== 1)
913 /* simple case - adjust the vector's address to point to the selected component */
914 if (!PLAB (file
, slang_asm_addr_push
, tia
->swz
.swizzle
[0] * 4))
916 if (!PUSH (file
, slang_asm_addr_add
))
922 /* two or more vector components are being referenced - the so-called write mask
923 * must be passed to the upper operations and applied when assigning value
930 /* swizzle the vector in-place using the swizzle temporary */
931 if (!_slang_assemble_constructor_from_swizzle (A
, &tia
->swz
, &tia
->spec
, &tib
->spec
))
937 GLuint i
, struct_size
= 0, field_offset
= 0, field_size
= 0;
938 GLboolean relocate
, shrink
;
940 /* calculate struct size, field offset and field size */
941 for (i
= 0; i
< tib
->spec
._struct
->fields
->num_variables
; i
++)
943 slang_variable
*field
;
944 slang_storage_aggregate agg
;
947 field
= &tib
->spec
._struct
->fields
->variables
[i
];
948 if (!slang_storage_aggregate_construct (&agg
))
950 if (!_slang_aggregate_variable (&agg
, &field
->type
.specifier
, field
->array_len
,
951 A
->space
.funcs
, A
->space
.structs
, A
->space
.vars
, A
->mach
, A
->file
, A
->atoms
))
953 slang_storage_aggregate_destruct (&agg
);
956 size
= _slang_sizeof_aggregate (&agg
);
957 slang_storage_aggregate_destruct (&agg
);
959 if (op
->a_id
== field
->a_name
)
962 struct_size
= field_offset
+ size
;
964 else if (struct_size
!= 0)
967 field_offset
+= size
;
971 * OPTIMIZATION: If selecting the last field, no relocation is needed.
973 relocate
= field_offset
!= struct_size
- field_size
;
976 * OPTIMIZATION: If field and struct sizes are equal, no partial free is needed.
978 shrink
= field_size
!= struct_size
;
982 if (!PLAB (A
->file
, slang_asm_addr_push
, field_offset
))
986 if (ref
== slang_ref_force
)
990 if (!PUSH (A
->file
, slang_asm_addr_add
))
1002 /* move the selected element to the beginning of the master expression */
1003 for (i
= 0; i
< field_size
; i
+= 4)
1004 if (!PLAB2 (A
->file
, slang_asm_float_move
, struct_size
- field_size
+ i
+ 4, i
+ 4))
1011 /* free the rest of the master expression */
1012 free_b
+= struct_size
- field_size
;
1017 if (!PLAB (A
->file
, slang_asm_local_free
, free_b
))
1026 GLboolean
_slang_assemble_operation (slang_assemble_ctx
*A
, slang_operation
*op
, slang_ref_type ref
)
1028 /* set default results */
1029 A
->ref
= /*(ref == slang_ref_freelance) ? slang_ref_force : */ref
;
1030 A
->swz
.num_components
= 0;
1034 case slang_oper_block_no_new_scope
:
1035 case slang_oper_block_new_scope
:
1039 for (i
= 0; i
< op
->num_children
; i
++)
1041 if (!_slang_assemble_operation (A
, &op
->children
[i
], slang_ref_forbid
/*slang_ref_freelance*/))
1043 if (!_slang_cleanup_stack (A
, &op
->children
[i
]))
1048 case slang_oper_variable_decl
:
1052 for (i
= 0; i
< op
->num_children
; i
++)
1054 /* TODO: perform initialization of op->children[i] */
1055 /* TODO: clean-up stack */
1059 case slang_oper_asm
:
1063 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_force
))
1065 for (i
= 1; i
< op
->num_children
; i
++)
1066 if (!_slang_assemble_operation (A
, &op
->children
[i
], slang_ref_forbid
))
1068 if (!call_asm_instruction (A
, op
->a_id
))
1072 case slang_oper_break
:
1073 if (!PLAB (A
->file
, slang_asm_jump
, A
->flow
.loop_end
))
1076 case slang_oper_continue
:
1077 if (!PLAB (A
->file
, slang_asm_jump
, A
->flow
.loop_start
))
1080 case slang_oper_discard
:
1081 if (!PUSH (A
->file
, slang_asm_discard
))
1083 if (!PUSH (A
->file
, slang_asm_exit
))
1086 case slang_oper_return
:
1087 if (A
->local
.ret_size
!= 0)
1089 /* push the result's address */
1090 if (!PLAB2 (A
->file
, slang_asm_local_addr
, 0, A
->local
.ret_size
))
1092 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
))
1095 A
->swz
.num_components
= 0;
1096 /* assign the operation to the function result (it was reserved on the stack) */
1097 if (!_slang_assemble_assignment (A
, op
->children
))
1100 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
1103 if (!PLAB (A
->file
, slang_asm_jump
, A
->flow
.function_end
))
1106 case slang_oper_expression
:
1107 if (ref
== slang_ref_force
)
1109 if (!_slang_assemble_operation (A
, &op
->children
[0], ref
))
1113 if (!_slang_assemble_if (A
, op
))
1116 case slang_oper_while
:
1117 if (!_slang_assemble_while (A
, op
))
1121 if (!_slang_assemble_do (A
, op
))
1124 case slang_oper_for
:
1125 if (!_slang_assemble_for (A
, op
))
1128 case slang_oper_void
:
1130 case slang_oper_literal_bool
:
1131 if (ref
== slang_ref_force
)
1133 if (!PLIT (A
->file
, slang_asm_bool_push
, op
->literal
))
1135 A
->ref
= slang_ref_forbid
;
1137 case slang_oper_literal_int
:
1138 if (ref
== slang_ref_force
)
1140 if (!PLIT (A
->file
, slang_asm_int_push
, op
->literal
))
1142 A
->ref
= slang_ref_forbid
;
1144 case slang_oper_literal_float
:
1145 if (ref
== slang_ref_force
)
1147 if (!PLIT (A
->file
, slang_asm_float_push
, op
->literal
))
1149 A
->ref
= slang_ref_forbid
;
1151 case slang_oper_identifier
:
1153 slang_variable
*var
;
1156 /* find the variable and calculate its size */
1157 var
= _slang_locate_variable (op
->locals
, op
->a_id
, GL_TRUE
);
1161 if (!sizeof_variable (A
, &var
->type
.specifier
, slang_qual_none
, var
->array_len
, &size
))
1164 /* prepare stack for dereferencing */
1165 if (ref
== slang_ref_forbid
)
1166 if (!PLAB2 (A
->file
, slang_asm_local_addr
, A
->local
.addr_tmp
, 4))
1169 /* push the variable's address */
1172 if (!PLAB (A
->file
, slang_asm_global_addr
, var
->address
))
1177 if (!PLAB2 (A
->file
, slang_asm_local_addr
, var
->address
, size
))
1181 /* perform the dereference */
1182 if (ref
== slang_ref_forbid
)
1184 if (!PUSH (A
->file
, slang_asm_addr_copy
))
1186 if (!PLAB (A
->file
, slang_asm_local_free
, 4))
1188 if (!_slang_dereference (A
, op
))
1193 case slang_oper_sequence
:
1194 if (ref
== slang_ref_force
)
1196 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
/*slang_ref_freelance*/))
1198 if (!_slang_cleanup_stack (A
, &op
->children
[0]))
1200 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
1202 A
->ref
= slang_ref_forbid
;
1204 case slang_oper_assign
:
1205 if (!_slang_assemble_assign (A
, op
, "=", ref
))
1208 case slang_oper_addassign
:
1209 if (!_slang_assemble_assign (A
, op
, "+=", ref
))
1213 case slang_oper_subassign
:
1214 if (!_slang_assemble_assign (A
, op
, "-=", ref
))
1218 case slang_oper_mulassign
:
1219 if (!_slang_assemble_assign (A
, op
, "*=", ref
))
1223 /*case slang_oper_modassign:*/
1224 /*case slang_oper_lshassign:*/
1225 /*case slang_oper_rshassign:*/
1226 /*case slang_oper_orassign:*/
1227 /*case slang_oper_xorassign:*/
1228 /*case slang_oper_andassign:*/
1229 case slang_oper_divassign
:
1230 if (!_slang_assemble_assign (A
, op
, "/=", ref
))
1234 case slang_oper_select
:
1235 if (!_slang_assemble_select (A
, op
))
1237 A
->ref
= slang_ref_forbid
;
1239 case slang_oper_logicalor
:
1240 if (!_slang_assemble_logicalor (A
, op
))
1242 A
->ref
= slang_ref_forbid
;
1244 case slang_oper_logicaland
:
1245 if (!_slang_assemble_logicaland (A
, op
))
1247 A
->ref
= slang_ref_forbid
;
1249 case slang_oper_logicalxor
:
1250 if (!_slang_assemble_function_call_name (A
, "^^", op
->children
, 2, GL_FALSE
))
1252 A
->ref
= slang_ref_forbid
;
1254 /*case slang_oper_bitor:*/
1255 /*case slang_oper_bitxor:*/
1256 /*case slang_oper_bitand:*/
1257 case slang_oper_less
:
1258 if (!_slang_assemble_function_call_name (A
, "<", op
->children
, 2, GL_FALSE
))
1260 A
->ref
= slang_ref_forbid
;
1262 case slang_oper_greater
:
1263 if (!_slang_assemble_function_call_name (A
, ">", op
->children
, 2, GL_FALSE
))
1265 A
->ref
= slang_ref_forbid
;
1267 case slang_oper_lessequal
:
1268 if (!_slang_assemble_function_call_name (A
, "<=", op
->children
, 2, GL_FALSE
))
1270 A
->ref
= slang_ref_forbid
;
1272 case slang_oper_greaterequal
:
1273 if (!_slang_assemble_function_call_name (A
, ">=", op
->children
, 2, GL_FALSE
))
1275 A
->ref
= slang_ref_forbid
;
1277 /*case slang_oper_lshift:*/
1278 /*case slang_oper_rshift:*/
1279 case slang_oper_add
:
1280 if (!_slang_assemble_function_call_name (A
, "+", op
->children
, 2, GL_FALSE
))
1282 A
->ref
= slang_ref_forbid
;
1284 case slang_oper_subtract
:
1285 if (!_slang_assemble_function_call_name (A
, "-", op
->children
, 2, GL_FALSE
))
1287 A
->ref
= slang_ref_forbid
;
1289 case slang_oper_multiply
:
1290 if (!_slang_assemble_function_call_name (A
, "*", op
->children
, 2, GL_FALSE
))
1292 A
->ref
= slang_ref_forbid
;
1294 /*case slang_oper_modulus:*/
1295 case slang_oper_divide
:
1296 if (!_slang_assemble_function_call_name (A
, "/", op
->children
, 2, GL_FALSE
))
1298 A
->ref
= slang_ref_forbid
;
1300 case slang_oper_equal
:
1301 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
))
1303 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
1305 if (!equality (A
, op
->children
, GL_TRUE
))
1307 A
->ref
= slang_ref_forbid
;
1309 case slang_oper_notequal
:
1310 if (!_slang_assemble_operation (A
, &op
->children
[0], slang_ref_forbid
))
1312 if (!_slang_assemble_operation (A
, &op
->children
[1], slang_ref_forbid
))
1314 if (!equality (A
, op
->children
, GL_FALSE
))
1316 A
->ref
= slang_ref_forbid
;
1318 case slang_oper_preincrement
:
1319 if (!_slang_assemble_assign (A
, op
, "++", ref
))
1323 case slang_oper_predecrement
:
1324 if (!_slang_assemble_assign (A
, op
, "--", ref
))
1328 case slang_oper_plus
:
1329 if (!_slang_dereference (A
, op
))
1331 A
->ref
= slang_ref_forbid
;
1333 case slang_oper_minus
:
1334 if (!_slang_assemble_function_call_name (A
, "-", op
->children
, 1, GL_FALSE
))
1336 A
->ref
= slang_ref_forbid
;
1338 /*case slang_oper_complement:*/
1339 case slang_oper_not
:
1340 if (!_slang_assemble_function_call_name (A
, "!", op
->children
, 1, GL_FALSE
))
1342 A
->ref
= slang_ref_forbid
;
1344 case slang_oper_subscript
:
1346 slang_assembly_typeinfo ti_arr
, ti_elem
;
1348 if (!slang_assembly_typeinfo_construct (&ti_arr
))
1350 if (!slang_assembly_typeinfo_construct (&ti_elem
))
1352 slang_assembly_typeinfo_destruct (&ti_arr
);
1355 if (!handle_subscript (A
, &ti_elem
, &ti_arr
, op
, ref
))
1357 slang_assembly_typeinfo_destruct (&ti_arr
);
1358 slang_assembly_typeinfo_destruct (&ti_elem
);
1361 slang_assembly_typeinfo_destruct (&ti_arr
);
1362 slang_assembly_typeinfo_destruct (&ti_elem
);
1365 case slang_oper_call
:
1367 slang_function
*fun
;
1369 fun
= _slang_locate_function (A
->space
.funcs
, op
->a_id
, op
->children
, op
->num_children
,
1370 &A
->space
, A
->atoms
);
1373 if (!_slang_assemble_constructor (A
, op
))
1378 if (!_slang_assemble_function_call (A
, fun
, op
->children
, op
->num_children
, GL_FALSE
))
1381 A
->ref
= slang_ref_forbid
;
1384 case slang_oper_field
:
1386 slang_assembly_typeinfo ti_after
, ti_before
;
1388 if (!slang_assembly_typeinfo_construct (&ti_after
))
1390 if (!slang_assembly_typeinfo_construct (&ti_before
))
1392 slang_assembly_typeinfo_destruct (&ti_after
);
1395 if (!handle_field (A
, &ti_after
, &ti_before
, op
, ref
))
1397 slang_assembly_typeinfo_destruct (&ti_after
);
1398 slang_assembly_typeinfo_destruct (&ti_before
);
1401 slang_assembly_typeinfo_destruct (&ti_after
);
1402 slang_assembly_typeinfo_destruct (&ti_before
);
1405 case slang_oper_postincrement
:
1406 if (!assemble_function_call_name_dummyint (A
, "++", op
->children
))
1408 A
->ref
= slang_ref_forbid
;
1410 case slang_oper_postdecrement
:
1411 if (!assemble_function_call_name_dummyint (A
, "--", op
->children
))
1413 A
->ref
= slang_ref_forbid
;