intermediate code generator (not finished);
[mesa.git] / src / mesa / shader / slang / slang_assemble.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.3
4 *
5 * Copyright (C) 2005 Brian Paul All Rights Reserved.
6 *
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:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
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.
23 */
24
25 /**
26 * \file slang_assemble.c
27 * slang intermediate code assembler
28 * \author Michal Krol
29 */
30
31 #include "imports.h"
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
40 /* slang_assembly */
41
42 static void slang_assembly_construct (slang_assembly *asm)
43 {
44 asm->type = slang_asm_none;
45 }
46
47 static void slang_assembly_destruct (slang_assembly *asm)
48 {
49 }
50
51 /* slang_assembly_file */
52
53 void slang_assembly_file_construct (slang_assembly_file *file)
54 {
55 file->code = NULL;
56 file->count = 0;
57 }
58
59 void slang_assembly_file_destruct (slang_assembly_file *file)
60 {
61 unsigned int i;
62
63 for (i = 0; i < file->count; i++)
64 slang_assembly_destruct (file->code + i);
65 slang_alloc_free (file->code);
66 }
67
68 static int slang_assembly_file_push_new (slang_assembly_file *file)
69 {
70 file->code = (slang_assembly *) slang_alloc_realloc (file->code, file->count * sizeof (
71 slang_assembly), (file->count + 1) * sizeof (slang_assembly));
72 if (file->code != NULL)
73 {
74 slang_assembly_construct (file->code + file->count);
75 file->count++;
76 return 1;
77 }
78 return 0;
79 }
80
81 static int slang_assembly_file_push_general (slang_assembly_file *file, slang_assembly_type type,
82 GLfloat literal, GLuint label, GLuint size)
83 {
84 slang_assembly *asm;
85 if (!slang_assembly_file_push_new (file))
86 return 0;
87 asm = file->code + file->count - 1;
88 asm->type = type;
89 asm->literal = literal;
90 asm->param[0] = label;
91 asm->param[1] = size;
92 return 1;
93 }
94
95 int slang_assembly_file_push (slang_assembly_file *file, slang_assembly_type type)
96 {
97 return slang_assembly_file_push_general (file, type, (GLfloat) 0, 0, 0);
98 }
99
100 int slang_assembly_file_push_label (slang_assembly_file *file, slang_assembly_type type,
101 GLuint label)
102 {
103 return slang_assembly_file_push_general (file, type, (GLfloat) 0, label, 0);
104 }
105
106 int slang_assembly_file_push_label2 (slang_assembly_file *file, slang_assembly_type type,
107 GLuint label1, GLuint label2)
108 {
109 return slang_assembly_file_push_general (file, type, (GLfloat) 0, label1, label2);
110 }
111
112 int slang_assembly_file_push_literal (slang_assembly_file *file, slang_assembly_type type,
113 GLfloat literal)
114 {
115 return slang_assembly_file_push_general (file, type, literal, 0, 0);
116 }
117
118 /* utility functions */
119
120 static int sizeof_variable (slang_type_specifier *spec, slang_operation *array_size,
121 slang_assembly_name_space *space, unsigned int *size)
122 {
123 slang_storage_aggregate agg;
124
125 slang_storage_aggregate_construct (&agg);
126 if (!_slang_aggregate_variable (&agg, spec, array_size, space->funcs, space->structs))
127 {
128 slang_storage_aggregate_destruct (&agg);
129 return 0;
130 }
131 *size += _slang_sizeof_aggregate (&agg);
132 slang_storage_aggregate_destruct (&agg);
133 return 1;
134 }
135
136 static int sizeof_variable2 (slang_variable *var, slang_assembly_name_space *space,
137 unsigned int *size)
138 {
139 var->address = *size;
140 return sizeof_variable (&var->type.specifier, var->array_size, space, size);
141 }
142
143 static int sizeof_variables (slang_variable_scope *vars, unsigned int start, unsigned int stop,
144 slang_assembly_name_space *space, unsigned int *size)
145 {
146 unsigned int i;
147
148 for (i = start; i < stop; i++)
149 if (!sizeof_variable2 (vars->variables + i, space, size))
150 return 0;
151 return 1;
152 }
153
154 static int collect_locals (slang_operation *op, slang_assembly_name_space *space,
155 unsigned int *size)
156 {
157 unsigned int i;
158
159 if (!sizeof_variables (op->locals, 0, op->locals->num_variables, space, size))
160 return 0;
161 for (i = 0; i < op->num_children; i++)
162 if (!collect_locals (op->children + i, space, size))
163 return 0;
164 return 1;
165 }
166
167 /* _slang_locate_function() */
168
169 slang_function *_slang_locate_function (const char *name, slang_operation *params,
170 unsigned int num_params, slang_assembly_name_space *space)
171 {
172 unsigned int i;
173
174 for (i = 0; i < space->funcs->num_functions; i++)
175 {
176 unsigned int j;
177 slang_function *f = space->funcs->functions + i;
178
179 if (slang_string_compare (name, f->header.name) != 0)
180 continue;
181 if (f->param_count != num_params)
182 continue;
183 for (j = 0; j < num_params; j++)
184 {
185 slang_assembly_typeinfo ti;
186 slang_assembly_typeinfo_construct (&ti);
187 if (!_slang_typeof_operation (params + j, space, &ti))
188 {
189 slang_assembly_typeinfo_destruct (&ti);
190 return 0;
191 }
192 if (!slang_type_specifier_equal (&ti.spec, &f->parameters->variables[j].type.specifier))
193 {
194 slang_assembly_typeinfo_destruct (&ti);
195 break;
196 }
197 slang_assembly_typeinfo_destruct (&ti);
198 /* "out" and "inout" formal parameter requires the actual parameter to be l-value */
199 if (!ti.can_be_referenced &&
200 f->parameters->variables[j].type.qualifier != slang_qual_out &&
201 f->parameters->variables[j].type.qualifier != slang_qual_inout)
202 break;
203 }
204 if (j == num_params)
205 return f;
206 }
207 if (space->funcs->outer_scope != NULL)
208 {
209 slang_assembly_name_space my_space = *space;
210 my_space.funcs = space->funcs->outer_scope;
211 return _slang_locate_function (name, params, num_params, &my_space);
212 }
213 return NULL;
214 }
215
216 /* _slang_assemble_function() */
217
218 int _slang_assemble_function (slang_assembly_file *file, slang_function *fun,
219 slang_assembly_name_space *space)
220 {
221 unsigned int param_size, local_size;
222 unsigned int skip, cleanup;
223 slang_assembly_flow_control flow;
224 slang_assembly_local_info info;
225 slang_assembly_stack_info stk;
226
227 fun->address = file->count;
228
229 if (fun->body == NULL)
230 {
231 /* TODO: jump to the actual function body */
232 return 1;
233 }
234
235 /* calculate return value and parameters size */
236 param_size = 0;
237 if (fun->header.type.specifier.type != slang_spec_void)
238 if (!sizeof_variable (&fun->header.type.specifier, NULL, space, &param_size))
239 return 0;
240 info.ret_size = param_size;
241 if (!sizeof_variables (fun->parameters, 0, fun->param_count, space, &param_size))
242 return 0;
243
244 /* calculate local variables size, take into account the four-byte return address and
245 temporaries for various tasks */
246 info.addr_tmp = param_size + 4;
247 info.swizzle_tmp = param_size + 4 + 4;
248 local_size = param_size + 4 + 4 + 16;
249 if (!sizeof_variables (fun->parameters, fun->param_count, fun->parameters->num_variables, space,
250 &local_size))
251 return 0;
252 if (!collect_locals (fun->body, space, &local_size))
253 return 0;
254
255 /* allocate local variable storage */
256 if (!slang_assembly_file_push_label (file, slang_asm_local_alloc, local_size - param_size - 4))
257 return 0;
258
259 /* mark a new frame for function variable storage */
260 if (!slang_assembly_file_push_label (file, slang_asm_enter, local_size))
261 return 0;
262
263 /* skip the cleanup jump */
264 skip = file->count;
265 if (!slang_assembly_file_push_new (file))
266 return 0;
267 file->code[skip].type = slang_asm_jump;
268
269 /* all "return" statements will be directed here */
270 flow.function_end = file->count;
271 cleanup = file->count;
272 if (!slang_assembly_file_push_new (file))
273 return 0;
274 file->code[cleanup].type = slang_asm_jump;
275
276 /* execute the function body */
277 file->code[skip].param[0] = file->count;
278 if (!_slang_assemble_operation (file, fun->body, 0, &flow, space, &info, &stk))
279 return 0;
280
281 /* this is the end of the function - restore the old function frame */
282 file->code[cleanup].param[0] = file->count;
283 if (!slang_assembly_file_push (file, slang_asm_leave))
284 return 0;
285
286 /* free local variable storage */
287 if (!slang_assembly_file_push_label (file, slang_asm_local_free, local_size - param_size - 4))
288 return 0;
289
290 /* jump out of the function */
291 if (!slang_assembly_file_push (file, slang_asm_return))
292 return 0;
293 return 1;
294 }
295
296 int _slang_cleanup_stack (slang_assembly_file *file, slang_operation *op, int ref,
297 slang_assembly_name_space *space)
298 {
299 slang_assembly_typeinfo ti;
300 unsigned int size;
301
302 slang_assembly_typeinfo_construct (&ti);
303 if (!_slang_typeof_operation (op, space, &ti))
304 {
305 slang_assembly_typeinfo_destruct (&ti);
306 return 0;
307 }
308 if (ti.spec.type == slang_spec_void)
309 size = 0;
310 else if (ref)
311 size = 4;
312 else
313 {
314 size = 0;
315 if (!sizeof_variable (&ti.spec, NULL, space, &size))
316 {
317 slang_assembly_typeinfo_destruct (&ti);
318 return 0;
319 }
320 }
321 slang_assembly_typeinfo_destruct (&ti);
322 if (size != 0)
323 {
324 if (!slang_assembly_file_push_label (file, slang_asm_local_free, size))
325 return 0;
326 }
327 return 1;
328 }
329
330 /* _slang_assemble_operation() */
331
332 /* XXX: general swizzle! */
333 static int dereference_aggregate (slang_assembly_file *file, const slang_storage_aggregate *agg,
334 unsigned int index, unsigned int *size, slang_assembly_local_info *info)
335 {
336 unsigned int i;
337
338 for (i = agg->count; i > 0; i--)
339 {
340 const slang_storage_array *arr = agg->arrays + i - 1;
341 unsigned int j;
342
343 for (j = arr->length; j > 0; j--)
344 {
345 if (arr->type == slang_stor_aggregate)
346 {
347 if (!dereference_aggregate (file, arr->aggregate, index, size, info))
348 return 0;
349 }
350 else
351 {
352 *size -= 4;
353 if (!slang_assembly_file_push_label2 (file, slang_asm_local_addr, info->addr_tmp,
354 4))
355 return 0;
356 if (!slang_assembly_file_push (file, slang_asm_addr_deref))
357 return 0;
358 if (!slang_assembly_file_push_label (file, slang_asm_addr_push, *size))
359 return 0;
360 if (!slang_assembly_file_push (file, slang_asm_addr_add))
361 return 0;
362 switch (arr->type)
363 {
364 case slang_stor_bool:
365 if (!slang_assembly_file_push (file, slang_asm_bool_deref))
366 return 0;
367 break;
368 case slang_stor_int:
369 if (!slang_assembly_file_push (file, slang_asm_int_deref))
370 return 0;
371 break;
372 case slang_stor_float:
373 if (!slang_assembly_file_push (file, slang_asm_float_deref))
374 return 0;
375 break;
376 }
377 index += 4;
378 }
379 }
380 }
381 return 1;
382 }
383 /* XXX: general swizzle! */
384 static int dereference (slang_assembly_file *file, slang_operation *op,
385 slang_assembly_name_space *space, slang_assembly_local_info *info)
386 {
387 slang_assembly_typeinfo ti;
388 int result;
389 slang_storage_aggregate agg;
390 unsigned int size;
391
392 slang_assembly_typeinfo_construct (&ti);
393 if (!_slang_typeof_operation (op, space, &ti))
394 {
395 slang_assembly_typeinfo_destruct (&ti);
396 return 0;
397 }
398
399 slang_storage_aggregate_construct (&agg);
400 if (!_slang_aggregate_variable (&agg, &ti.spec, NULL, space->funcs, space->structs))
401 {
402 slang_storage_aggregate_destruct (&agg);
403 slang_assembly_typeinfo_destruct (&ti);
404 return 0;
405 }
406
407 size = _slang_sizeof_aggregate (&agg);
408 result = dereference_aggregate (file, &agg, 0, &size, info);
409
410 slang_storage_aggregate_destruct (&agg);
411 slang_assembly_typeinfo_destruct (&ti);
412 return result;
413 }
414
415 static int call_function (slang_assembly_file *file, slang_function *fun, slang_operation *params,
416 unsigned int param_count, int assignment, slang_assembly_name_space *space,
417 slang_assembly_local_info *info)
418 {
419 unsigned int ret_size, i;
420 slang_assembly_stack_info stk;
421
422 /* make room for the return value, if any */
423 ret_size = 0;
424 if (!sizeof_variable (&fun->header.type.specifier, NULL, space, &ret_size))
425 return 0;
426 if (ret_size > 0)
427 {
428 if (!slang_assembly_file_push_label (file, slang_asm_local_alloc, ret_size))
429 return 0;
430 }
431
432 /* push the actual parameters on the stack */
433 for (i = 0; i < param_count; i++)
434 {
435 slang_assembly_flow_control flow;
436
437 if (i == 0 && assignment)
438 {
439 if (!slang_assembly_file_push_label2 (file, slang_asm_local_addr, info->addr_tmp, 4))
440 return 0;
441 /* TODO: optimize the "out" parameter case */
442 /* TODO: inspect stk */
443 if (!_slang_assemble_operation (file, params, 1, &flow, space, info, &stk))
444 return 0;
445 if (!slang_assembly_file_push (file, slang_asm_addr_copy))
446 return 0;
447 if (!slang_assembly_file_push (file, slang_asm_addr_deref))
448 return 0;
449 if (!slang_assembly_file_push_label2 (file, slang_asm_local_addr, info->addr_tmp, 4))
450 return 0;
451 if (!slang_assembly_file_push (file, slang_asm_addr_deref))
452 return 0;
453 if (!dereference (file, params, space, info))
454 return 0;
455 }
456 else
457 {
458 /* TODO: for "out" and "inout" parameters also push the address (first) */
459 /* TODO: optimize the "out" parameter case */
460 /* TODO: inspect stk */
461 if (!_slang_assemble_operation (file, params + i, 0, &flow, space, info, &stk))
462 return 0;
463 }
464 }
465
466 /* call the function */
467 if (!slang_assembly_file_push_label (file, slang_asm_call, fun->address))
468 return 0;
469
470 /* pop the parameters from the stack */
471 for (i = param_count; i > 0; i--)
472 {
473 /* XXX: copy inout/out params back to the actual variables */
474 if (!_slang_cleanup_stack (file, params + i - 1, 0, space))
475 return 0;
476 }
477
478 return 1;
479 }
480
481 static int call_function_name (slang_assembly_file *file, const char *name, slang_operation *params,
482 unsigned int param_count, int assignment, slang_assembly_name_space *space,
483 slang_assembly_local_info *info)
484 {
485 slang_function *fun = _slang_locate_function (name, params, param_count, space);
486 if (fun == NULL)
487 return 0;
488 return call_function (file, fun, params, param_count, assignment, space, info);
489 }
490
491 static int call_function_name_dummyint (slang_assembly_file *file, const char *name,
492 slang_operation *params, slang_assembly_name_space *space, slang_assembly_local_info *info)
493 {
494 slang_operation p2[2];
495 int result;
496
497 p2[0] = *params;
498 if (!slang_operation_construct_a (p2 + 1))
499 return 0;
500 p2[1].type = slang_oper_literal_int;
501 result = call_function_name (file, name, p2, 2, 0, space, info);
502 slang_operation_destruct (p2 + 1);
503 return result;
504 }
505
506 static int call_asm_instruction (slang_assembly_file *file, const char *name)
507 {
508 const struct
509 {
510 const char *name;
511 slang_assembly_type code1, code2;
512 } inst[] = {
513 { "float_to_int", slang_asm_float_to_int, slang_asm_int_copy },
514 { "int_to_float", slang_asm_int_to_float, slang_asm_float_copy },
515 { "float_copy", slang_asm_float_copy, slang_asm_none },
516 { "int_copy", slang_asm_int_copy, slang_asm_none },
517 { "bool_copy", slang_asm_bool_copy, slang_asm_none },
518 { "float_add", slang_asm_float_add, slang_asm_float_copy },
519 { "float_multiply", slang_asm_float_multiply, slang_asm_float_copy },
520 { "float_divide", slang_asm_float_divide, slang_asm_float_copy },
521 { "float_negate", slang_asm_float_negate, slang_asm_float_copy },
522 { "float_less", slang_asm_float_less, slang_asm_bool_copy },
523 { "float_equal", slang_asm_float_equal, slang_asm_bool_copy },
524 { NULL, slang_asm_none, slang_asm_none }
525 };
526 unsigned int i;
527
528 for (i = 0; inst[i].name != NULL; i++)
529 if (slang_string_compare (name, inst[i].name) == 0)
530 break;
531 if (inst[i].name == NULL)
532 return 0;
533
534 if (!slang_assembly_file_push_label2 (file, inst[i].code1, 4, 0))
535 return 0;
536 if (inst[i].code2 != slang_asm_none)
537 if (!slang_assembly_file_push_label2 (file, inst[i].code2, 4, 0))
538 return 0;
539
540 /* clean-up the stack from the remaining dst address */
541 if (!slang_assembly_file_push_label (file, slang_asm_local_free, 4))
542 return 0;
543
544 return 1;
545 }
546 /* XXX: general swizzle! */
547 static int assign_aggregate (slang_assembly_file *file, const slang_storage_aggregate *agg,
548 unsigned int *index, unsigned int size, slang_assembly_local_info *info)
549 {
550 unsigned int i;
551
552 for (i = 0; i < agg->count; i++)
553 {
554 const slang_storage_array *arr = agg->arrays + i;
555 unsigned int j;
556
557 for (j = 0; j < arr->length; j++)
558 {
559 if (arr->type == slang_stor_aggregate)
560 {
561 if (!assign_aggregate (file, arr->aggregate, index, size, info))
562 return 0;
563 }
564 else
565 {
566 switch (arr->type)
567 {
568 case slang_stor_bool:
569 if (!slang_assembly_file_push_label2 (file, slang_asm_bool_copy,
570 size - *index, *index))
571 return 0;
572 break;
573 case slang_stor_int:
574 if (!slang_assembly_file_push_label2 (file, slang_asm_int_copy,
575 size - *index, *index))
576 return 0;
577 break;
578 case slang_stor_float:
579 if (!slang_assembly_file_push_label2 (file, slang_asm_float_copy,
580 size - *index, *index))
581 return 0;
582 break;
583 }
584 *index += 4;
585 }
586 }
587 }
588 return 1;
589 }
590 /* XXX: general swizzle! */
591 static int assignment (slang_assembly_file *file, slang_operation *op,
592 slang_assembly_name_space *space, slang_assembly_local_info *info)
593 {
594 slang_assembly_typeinfo ti;
595 int result;
596 slang_storage_aggregate agg;
597 unsigned int index, size;
598
599 slang_assembly_typeinfo_construct (&ti);
600 if (!_slang_typeof_operation (op, space, &ti))
601 {
602 slang_assembly_typeinfo_destruct (&ti);
603 return 0;
604 }
605
606 slang_storage_aggregate_construct (&agg);
607 if (!_slang_aggregate_variable (&agg, &ti.spec, NULL, space->funcs, space->structs))
608 {
609 slang_storage_aggregate_destruct (&agg);
610 slang_assembly_typeinfo_destruct (&ti);
611 return 0;
612 }
613
614 index = 0;
615 size = _slang_sizeof_aggregate (&agg);
616 result = assign_aggregate (file, &agg, &index, size, info);
617
618 slang_storage_aggregate_destruct (&agg);
619 slang_assembly_typeinfo_destruct (&ti);
620 return result;
621 }
622 /* XXX: general swizzle! */
623 static int equality_aggregate (slang_assembly_file *file, const slang_storage_aggregate *agg,
624 unsigned int *index, unsigned int size, slang_assembly_local_info *info, unsigned int z_label)
625 {
626 unsigned int i;
627
628 for (i = 0; i < agg->count; i++)
629 {
630 const slang_storage_array *arr = agg->arrays + i;
631 unsigned int j;
632
633 for (j = 0; j < arr->length; j++)
634 {
635 if (arr->type == slang_stor_aggregate)
636 {
637 if (!equality_aggregate (file, arr->aggregate, index, size, info, z_label))
638 return 0;
639 }
640 else
641 {
642 if (!slang_assembly_file_push_label2 (file, slang_asm_float_equal, size + *index,
643 *index))
644 return 0;
645 *index += 4;
646 if (!slang_assembly_file_push_label (file, slang_asm_jump_if_zero, z_label))
647 return 0;
648 }
649 }
650 }
651 return 1;
652 }
653 /* XXX: general swizzle! */
654 static int equality (slang_assembly_file *file, slang_operation *op,
655 slang_assembly_name_space *space, slang_assembly_local_info *info, int equal)
656 {
657 slang_assembly_typeinfo ti;
658 int result;
659 slang_storage_aggregate agg;
660 unsigned int index, size;
661 unsigned int skip_jump, true_label, true_jump, false_label, false_jump;
662
663 /* get type of operation */
664 slang_assembly_typeinfo_construct (&ti);
665 if (!_slang_typeof_operation (op, space, &ti))
666 {
667 slang_assembly_typeinfo_destruct (&ti);
668 return 0;
669 }
670
671 /* convert it to an aggregate */
672 slang_storage_aggregate_construct (&agg);
673 if (!(result = _slang_aggregate_variable (&agg, &ti.spec, NULL, space->funcs, space->structs)))
674 goto end;
675
676 /* compute the size of the agregate - there are two such aggregates on the stack */
677 size = _slang_sizeof_aggregate (&agg);
678
679 /* jump to the actual data-comparison code */
680 skip_jump = file->count;
681 if (!(result = slang_assembly_file_push (file, slang_asm_jump)))
682 goto end;
683
684 /* pop off the stack the compared data and push 1 */
685 true_label = file->count;
686 if (!(result = slang_assembly_file_push_label (file, slang_asm_local_free, size * 2)))
687 goto end;
688 if (!(result = slang_assembly_file_push_literal (file, slang_asm_bool_push, 1.0f)))
689 goto end;
690 true_jump = file->count;
691 if (!(result = slang_assembly_file_push (file, slang_asm_jump)))
692 goto end;
693
694 false_label = file->count;
695 if (!(result = slang_assembly_file_push_label (file, slang_asm_local_free, size * 2)))
696 goto end;
697 if (!(result = slang_assembly_file_push_literal (file, slang_asm_bool_push, 0.0f)))
698 goto end;
699 false_jump = file->count;
700 if (!(result = slang_assembly_file_push (file, slang_asm_jump)))
701 goto end;
702
703 file->code[skip_jump].param[0] = file->count;
704
705 /* compare the data on stack, it will eventually jump either to true or false label */
706 index = 0;
707 if (!(result = equality_aggregate (file, &agg, &index, size, info,
708 equal ? false_label : true_label)))
709 goto end;
710 if (!(result = slang_assembly_file_push_label (file, slang_asm_jump,
711 equal ? true_label : false_label)))
712 goto end;
713
714 file->code[true_jump].param[0] = file->count;
715 file->code[false_jump].param[0] = file->count;
716
717 result = 1;
718 end:
719 slang_storage_aggregate_destruct (&agg);
720 slang_assembly_typeinfo_destruct (&ti);
721 return result;
722 }
723
724 int _slang_assemble_operation (slang_assembly_file *file, slang_operation *op, int reference,
725 slang_assembly_flow_control *flow, slang_assembly_name_space *space,
726 slang_assembly_local_info *info, slang_assembly_stack_info *stk)
727 {
728 unsigned int asm;
729
730 stk->swizzle_mask = 0;
731
732 asm = file->count;
733 if (!slang_assembly_file_push_new (file))
734 return 0;
735
736 switch (op->type)
737 {
738 case slang_oper_block_no_new_scope:
739 case slang_oper_block_new_scope:
740 {
741 unsigned int i;
742 for (i = 0; i < op->num_children; i++)
743 {
744 slang_assembly_stack_info stk;
745 if (!_slang_assemble_operation (file, op->children + i, 0, flow, space, info, &stk))
746 return 0;
747 /* TODO: pass-in stk to cleanup */
748 if (!_slang_cleanup_stack (file, op->children + i, 0, space))
749 return 0;
750 }
751 }
752 break;
753 case slang_oper_variable_decl:
754 {
755 unsigned int i;
756
757 for (i = 0; i < op->num_children; i++)
758 {
759 /* TODO: perform initialization of op->children[i] */
760 /* TODO: clean-up stack */
761 }
762 }
763 break;
764 case slang_oper_asm:
765 {
766 unsigned int i;
767 for (i = 0; i < op->num_children; i++)
768 {
769 slang_assembly_stack_info stk;
770 if (!_slang_assemble_operation (file, op->children + i, i == 0, flow, space, info,
771 &stk))
772 return 0;
773 /* TODO: inspect stk */
774 }
775 if (!call_asm_instruction (file, op->identifier))
776 return 0;
777 }
778 break;
779 case slang_oper_break:
780 file->code[asm].type = slang_asm_jump;
781 file->code[asm].param[0] = flow->loop_end;
782 break;
783 case slang_oper_continue:
784 file->code[asm].type = slang_asm_jump;
785 file->code[asm].param[0] = flow->loop_start;
786 break;
787 case slang_oper_discard:
788 file->code[asm].type = slang_asm_discard;
789 if (!slang_assembly_file_push (file, slang_asm_exit))
790 return 0;
791 break;
792 case slang_oper_return:
793 if (info->ret_size != 0)
794 {
795 slang_assembly_stack_info stk;
796 if (!slang_assembly_file_push_label2 (file, slang_asm_local_addr, 0, info->ret_size))
797 return 0;
798 if (!_slang_assemble_operation (file, op->children, 0, flow, space, info, &stk))
799 return 0;
800 /* TODO: inspect stk */
801 if (!assignment (file, op->children, space, info))
802 return 0;
803 if (!slang_assembly_file_push_label (file, slang_asm_local_free, 4))
804 return 0;
805 }
806 if (!slang_assembly_file_push_label (file, slang_asm_jump, flow->function_end))
807 return 0;
808 break;
809 case slang_oper_expression:
810 {
811 slang_assembly_stack_info stk;
812 if (!_slang_assemble_operation (file, op->children, reference, flow, space, info, &stk))
813 return 0;
814 /* TODO: inspect stk */
815 }
816 break;
817 case slang_oper_if:
818 if (!_slang_assemble_if (file, op, flow, space, info))
819 return 0;
820 break;
821 case slang_oper_while:
822 if (!_slang_assemble_while (file, op, flow, space, info))
823 return 0;
824 break;
825 case slang_oper_do:
826 if (!_slang_assemble_do (file, op, flow, space, info))
827 return 0;
828 break;
829 case slang_oper_for:
830 if (!_slang_assemble_for (file, op, flow, space, info))
831 return 0;
832 break;
833 case slang_oper_void:
834 break;
835 case slang_oper_literal_bool:
836 file->code[asm].type = slang_asm_bool_push;
837 file->code[asm].literal = op->literal;
838 break;
839 case slang_oper_literal_int:
840 file->code[asm].type = slang_asm_int_push;
841 file->code[asm].literal = op->literal;
842 break;
843 case slang_oper_literal_float:
844 file->code[asm].type = slang_asm_float_push;
845 file->code[asm].literal = op->literal;
846 break;
847 case slang_oper_identifier:
848 {
849 slang_variable *var;
850 unsigned int size;
851 var = _slang_locate_variable (op->locals, op->identifier, 1);
852 if (var == NULL)
853 return 0;
854 size = 0;
855 if (!sizeof_variable (&var->type.specifier, var->array_size, space, &size))
856 return 0;
857 if (var->initializer != NULL)
858 {
859 assert (!"var->initializer, oper_identifier");
860 }
861 else
862 {
863 if (!reference)
864 {
865 if (!slang_assembly_file_push_label2 (file, slang_asm_local_addr,
866 info->addr_tmp, 4))
867 return 0;
868 }
869 /* XXX: globals! */
870 if (!slang_assembly_file_push_label2 (file, slang_asm_local_addr, var->address,
871 size))
872 return 0;
873 if (!reference)
874 {
875 if (!slang_assembly_file_push (file, slang_asm_addr_copy))
876 return 0;
877 if (!slang_assembly_file_push_label (file, slang_asm_local_free, 4))
878 return 0;
879 if (!dereference (file, op, space, info))
880 return 0;
881 }
882 }
883 }
884 break;
885 case slang_oper_sequence:
886 {
887 slang_assembly_stack_info stk;
888 if (!_slang_assemble_operation (file, op->children, 0, flow, space, info, &stk))
889 return 0;
890 /* TODO: pass-in stk to cleanup */
891 if (!_slang_cleanup_stack (file, op->children, 0, space))
892 return 0;
893 if (!_slang_assemble_operation (file, op->children + 1, 0, flow, space, info,
894 &stk))
895 return 0;
896 /* TODO: inspect stk */
897 }
898 break;
899 case slang_oper_assign:
900 {
901 slang_assembly_stack_info stk;
902 if (!reference)
903 if (!slang_assembly_file_push_label2 (file, slang_asm_local_addr, info->addr_tmp,
904 4))
905 return 0;
906 if (!_slang_assemble_operation (file, op->children, 1, flow, space, info, &stk))
907 return 0;
908 /* TODO: inspect stk */
909 if (!_slang_assemble_operation (file, op->children + 1, 0, flow, space, info, &stk))
910 return 0;
911 /* TODO: inspect stk */
912 if (!assignment (file, op->children, space, info))
913 return 0;
914 if (!reference)
915 {
916 if (!slang_assembly_file_push (file, slang_asm_addr_copy))
917 return 0;
918 if (!slang_assembly_file_push_label (file, slang_asm_local_free, 4))
919 return 0;
920 if (!dereference (file, op->children, space, info))
921 return 0;
922 }
923 }
924 break;
925 case slang_oper_addassign:
926 /* TODO: posprawdzaj czy zadzia³a dereferencja */
927 if (!call_function_name (file, "+=", op->children, 2, 1, space, info))
928 return 0;
929 if (reference)
930 {
931 /* TODO: stack is address */
932 }
933 else
934 {
935 if (!dereference (file, op->children, space, info))
936 return 0;
937 /* TODO: stack is operation type */
938 }
939 break;
940 case slang_oper_subassign:
941 /* TODO: posprawdzaj czy zadzia³a dereferencja */
942 if (!call_function_name (file, "-=", op->children, 2, 1, space, info))
943 return 0;
944 if (reference)
945 {
946 /* TODO: stack is address */
947 }
948 else
949 {
950 if (!dereference (file, op->children, space, info))
951 return 0;
952 /* TODO: stack is operation type */
953 }
954 break;
955 case slang_oper_mulassign:
956 /* TODO: posprawdzaj czy zadzia³a dereferencja */
957 if (!call_function_name (file, "*=", op->children, 2, 1, space, info))
958 return 0;
959 if (reference)
960 {
961 /* TODO: stack is address */
962 }
963 else
964 {
965 if (!dereference (file, op->children, space, info))
966 return 0;
967 /* TODO: stack is operation type */
968 }
969 break;
970 /*case slang_oper_modassign:*/
971 /*case slang_oper_lshassign:*/
972 /*case slang_oper_rshassign:*/
973 /*case slang_oper_orassign:*/
974 /*case slang_oper_xorassign:*/
975 /*case slang_oper_andassign:*/
976 case slang_oper_divassign:
977 /* TODO: posprawdzaj czy zadzia³a dereferencja */
978 if (!call_function_name (file, "/=", op->children, 2, 1, space, info))
979 return 0;
980 if (reference)
981 {
982 /* TODO: stack is address */
983 }
984 else
985 {
986 if (!dereference (file, op->children, space, info))
987 return 0;
988 /* TODO: stack is operation type */
989 }
990 break;
991 case slang_oper_select:
992 if (!_slang_assemble_select (file, op, flow, space, info))
993 return 0;
994 break;
995 case slang_oper_logicalor:
996 if (!_slang_assemble_logicalor (file, op, flow, space, info))
997 return 0;
998 break;
999 case slang_oper_logicaland:
1000 if (!_slang_assemble_logicaland (file, op, flow, space, info))
1001 return 0;
1002 break;
1003 case slang_oper_logicalxor:
1004 if (!call_function_name (file, "^^", op->children, 2, 0, space, info))
1005 return 0;
1006 break;
1007 /*case slang_oper_bitor:*/
1008 /*case slang_oper_bitxor:*/
1009 /*case slang_oper_bitand:*/
1010 case slang_oper_less:
1011 if (!call_function_name (file, "<", op->children, 2, 0, space, info))
1012 return 0;
1013 break;
1014 case slang_oper_greater:
1015 if (!call_function_name (file, ">", op->children, 2, 0, space, info))
1016 return 0;
1017 break;
1018 case slang_oper_lessequal:
1019 if (!call_function_name (file, "<=", op->children, 2, 0, space, info))
1020 return 0;
1021 break;
1022 case slang_oper_greaterequal:
1023 if (!call_function_name (file, ">=", op->children, 2, 0, space, info))
1024 return 0;
1025 break;
1026 /*case slang_oper_lshift:*/
1027 /*case slang_oper_rshift:*/
1028 case slang_oper_add:
1029 if (!call_function_name (file, "+", op->children, 2, 0, space, info))
1030 return 0;
1031 break;
1032 case slang_oper_subtract:
1033 if (!call_function_name (file, "-", op->children, 2, 0, space, info))
1034 return 0;
1035 break;
1036 case slang_oper_multiply:
1037 if (!call_function_name (file, "*", op->children, 2, 0, space, info))
1038 return 0;
1039 break;
1040 /*case slang_oper_modulus:*/
1041 case slang_oper_divide:
1042 if (!call_function_name (file, "/", op->children, 2, 0, space, info))
1043 return 0;
1044 break;
1045 case slang_oper_equal:
1046 {
1047 slang_assembly_stack_info stk;
1048 if (!_slang_assemble_operation (file, op->children, 0, flow, space, info, &stk))
1049 return 0;
1050 /* TODO: inspect stk */
1051 if (!_slang_assemble_operation (file, op->children + 1, 0, flow, space, info, &stk))
1052 return 0;
1053 /* TODO: inspect stk */
1054 if (!equality (file, op->children, space, info, 1))
1055 return 0;
1056 }
1057 break;
1058 case slang_oper_notequal:
1059 {
1060 slang_assembly_stack_info stk;
1061 if (!_slang_assemble_operation (file, op->children, 0, flow, space, info, &stk))
1062 return 0;
1063 /* TODO: inspect stk */
1064 if (!_slang_assemble_operation (file, op->children + 1, 0, flow, space, info, &stk))
1065 return 0;
1066 /* TODO: inspect stk */
1067 if (!equality (file, op->children, space, info, 0))
1068 return 0;
1069 }
1070 break;
1071 case slang_oper_preincrement:
1072 /* TODO: posprawdzaj czy zadzia³a dereferencja */
1073 if (!call_function_name (file, "++", op->children, 1, 1, space, info))
1074 return 0;
1075 if (reference)
1076 {
1077 /* TODO: stack is address */
1078 }
1079 else
1080 {
1081 /* TODO: dereference */
1082 /* TODO: stack is operation type */
1083 }
1084 break;
1085 case slang_oper_predecrement:
1086 /* TODO: posprawdzaj czy zadzia³a dereferencja */
1087 if (!call_function_name (file, "--", op->children, 1, 1, space, info))
1088 return 0;
1089 if (reference)
1090 {
1091 /* TODO: stack is address */
1092 }
1093 else
1094 {
1095 /* TODO: dereference */
1096 /* TODO: stack is operation type */
1097 }
1098 break;
1099 case slang_oper_plus:
1100 if (!call_function_name (file, "+", op->children, 1, 0, space, info))
1101 return 0;
1102 break;
1103 case slang_oper_minus:
1104 if (!call_function_name (file, "-", op->children, 1, 0, space, info))
1105 return 0;
1106 break;
1107 /*case slang_oper_complement:*/
1108 case slang_oper_not:
1109 if (!call_function_name (file, "!", op->children, 1, 0, space, info))
1110 return 0;
1111 break;
1112 case slang_oper_subscript:
1113 {
1114 slang_assembly_stack_info _stk;
1115 slang_assembly_typeinfo ti_arr, ti_elem;
1116 unsigned int arr_size = 0, elem_size = 0;
1117 if (!_slang_assemble_operation (file, op->children, reference, flow, space, info,
1118 &_stk))
1119 return 0;
1120 if (!_slang_assemble_operation (file, op->children + 1, 0, flow, space, info, &_stk))
1121 return 0;
1122 slang_assembly_typeinfo_construct (&ti_arr);
1123 if (!_slang_typeof_operation (op->children, space, &ti_arr))
1124 {
1125 slang_assembly_typeinfo_destruct (&ti_arr);
1126 return 0;
1127 }
1128 if (!sizeof_variable (&ti_arr.spec, NULL, space, &arr_size))
1129 {
1130 slang_assembly_typeinfo_destruct (&ti_arr);
1131 return 0;
1132 }
1133 slang_assembly_typeinfo_construct (&ti_elem);
1134 if (!_slang_typeof_operation (op, space, &ti_elem))
1135 {
1136 slang_assembly_typeinfo_destruct (&ti_arr);
1137 slang_assembly_typeinfo_destruct (&ti_elem);
1138 return 0;
1139 }
1140 if (!sizeof_variable (&ti_elem.spec, NULL, space, &elem_size))
1141 {
1142 slang_assembly_typeinfo_destruct (&ti_arr);
1143 slang_assembly_typeinfo_destruct (&ti_elem);
1144 return 0;
1145 }
1146 if (!slang_assembly_file_push (file, slang_asm_int_to_addr))
1147 {
1148 slang_assembly_typeinfo_destruct (&ti_arr);
1149 slang_assembly_typeinfo_destruct (&ti_elem);
1150 return 0;
1151 }
1152 if (!slang_assembly_file_push_label (file, slang_asm_addr_push, elem_size))
1153 {
1154 slang_assembly_typeinfo_destruct (&ti_arr);
1155 slang_assembly_typeinfo_destruct (&ti_elem);
1156 return 0;
1157 }
1158 if (!slang_assembly_file_push (file, slang_asm_addr_multiply))
1159 {
1160 slang_assembly_typeinfo_destruct (&ti_arr);
1161 slang_assembly_typeinfo_destruct (&ti_elem);
1162 return 0;
1163 }
1164 if (reference)
1165 {
1166 if (!slang_assembly_file_push (file, slang_asm_addr_add))
1167 {
1168 slang_assembly_typeinfo_destruct (&ti_arr);
1169 slang_assembly_typeinfo_destruct (&ti_elem);
1170 return 0;
1171 }
1172 }
1173 else
1174 {
1175 unsigned int i;
1176 for (i = 0; i < elem_size; i += 4)
1177 {
1178 if (!slang_assembly_file_push_label2 (file, slang_asm_float_move,
1179 arr_size - elem_size + i + 4, i + 4))
1180 {
1181 slang_assembly_typeinfo_destruct (&ti_arr);
1182 slang_assembly_typeinfo_destruct (&ti_elem);
1183 return 0;
1184 }
1185 }
1186 if (!slang_assembly_file_push_label (file, slang_asm_local_free, 4))
1187 {
1188 slang_assembly_typeinfo_destruct (&ti_arr);
1189 slang_assembly_typeinfo_destruct (&ti_elem);
1190 return 0;
1191 }
1192 if (!slang_assembly_file_push_label (file, slang_asm_local_free,
1193 arr_size - elem_size))
1194 {
1195 slang_assembly_typeinfo_destruct (&ti_arr);
1196 slang_assembly_typeinfo_destruct (&ti_elem);
1197 return 0;
1198 }
1199 }
1200 slang_assembly_typeinfo_destruct (&ti_arr);
1201 slang_assembly_typeinfo_destruct (&ti_elem);
1202 }
1203 break;
1204 case slang_oper_call:
1205 {
1206 slang_function *fun = _slang_locate_function (op->identifier, op->children,
1207 op->num_children, space);
1208 if (fun == NULL)
1209 {
1210 if (!_slang_assemble_constructor (file, op, flow, space, info))
1211 return 0;
1212 }
1213 else
1214 {
1215 if (!call_function (file, fun, op->children, op->num_children, 0, space, info))
1216 return 0;
1217 }
1218 }
1219 break;
1220 case slang_oper_field:
1221 {
1222 slang_assembly_typeinfo ti_after, ti_before;
1223 slang_assembly_stack_info _stk;
1224 slang_assembly_typeinfo_construct (&ti_after);
1225 if (!_slang_typeof_operation (op, space, &ti_after))
1226 {
1227 slang_assembly_typeinfo_destruct (&ti_after);
1228 return 0;
1229 }
1230 slang_assembly_typeinfo_construct (&ti_before);
1231 if (!_slang_typeof_operation (op->children, space, &ti_before))
1232 {
1233 slang_assembly_typeinfo_destruct (&ti_after);
1234 slang_assembly_typeinfo_destruct (&ti_before);
1235 return 0;
1236 }
1237 if (!reference && ti_after.is_swizzled)
1238 {
1239 if (!slang_assembly_file_push_label2 (file, slang_asm_local_addr,
1240 info->swizzle_tmp, 16))
1241 {
1242 slang_assembly_typeinfo_destruct (&ti_after);
1243 slang_assembly_typeinfo_destruct (&ti_before);
1244 return 0;
1245 }
1246 }
1247 if (!_slang_assemble_operation (file, op->children, reference, flow, space, info,
1248 &_stk))
1249 {
1250 slang_assembly_typeinfo_destruct (&ti_after);
1251 slang_assembly_typeinfo_destruct (&ti_before);
1252 return 0;
1253 }
1254 /* TODO: inspect stk */
1255 if (ti_after.is_swizzled)
1256 {
1257 if (reference)
1258 {
1259 if (ti_after.swz.num_components == 1)
1260 {
1261 if (!slang_assembly_file_push_label (file, slang_asm_addr_push,
1262 ti_after.swz.swizzle[0] * 4))
1263 {
1264 slang_assembly_typeinfo_destruct (&ti_after);
1265 slang_assembly_typeinfo_destruct (&ti_before);
1266 return 0;
1267 }
1268 if (!slang_assembly_file_push (file, slang_asm_addr_add))
1269 {
1270 slang_assembly_typeinfo_destruct (&ti_after);
1271 slang_assembly_typeinfo_destruct (&ti_before);
1272 return 0;
1273 }
1274 }
1275 else
1276 {
1277 unsigned int i;
1278 for (i = 0; i < ti_after.swz.num_components; i++)
1279 stk->swizzle_mask |= 1 << ti_after.swz.swizzle[i];
1280 }
1281 }
1282 else
1283 {
1284 if (!_slang_assemble_constructor_from_swizzle (file, &ti_after.swz,
1285 &ti_after.spec, &ti_before.spec, info))
1286 {
1287 slang_assembly_typeinfo_destruct (&ti_after);
1288 slang_assembly_typeinfo_destruct (&ti_before);
1289 return 0;
1290 }
1291 }
1292 }
1293 else
1294 {
1295 if (reference)
1296 {
1297 /* TODO: struct field address */
1298 }
1299 else
1300 {
1301 /* TODO: struct field value */
1302 }
1303 }
1304 slang_assembly_typeinfo_destruct (&ti_after);
1305 slang_assembly_typeinfo_destruct (&ti_before);
1306 }
1307 break;
1308 case slang_oper_postincrement:
1309 if (!call_function_name_dummyint (file, "++", op->children, space, info))
1310 return 0;
1311 if (!dereference (file, op, space, info))
1312 return 0;
1313 break;
1314 case slang_oper_postdecrement:
1315 if (!call_function_name_dummyint (file, "--", op->children, space, info))
1316 return 0;
1317 if (!dereference (file, op, space, info))
1318 return 0;
1319 break;
1320 default:
1321 return 0;
1322 }
1323 return 1;
1324 }
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334 void xxx_first (slang_assembly_file *file)
1335 {
1336 slang_assembly_file_push (file, slang_asm_jump);
1337 }
1338
1339 void xxx_prolog (slang_assembly_file *file)
1340 {
1341 file->code[0].param[0] = file->count;
1342
1343 /* allocate local storage for inout/out params */
1344 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1345 slang_assembly_file_push_label (file, slang_asm_enter, 4);
1346
1347 /* slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1348 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1349 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1350 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1351 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1352 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1353 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1354 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1355 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1356 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1357 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1358 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1359 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1360 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1361 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);*/
1362 slang_assembly_file_push_literal (file, slang_asm_int_push, 777.777f);
1363 /* slang_assembly_file_push_literal (file, slang_asm_float_push, 16.16f);
1364 slang_assembly_file_push_literal (file, slang_asm_float_push, 15.15f);
1365 slang_assembly_file_push_literal (file, slang_asm_float_push, 14.14f);
1366 slang_assembly_file_push_literal (file, slang_asm_float_push, 13.13f);
1367 slang_assembly_file_push_literal (file, slang_asm_float_push, 12.12f);
1368 slang_assembly_file_push_literal (file, slang_asm_float_push, 11.11f);
1369 slang_assembly_file_push_literal (file, slang_asm_float_push, 10.10f);
1370 slang_assembly_file_push_literal (file, slang_asm_float_push, 9.9f);
1371 slang_assembly_file_push_literal (file, slang_asm_float_push, 8.8f);
1372 slang_assembly_file_push_literal (file, slang_asm_float_push, 7.7f);
1373 slang_assembly_file_push_literal (file, slang_asm_float_push, 6.6f);
1374 slang_assembly_file_push_literal (file, slang_asm_float_push, 5.5f);
1375 slang_assembly_file_push_literal (file, slang_asm_float_push, 4.4f);
1376 slang_assembly_file_push_literal (file, slang_asm_float_push, 3.3f);
1377 slang_assembly_file_push_literal (file, slang_asm_float_push, 2.2f);*/
1378 slang_assembly_file_push_literal (file, slang_asm_float_push, 1.1f);
1379
1380 slang_assembly_file_push_label (file, slang_asm_call, file->count + 3);
1381 slang_assembly_file_push_label (file, slang_asm_local_free, 4);
1382
1383 slang_assembly_file_push (file, slang_asm_exit);
1384 }
1385