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