remove some test code;
[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 #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))
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))
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_a (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 goto end;
623
624 /* compute the size of the agregate - there are two such aggregates on the stack */
625 size = _slang_sizeof_aggregate (&agg);
626
627 /* jump to the actual data-comparison code */
628 skip_jump = file->count;
629 if (!(result = slang_assembly_file_push (file, slang_asm_jump)))
630 goto end;
631
632 /* pop off the stack the compared data and push 1 */
633 true_label = file->count;
634 if (!(result = slang_assembly_file_push_label (file, slang_asm_local_free, size * 2)))
635 goto end;
636 if (!(result = slang_assembly_file_push_literal (file, slang_asm_bool_push, 1.0f)))
637 goto end;
638 true_jump = file->count;
639 if (!(result = slang_assembly_file_push (file, slang_asm_jump)))
640 goto end;
641
642 false_label = file->count;
643 if (!(result = slang_assembly_file_push_label (file, slang_asm_local_free, size * 2)))
644 goto end;
645 if (!(result = slang_assembly_file_push_literal (file, slang_asm_bool_push, 0.0f)))
646 goto end;
647 false_jump = file->count;
648 if (!(result = slang_assembly_file_push (file, slang_asm_jump)))
649 goto end;
650
651 file->code[skip_jump].param[0] = file->count;
652
653 /* compare the data on stack, it will eventually jump either to true or false label */
654 index = 0;
655 if (!(result = equality_aggregate (file, &agg, &index, size, info,
656 equal ? false_label : true_label)))
657 goto end;
658 if (!(result = slang_assembly_file_push_label (file, slang_asm_jump,
659 equal ? true_label : false_label)))
660 goto end;
661
662 file->code[true_jump].param[0] = file->count;
663 file->code[false_jump].param[0] = file->count;
664
665 result = 1;
666 end:
667 slang_storage_aggregate_destruct (&agg);
668 slang_assembly_typeinfo_destruct (&ti);
669 return result;
670 }
671
672 int _slang_assemble_operation (slang_assembly_file *file, slang_operation *op, int reference,
673 slang_assembly_flow_control *flow, slang_assembly_name_space *space,
674 slang_assembly_local_info *info, slang_assembly_stack_info *stk)
675 {
676 unsigned int assem;
677
678 stk->swizzle_mask = 0;
679
680 assem = file->count;
681 if (!slang_assembly_file_push_new (file))
682 return 0;
683
684 switch (op->type)
685 {
686 case slang_oper_block_no_new_scope:
687 case slang_oper_block_new_scope:
688 {
689 unsigned int i;
690 for (i = 0; i < op->num_children; i++)
691 {
692 slang_assembly_stack_info stk;
693 if (!_slang_assemble_operation (file, op->children + i, 0, flow, space, info, &stk))
694 return 0;
695 /* TODO: pass-in stk to cleanup */
696 if (!_slang_cleanup_stack (file, op->children + i, 0, space))
697 return 0;
698 }
699 }
700 break;
701 case slang_oper_variable_decl:
702 {
703 unsigned int i;
704
705 for (i = 0; i < op->num_children; i++)
706 {
707 /* TODO: perform initialization of op->children[i] */
708 /* TODO: clean-up stack */
709 }
710 }
711 break;
712 case slang_oper_asm:
713 {
714 unsigned int i;
715 for (i = 0; i < op->num_children; i++)
716 {
717 slang_assembly_stack_info stk;
718 if (!_slang_assemble_operation (file, op->children + i, i == 0, flow, space, info,
719 &stk))
720 return 0;
721 /* TODO: inspect stk */
722 }
723 if (!call_asm_instruction (file, op->identifier))
724 return 0;
725 }
726 break;
727 case slang_oper_break:
728 file->code[assem].type = slang_asm_jump;
729 file->code[assem].param[0] = flow->loop_end;
730 break;
731 case slang_oper_continue:
732 file->code[assem].type = slang_asm_jump;
733 file->code[assem].param[0] = flow->loop_start;
734 break;
735 case slang_oper_discard:
736 file->code[assem].type = slang_asm_discard;
737 if (!slang_assembly_file_push (file, slang_asm_exit))
738 return 0;
739 break;
740 case slang_oper_return:
741 if (info->ret_size != 0)
742 {
743 slang_assembly_stack_info stk;
744 if (!slang_assembly_file_push_label2 (file, slang_asm_local_addr, 0, info->ret_size))
745 return 0;
746 if (!_slang_assemble_operation (file, op->children, 0, flow, space, info, &stk))
747 return 0;
748 /* TODO: inspect stk */
749 if (!_slang_assemble_assignment (file, op->children, space, info))
750 return 0;
751 if (!slang_assembly_file_push_label (file, slang_asm_local_free, 4))
752 return 0;
753 }
754 if (!slang_assembly_file_push_label (file, slang_asm_jump, flow->function_end))
755 return 0;
756 break;
757 case slang_oper_expression:
758 {
759 slang_assembly_stack_info stk;
760 if (!_slang_assemble_operation (file, op->children, reference, flow, space, info, &stk))
761 return 0;
762 /* TODO: inspect stk */
763 }
764 break;
765 case slang_oper_if:
766 if (!_slang_assemble_if (file, op, flow, space, info))
767 return 0;
768 break;
769 case slang_oper_while:
770 if (!_slang_assemble_while (file, op, flow, space, info))
771 return 0;
772 break;
773 case slang_oper_do:
774 if (!_slang_assemble_do (file, op, flow, space, info))
775 return 0;
776 break;
777 case slang_oper_for:
778 if (!_slang_assemble_for (file, op, flow, space, info))
779 return 0;
780 break;
781 case slang_oper_void:
782 break;
783 case slang_oper_literal_bool:
784 file->code[assem].type = slang_asm_bool_push;
785 file->code[assem].literal = op->literal;
786 break;
787 case slang_oper_literal_int:
788 file->code[assem].type = slang_asm_int_push;
789 file->code[assem].literal = op->literal;
790 break;
791 case slang_oper_literal_float:
792 file->code[assem].type = slang_asm_float_push;
793 file->code[assem].literal = op->literal;
794 break;
795 case slang_oper_identifier:
796 {
797 slang_variable *var;
798 unsigned int size;
799 var = _slang_locate_variable (op->locals, op->identifier, 1);
800 if (var == NULL)
801 return 0;
802 size = 0;
803 if (!sizeof_variable (&var->type.specifier, slang_qual_none, var->array_size, space,
804 &size))
805 return 0;
806 if (var->initializer != NULL)
807 {
808 assert (!"var->initializer, oper_identifier");
809 }
810 else
811 {
812 if (!reference)
813 {
814 if (!slang_assembly_file_push_label2 (file, slang_asm_local_addr,
815 info->addr_tmp, 4))
816 return 0;
817 }
818 /* XXX: globals! */
819 if (!slang_assembly_file_push_label2 (file, slang_asm_local_addr, var->address,
820 size))
821 return 0;
822 if (!reference)
823 {
824 if (!slang_assembly_file_push (file, slang_asm_addr_copy))
825 return 0;
826 if (!slang_assembly_file_push_label (file, slang_asm_local_free, 4))
827 return 0;
828 if (!dereference (file, op, space, info))
829 return 0;
830 }
831 }
832 }
833 break;
834 case slang_oper_sequence:
835 {
836 slang_assembly_stack_info stk;
837 if (!_slang_assemble_operation (file, op->children, 0, flow, space, info, &stk))
838 return 0;
839 /* TODO: pass-in stk to cleanup */
840 if (!_slang_cleanup_stack (file, op->children, 0, space))
841 return 0;
842 if (!_slang_assemble_operation (file, op->children + 1, 0, flow, space, info,
843 &stk))
844 return 0;
845 /* TODO: inspect stk */
846 }
847 break;
848 case slang_oper_assign:
849 if (!_slang_assemble_assign (file, op, "=", reference, space, info))
850 return 0;
851 break;
852 case slang_oper_addassign:
853 if (!_slang_assemble_assign (file, op, "+=", reference, space, info))
854 return 0;
855 break;
856 case slang_oper_subassign:
857 if (!_slang_assemble_assign (file, op, "-=", reference, space, info))
858 return 0;
859 break;
860 case slang_oper_mulassign:
861 if (!_slang_assemble_assign (file, op, "*=", reference, space, info))
862 return 0;
863 break;
864 /*case slang_oper_modassign:*/
865 /*case slang_oper_lshassign:*/
866 /*case slang_oper_rshassign:*/
867 /*case slang_oper_orassign:*/
868 /*case slang_oper_xorassign:*/
869 /*case slang_oper_andassign:*/
870 case slang_oper_divassign:
871 if (!_slang_assemble_assign (file, op, "/=", reference, space, info))
872 return 0;
873 break;
874 case slang_oper_select:
875 if (!_slang_assemble_select (file, op, flow, space, info))
876 return 0;
877 break;
878 case slang_oper_logicalor:
879 if (!_slang_assemble_logicalor (file, op, flow, space, info))
880 return 0;
881 break;
882 case slang_oper_logicaland:
883 if (!_slang_assemble_logicaland (file, op, flow, space, info))
884 return 0;
885 break;
886 case slang_oper_logicalxor:
887 if (!call_function_name (file, "^^", op->children, 2, 0, space, info))
888 return 0;
889 break;
890 /*case slang_oper_bitor:*/
891 /*case slang_oper_bitxor:*/
892 /*case slang_oper_bitand:*/
893 case slang_oper_less:
894 if (!call_function_name (file, "<", op->children, 2, 0, space, info))
895 return 0;
896 break;
897 case slang_oper_greater:
898 if (!call_function_name (file, ">", op->children, 2, 0, space, info))
899 return 0;
900 break;
901 case slang_oper_lessequal:
902 if (!call_function_name (file, "<=", op->children, 2, 0, space, info))
903 return 0;
904 break;
905 case slang_oper_greaterequal:
906 if (!call_function_name (file, ">=", op->children, 2, 0, space, info))
907 return 0;
908 break;
909 /*case slang_oper_lshift:*/
910 /*case slang_oper_rshift:*/
911 case slang_oper_add:
912 if (!call_function_name (file, "+", op->children, 2, 0, space, info))
913 return 0;
914 break;
915 case slang_oper_subtract:
916 if (!call_function_name (file, "-", op->children, 2, 0, space, info))
917 return 0;
918 break;
919 case slang_oper_multiply:
920 if (!call_function_name (file, "*", op->children, 2, 0, space, info))
921 return 0;
922 break;
923 /*case slang_oper_modulus:*/
924 case slang_oper_divide:
925 if (!call_function_name (file, "/", op->children, 2, 0, space, info))
926 return 0;
927 break;
928 case slang_oper_equal:
929 {
930 slang_assembly_stack_info stk;
931 if (!_slang_assemble_operation (file, op->children, 0, flow, space, info, &stk))
932 return 0;
933 /* TODO: inspect stk */
934 if (!_slang_assemble_operation (file, op->children + 1, 0, flow, space, info, &stk))
935 return 0;
936 /* TODO: inspect stk */
937 if (!equality (file, op->children, space, info, 1))
938 return 0;
939 }
940 break;
941 case slang_oper_notequal:
942 {
943 slang_assembly_stack_info stk;
944 if (!_slang_assemble_operation (file, op->children, 0, flow, space, info, &stk))
945 return 0;
946 /* TODO: inspect stk */
947 if (!_slang_assemble_operation (file, op->children + 1, 0, flow, space, info, &stk))
948 return 0;
949 /* TODO: inspect stk */
950 if (!equality (file, op->children, space, info, 0))
951 return 0;
952 }
953 break;
954 case slang_oper_preincrement:
955 if (!_slang_assemble_assign (file, op, "++", reference, space, info))
956 return 0;
957 break;
958 case slang_oper_predecrement:
959 if (!_slang_assemble_assign (file, op, "--", reference, space, info))
960 return 0;
961 break;
962 case slang_oper_plus:
963 if (!call_function_name (file, "+", op->children, 1, 0, space, info))
964 return 0;
965 break;
966 case slang_oper_minus:
967 if (!call_function_name (file, "-", op->children, 1, 0, space, info))
968 return 0;
969 break;
970 /*case slang_oper_complement:*/
971 case slang_oper_not:
972 if (!call_function_name (file, "!", op->children, 1, 0, space, info))
973 return 0;
974 break;
975 case slang_oper_subscript:
976 {
977 slang_assembly_stack_info _stk;
978 slang_assembly_typeinfo ti_arr, ti_elem;
979 unsigned int arr_size = 0, elem_size = 0;
980 if (!_slang_assemble_operation (file, op->children, reference, flow, space, info,
981 &_stk))
982 return 0;
983 if (!_slang_assemble_operation (file, op->children + 1, 0, flow, space, info, &_stk))
984 return 0;
985 slang_assembly_typeinfo_construct (&ti_arr);
986 if (!_slang_typeof_operation (op->children, space, &ti_arr))
987 {
988 slang_assembly_typeinfo_destruct (&ti_arr);
989 return 0;
990 }
991 if (!sizeof_variable (&ti_arr.spec, slang_qual_none, NULL, space, &arr_size))
992 {
993 slang_assembly_typeinfo_destruct (&ti_arr);
994 return 0;
995 }
996 slang_assembly_typeinfo_construct (&ti_elem);
997 if (!_slang_typeof_operation (op, space, &ti_elem))
998 {
999 slang_assembly_typeinfo_destruct (&ti_arr);
1000 slang_assembly_typeinfo_destruct (&ti_elem);
1001 return 0;
1002 }
1003 if (!sizeof_variable (&ti_elem.spec, slang_qual_none, NULL, space, &elem_size))
1004 {
1005 slang_assembly_typeinfo_destruct (&ti_arr);
1006 slang_assembly_typeinfo_destruct (&ti_elem);
1007 return 0;
1008 }
1009 if (!slang_assembly_file_push (file, slang_asm_int_to_addr))
1010 {
1011 slang_assembly_typeinfo_destruct (&ti_arr);
1012 slang_assembly_typeinfo_destruct (&ti_elem);
1013 return 0;
1014 }
1015 if (!slang_assembly_file_push_label (file, slang_asm_addr_push, elem_size))
1016 {
1017 slang_assembly_typeinfo_destruct (&ti_arr);
1018 slang_assembly_typeinfo_destruct (&ti_elem);
1019 return 0;
1020 }
1021 if (!slang_assembly_file_push (file, slang_asm_addr_multiply))
1022 {
1023 slang_assembly_typeinfo_destruct (&ti_arr);
1024 slang_assembly_typeinfo_destruct (&ti_elem);
1025 return 0;
1026 }
1027 if (reference)
1028 {
1029 if (!slang_assembly_file_push (file, slang_asm_addr_add))
1030 {
1031 slang_assembly_typeinfo_destruct (&ti_arr);
1032 slang_assembly_typeinfo_destruct (&ti_elem);
1033 return 0;
1034 }
1035 }
1036 else
1037 {
1038 unsigned int i;
1039 for (i = 0; i < elem_size; i += 4)
1040 {
1041 if (!slang_assembly_file_push_label2 (file, slang_asm_float_move,
1042 arr_size - elem_size + i + 4, i + 4))
1043 {
1044 slang_assembly_typeinfo_destruct (&ti_arr);
1045 slang_assembly_typeinfo_destruct (&ti_elem);
1046 return 0;
1047 }
1048 }
1049 if (!slang_assembly_file_push_label (file, slang_asm_local_free, 4))
1050 {
1051 slang_assembly_typeinfo_destruct (&ti_arr);
1052 slang_assembly_typeinfo_destruct (&ti_elem);
1053 return 0;
1054 }
1055 if (!slang_assembly_file_push_label (file, slang_asm_local_free,
1056 arr_size - elem_size))
1057 {
1058 slang_assembly_typeinfo_destruct (&ti_arr);
1059 slang_assembly_typeinfo_destruct (&ti_elem);
1060 return 0;
1061 }
1062 }
1063 slang_assembly_typeinfo_destruct (&ti_arr);
1064 slang_assembly_typeinfo_destruct (&ti_elem);
1065 }
1066 break;
1067 case slang_oper_call:
1068 {
1069 slang_function *fun = _slang_locate_function (op->identifier, op->children,
1070 op->num_children, space);
1071 if (fun == NULL)
1072 {
1073 if (!_slang_assemble_constructor (file, op, flow, space, info))
1074 return 0;
1075 }
1076 else
1077 {
1078 if (!call_function (file, fun, op->children, op->num_children, 0, space, info))
1079 return 0;
1080 }
1081 }
1082 break;
1083 case slang_oper_field:
1084 {
1085 slang_assembly_typeinfo ti_after, ti_before;
1086 slang_assembly_stack_info _stk;
1087 slang_assembly_typeinfo_construct (&ti_after);
1088 if (!_slang_typeof_operation (op, space, &ti_after))
1089 {
1090 slang_assembly_typeinfo_destruct (&ti_after);
1091 return 0;
1092 }
1093 slang_assembly_typeinfo_construct (&ti_before);
1094 if (!_slang_typeof_operation (op->children, space, &ti_before))
1095 {
1096 slang_assembly_typeinfo_destruct (&ti_after);
1097 slang_assembly_typeinfo_destruct (&ti_before);
1098 return 0;
1099 }
1100 if (!reference && ti_after.is_swizzled)
1101 {
1102 if (!slang_assembly_file_push_label2 (file, slang_asm_local_addr,
1103 info->swizzle_tmp, 16))
1104 {
1105 slang_assembly_typeinfo_destruct (&ti_after);
1106 slang_assembly_typeinfo_destruct (&ti_before);
1107 return 0;
1108 }
1109 }
1110 if (!_slang_assemble_operation (file, op->children, reference, flow, space, info,
1111 &_stk))
1112 {
1113 slang_assembly_typeinfo_destruct (&ti_after);
1114 slang_assembly_typeinfo_destruct (&ti_before);
1115 return 0;
1116 }
1117 /* TODO: inspect stk */
1118 if (ti_after.is_swizzled)
1119 {
1120 if (reference)
1121 {
1122 if (ti_after.swz.num_components == 1)
1123 {
1124 if (!slang_assembly_file_push_label (file, slang_asm_addr_push,
1125 ti_after.swz.swizzle[0] * 4))
1126 {
1127 slang_assembly_typeinfo_destruct (&ti_after);
1128 slang_assembly_typeinfo_destruct (&ti_before);
1129 return 0;
1130 }
1131 if (!slang_assembly_file_push (file, slang_asm_addr_add))
1132 {
1133 slang_assembly_typeinfo_destruct (&ti_after);
1134 slang_assembly_typeinfo_destruct (&ti_before);
1135 return 0;
1136 }
1137 }
1138 else
1139 {
1140 unsigned int i;
1141 for (i = 0; i < ti_after.swz.num_components; i++)
1142 stk->swizzle_mask |= 1 << ti_after.swz.swizzle[i];
1143 }
1144 }
1145 else
1146 {
1147 if (!_slang_assemble_constructor_from_swizzle (file, &ti_after.swz,
1148 &ti_after.spec, &ti_before.spec, info))
1149 {
1150 slang_assembly_typeinfo_destruct (&ti_after);
1151 slang_assembly_typeinfo_destruct (&ti_before);
1152 return 0;
1153 }
1154 }
1155 }
1156 else
1157 {
1158 if (reference)
1159 {
1160 /* TODO: struct field address */
1161 }
1162 else
1163 {
1164 /* TODO: struct field value */
1165 }
1166 }
1167 slang_assembly_typeinfo_destruct (&ti_after);
1168 slang_assembly_typeinfo_destruct (&ti_before);
1169 }
1170 break;
1171 case slang_oper_postincrement:
1172 if (!call_function_name_dummyint (file, "++", op->children, space, info))
1173 return 0;
1174 if (!dereference (file, op, space, info))
1175 return 0;
1176 break;
1177 case slang_oper_postdecrement:
1178 if (!call_function_name_dummyint (file, "--", op->children, space, info))
1179 return 0;
1180 if (!dereference (file, op, space, info))
1181 return 0;
1182 break;
1183 default:
1184 return 0;
1185 }
1186 return 1;
1187 }
1188