05574d0e5618ccba1f6afa6beae62e86ad152bb3
[mesa.git] / src / mesa / shader / slang / slang_assemble.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.2
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_assemble.h"
33 #include "slang_compile.h"
34 #include "slang_storage.h"
35 #include "slang_error.h"
36
37 #include "slang_print.h"
38 /*#include "assemble2.c"*/
39
40 /* slang_assembly */
41
42 static GLboolean
43 slang_assembly_construct(slang_assembly * assem)
44 {
45 assem->type = slang_asm_none;
46 return GL_TRUE;
47 }
48
49 static GLvoid
50 slang_assembly_destruct(slang_assembly * assem)
51 {
52 }
53
54 /*
55 * slang_assembly_file
56 */
57
58 GLvoid
59 _slang_assembly_file_ctr(slang_assembly_file * self)
60 {
61 self->code = NULL;
62 self->count = 0;
63 self->capacity = 0;
64 }
65
66 GLvoid
67 slang_assembly_file_destruct(slang_assembly_file * file)
68 {
69 GLuint i;
70
71 for (i = 0; i < file->count; i++)
72 slang_assembly_destruct(&file->code[i]);
73 slang_alloc_free(file->code);
74 }
75
76 static GLboolean
77 push_new(slang_assembly_file * file)
78 {
79 if (file->count == file->capacity) {
80 GLuint n;
81
82 if (file->capacity == 0)
83 n = 256;
84 else
85 n = file->capacity * 2;
86 file->code = (slang_assembly *)
87 slang_alloc_realloc(file->code,
88 file->capacity * sizeof(slang_assembly),
89 n * sizeof(slang_assembly));
90 if (file->code == NULL)
91 return GL_FALSE;
92 file->capacity = n;
93 }
94 if (!slang_assembly_construct(&file->code[file->count]))
95 return GL_FALSE;
96 file->count++;
97 return GL_TRUE;
98 }
99
100 static GLboolean
101 push_gen(slang_assembly_file * file, slang_assembly_type type,
102 GLfloat literal, GLuint label, GLuint size)
103 {
104 slang_assembly *assem;
105
106 #if 0
107 printf("Gen %s %f %d %d\n", slang_asm_string(type), literal, label, size);
108 #endif
109 if (!push_new(file))
110 return GL_FALSE;
111 assem = &file->code[file->count - 1];
112 assem->type = type;
113 assem->literal = literal;
114 assem->param[0] = label;
115 assem->param[1] = size;
116 return GL_TRUE;
117 }
118
119 GLboolean
120 slang_assembly_file_push(slang_assembly_file * file, slang_assembly_type type)
121 {
122 return push_gen(file, type, (GLfloat) 0, 0, 0);
123 }
124
125 GLboolean
126 slang_assembly_file_push_label(slang_assembly_file * file,
127 slang_assembly_type type, GLuint label)
128 {
129 return push_gen(file, type, (GLfloat) 0, label, 0);
130 }
131
132 GLboolean
133 slang_assembly_file_push_label2(slang_assembly_file * file,
134 slang_assembly_type type, GLuint label1,
135 GLuint label2)
136 {
137 return push_gen(file, type, (GLfloat) 0, label1, label2);
138 }
139
140 GLboolean
141 slang_assembly_file_push_literal(slang_assembly_file * file,
142 slang_assembly_type type, GLfloat literal)
143 {
144 return push_gen(file, type, literal, 0, 0);
145 }
146
147 #define PUSH slang_assembly_file_push
148 #define PLAB slang_assembly_file_push_label
149 #define PLAB2 slang_assembly_file_push_label2
150 #define PLIT slang_assembly_file_push_literal
151
152 /* slang_assembly_file_restore_point */
153
154 GLboolean
155 slang_assembly_file_restore_point_save(slang_assembly_file * file,
156 slang_assembly_file_restore_point *
157 point)
158 {
159 point->count = file->count;
160 return GL_TRUE;
161 }
162
163 GLboolean
164 slang_assembly_file_restore_point_load(slang_assembly_file * file,
165 slang_assembly_file_restore_point *
166 point)
167 {
168 GLuint i;
169
170 for (i = point->count; i < file->count; i++)
171 slang_assembly_destruct(&file->code[i]);
172 file->count = point->count;
173 return GL_TRUE;
174 }
175
176 /* utility functions */
177
178 static GLboolean
179 sizeof_variable(const slang_assemble_ctx * A, slang_type_specifier * spec,
180 slang_type_qualifier qual, GLuint array_len, GLuint * size)
181 {
182 slang_storage_aggregate agg;
183
184 /* calculate the size of the variable's aggregate */
185 if (!slang_storage_aggregate_construct(&agg))
186 return GL_FALSE;
187 if (!_slang_aggregate_variable(&agg, spec, array_len, A->space.funcs,
188 A->space.structs, A->space.vars, A->mach,
189 A->file, A->atoms)) {
190 slang_storage_aggregate_destruct(&agg);
191 return GL_FALSE;
192 }
193 *size += _slang_sizeof_aggregate(&agg);
194 slang_storage_aggregate_destruct(&agg);
195
196 /* for reference variables consider the additional address overhead */
197 if (qual == slang_qual_out || qual == slang_qual_inout)
198 *size += 4;
199
200 return GL_TRUE;
201 }
202
203 static GLboolean
204 sizeof_variable2(slang_assemble_ctx * A, slang_variable * var, GLuint * size)
205 {
206 var->address = *size;
207 if (var->type.qualifier == slang_qual_out
208 || var->type.qualifier == slang_qual_inout)
209 var->address += 4;
210 return sizeof_variable(A, &var->type.specifier, var->type.qualifier,
211 var->array_len, size);
212 }
213
214 static GLboolean
215 sizeof_variables(slang_assemble_ctx * A, slang_variable_scope * vars,
216 GLuint start, GLuint stop, GLuint * size)
217 {
218 GLuint i;
219
220 for (i = start; i < stop; i++)
221 if (!sizeof_variable2(A, &vars->variables[i], size))
222 return GL_FALSE;
223 return GL_TRUE;
224 }
225
226 static GLboolean
227 collect_locals(slang_assemble_ctx * A, slang_operation * op, GLuint * size)
228 {
229 GLuint i;
230
231 if (!sizeof_variables(A, op->locals, 0, op->locals->num_variables, size))
232 return GL_FALSE;
233 for (i = 0; i < op->num_children; i++)
234 if (!collect_locals(A, &op->children[i], size))
235 return GL_FALSE;
236 return GL_TRUE;
237 }
238
239 /* _slang_locate_function() */
240
241 /**
242 * Locate a function by comparing actual arguments against formal parameters.
243 */
244 slang_function *
245 _slang_locate_function(const slang_function_scope * funcs, slang_atom a_name,
246 const slang_operation * args, GLuint num_args,
247 const slang_assembly_name_space * space,
248 slang_atom_pool * atoms)
249 {
250 GLuint i;
251
252 for (i = 0; i < funcs->num_functions; i++) {
253 slang_function *f = &funcs->functions[i];
254 const GLuint haveRetValue = _slang_function_has_return_value(f);
255 GLuint j;
256
257 if (a_name != f->header.a_name)
258 continue;
259 if (f->param_count - haveRetValue != num_args)
260 continue;
261
262 /* compare parameter / argument types */
263 for (j = 0; j < num_args; j++) {
264 slang_assembly_typeinfo ti;
265
266 if (!slang_assembly_typeinfo_construct(&ti))
267 return NULL;
268 if (!_slang_typeof_operation_(&args[j], space, &ti, atoms)) {
269 slang_assembly_typeinfo_destruct(&ti);
270 return NULL;
271 }
272 if (!slang_type_specifier_equal(&ti.spec,
273 &f->parameters->variables[j/* + haveRetValue*/].type.specifier)) {
274 slang_assembly_typeinfo_destruct(&ti);
275 break;
276 }
277 slang_assembly_typeinfo_destruct(&ti);
278
279 /* "out" and "inout" formal parameter requires the actual parameter to be l-value */
280 if (!ti.can_be_referenced &&
281 (f->parameters->variables[j/* + haveRetValue*/].type.qualifier == slang_qual_out ||
282 f->parameters->variables[j/* + haveRetValue*/].type.qualifier == slang_qual_inout))
283 break;
284 }
285 if (j == num_args)
286 return f;
287 }
288 if (funcs->outer_scope != NULL)
289 return _slang_locate_function(funcs->outer_scope, a_name, args,
290 num_args, space, atoms);
291 return NULL;
292 }
293
294
295
296 /**
297 * Generate assembly for a parsed function.
298 */
299 GLboolean
300 _slang_assemble_function(slang_assemble_ctx * A, slang_function * fun)
301 {
302 GLuint param_size, local_size;
303 GLuint skip, cleanup;
304 const GLuint haveRetValue = _slang_function_has_return_value(fun);
305
306 fun->address = A->file->count;
307
308 if (fun->body == NULL) {
309 /* jump to the actual function body - we do not know it, so add
310 * the instruction to fixup table
311 */
312 if (!slang_fixup_save(&fun->fixups, fun->address))
313 RETURN_NIL();
314 if (!PUSH(A->file, slang_asm_jump))
315 RETURN_OUT_OF_MEMORY();
316 return GL_TRUE;
317 }
318 else {
319 /* resolve all fixup table entries and delete it */
320 GLuint i;
321 for (i = 0; i < fun->fixups.count; i++)
322 A->file->code[fun->fixups.table[i]].param[0] = fun->address;
323 slang_fixup_table_free(&fun->fixups);
324 }
325
326 /* At this point traverse function formal parameters and code to calculate
327 * total memory size to be allocated on the stack.
328 * During this process the variables will be assigned local addresses to
329 * reference them in the code.
330 * No storage optimizations are performed so exclusive scopes are not
331 * detected and shared.
332 */
333
334 /* calculate return value size */
335 param_size = 0;
336 if (fun->header.type.specifier.type != slang_spec_void) {
337 if (!sizeof_variable(A, &fun->header.type.specifier,
338 slang_qual_none, 0, &param_size))
339 RETURN_NIL();
340 }
341 A->local.ret_size = param_size;
342
343 /* calculate formal parameter list size */
344 if (!sizeof_variables(A, fun->parameters,
345 0,
346 fun->param_count - haveRetValue, &param_size))
347 RETURN_NIL();
348
349 /* calculate local variables size - take into account the four-byte
350 * return address and temporaries for various tasks (4 for addr and
351 * 16 for swizzle temporaries). these include variables from the
352 * formal parameter scope and from the code
353 */
354 A->local.addr_tmp = param_size + 4;
355 A->local.swizzle_tmp = param_size + 4 + 4;
356 local_size = param_size + 4 + 4 + 16;
357 if (!sizeof_variables(A, fun->parameters, fun->param_count,
358 fun->parameters->num_variables, &local_size)) {
359 RETURN_OUT_OF_MEMORY();
360 }
361 if (!collect_locals(A, fun->body, &local_size))
362 RETURN_NIL();
363
364 /* allocate local variable storage */
365 if (!PLAB(A->file, slang_asm_local_alloc, local_size - param_size - 4))
366 RETURN_OUT_OF_MEMORY();
367
368 /* mark a new frame for function variable storage */
369 if (!PLAB(A->file, slang_asm_enter, local_size))
370 RETURN_OUT_OF_MEMORY();
371
372 /* jump directly to the actual code */
373 skip = A->file->count;
374 if (!push_new(A->file))
375 RETURN_OUT_OF_MEMORY();
376 A->file->code[skip].type = slang_asm_jump;
377
378 /* all "return" statements will be directed here */
379 A->flow.function_end = A->file->count;
380 cleanup = A->file->count;
381 if (!push_new(A->file))
382 RETURN_OUT_OF_MEMORY();
383 A->file->code[cleanup].type = slang_asm_jump;
384
385 /* execute the function body */
386 A->file->code[skip].param[0] = A->file->count;
387 if (!_slang_assemble_operation(A, fun->body,
388 /*slang_ref_freelance */ slang_ref_forbid))
389 RETURN_NIL();
390
391 /* this is the end of the function - restore the old function frame */
392 A->file->code[cleanup].param[0] = A->file->count;
393 if (!PUSH(A->file, slang_asm_leave))
394 RETURN_OUT_OF_MEMORY();
395
396 /* free local variable storage */
397 if (!PLAB(A->file, slang_asm_local_free, local_size - param_size - 4))
398 RETURN_OUT_OF_MEMORY();
399
400 /* return from the function */
401 if (!PUSH(A->file, slang_asm_return))
402 RETURN_OUT_OF_MEMORY();
403
404 return GL_TRUE;
405 }
406
407 GLboolean
408 _slang_cleanup_stack(slang_assemble_ctx * A, slang_operation * op)
409 {
410 slang_assembly_typeinfo ti;
411 GLuint size = 0;
412
413 /* get type info of the operation and calculate its size */
414 if (!slang_assembly_typeinfo_construct(&ti))
415 return GL_FALSE;
416 if (!_slang_typeof_operation(A, op, &ti)) {
417 slang_assembly_typeinfo_destruct(&ti);
418 return GL_FALSE;
419 }
420 if (ti.spec.type != slang_spec_void) {
421 if (A->ref == slang_ref_force) {
422 size = 4;
423 }
424 else if (!sizeof_variable(A, &ti.spec, slang_qual_none, 0, &size)) {
425 slang_assembly_typeinfo_destruct(&ti);
426 return GL_FALSE;
427 }
428 }
429 slang_assembly_typeinfo_destruct(&ti);
430
431 /* if nonzero, free it from the stack */
432 if (size != 0) {
433 if (!PLAB(A->file, slang_asm_local_free, size))
434 return GL_FALSE;
435 }
436
437 return GL_TRUE;
438 }
439
440 /* _slang_assemble_operation() */
441
442 static GLboolean
443 dereference_basic(slang_assemble_ctx * A, slang_storage_type type,
444 GLuint * size, slang_swizzle * swz, GLboolean is_swizzled)
445 {
446 GLuint src_offset;
447 slang_assembly_type ty;
448
449 *size -= _slang_sizeof_type(type);
450
451 /* If swizzling is taking place, we are forced to use scalar
452 * operations, even if we have vec4 instructions enabled (this
453 * should be actually done with special vec4 shuffle instructions).
454 * Adjust the size and calculate the offset within source variable
455 * to read.
456 */
457 if (is_swizzled)
458 src_offset = swz->swizzle[*size / 4] * 4;
459 else
460 src_offset = *size;
461
462 /* dereference data slot of a basic type */
463 if (!PLAB2(A->file, slang_asm_local_addr, A->local.addr_tmp, 4))
464 return GL_FALSE;
465 if (!PUSH(A->file, slang_asm_addr_deref))
466 return GL_FALSE;
467 if (src_offset != 0) {
468 if (!PLAB(A->file, slang_asm_addr_push, src_offset))
469 return GL_FALSE;
470 if (!PUSH(A->file, slang_asm_addr_add))
471 return GL_FALSE;
472 }
473
474 switch (type) {
475 case slang_stor_bool:
476 ty = slang_asm_bool_deref;
477 break;
478 case slang_stor_int:
479 ty = slang_asm_int_deref;
480 break;
481 case slang_stor_float:
482 ty = slang_asm_float_deref;
483 break;
484 #if defined(USE_X86_ASM) || defined(SLANG_X86)
485 case slang_stor_vec4:
486 ty = slang_asm_vec4_deref;
487 break;
488 #endif
489 default:
490 _mesa_problem(NULL, "Unexpected arr->type in dereference_basic");
491 ty = slang_asm_none;
492 }
493
494 return PUSH(A->file, ty);
495 }
496
497 static GLboolean
498 dereference_aggregate(slang_assemble_ctx * A,
499 const slang_storage_aggregate * agg, GLuint * size,
500 slang_swizzle * swz, GLboolean is_swizzled)
501 {
502 GLuint i;
503
504 for (i = agg->count; i > 0; i--) {
505 const slang_storage_array *arr = &agg->arrays[i - 1];
506 GLuint j;
507
508 for (j = arr->length; j > 0; j--) {
509 if (arr->type == slang_stor_aggregate) {
510 if (!dereference_aggregate(A, arr->aggregate, size,
511 swz, is_swizzled))
512 return GL_FALSE;
513 }
514 else {
515 if (is_swizzled && arr->type == slang_stor_vec4) {
516 if (!dereference_basic(A, slang_stor_float, size, swz, is_swizzled))
517 return GL_FALSE;
518 if (!dereference_basic(A, slang_stor_float, size, swz, is_swizzled))
519 return GL_FALSE;
520 if (!dereference_basic(A, slang_stor_float, size, swz, is_swizzled))
521 return GL_FALSE;
522 if (!dereference_basic(A, slang_stor_float, size, swz, is_swizzled))
523 return GL_FALSE;
524 }
525 else {
526 if (!dereference_basic(A, arr->type, size, swz, is_swizzled))
527 return GL_FALSE;
528 }
529 }
530 }
531 }
532
533 return GL_TRUE;
534 }
535
536 GLboolean
537 _slang_dereference(slang_assemble_ctx * A, slang_operation * op)
538 {
539 slang_assembly_typeinfo ti;
540 GLboolean result = GL_FALSE;
541 slang_storage_aggregate agg;
542 GLuint size;
543
544 /* get type information of the given operation */
545 if (!slang_assembly_typeinfo_construct(&ti))
546 return GL_FALSE;
547 if (!_slang_typeof_operation(A, op, &ti))
548 goto end1;
549
550 /* construct aggregate from the type info */
551 if (!slang_storage_aggregate_construct(&agg))
552 goto end1;
553 if (!_slang_aggregate_variable(&agg, &ti.spec, ti.array_len, A->space.funcs,
554 A->space.structs, A->space.vars, A->mach,
555 A->file, A->atoms))
556 goto end;
557
558 /* dereference the resulting aggregate */
559 size = _slang_sizeof_aggregate(&agg);
560 result = dereference_aggregate(A, &agg, &size, &ti.swz, ti.is_swizzled);
561
562 end:
563 slang_storage_aggregate_destruct(&agg);
564 end1:
565 slang_assembly_typeinfo_destruct(&ti);
566 return result;
567 }
568
569
570 /**
571 * Assemble a function call, given a pointer to the actual function to call.
572 */
573 GLboolean
574 _slang_assemble_function_call(slang_assemble_ctx * A, slang_function * fun,
575 slang_operation * params, GLuint param_count,
576 GLboolean assignment)
577 {
578 GLuint i;
579 slang_swizzle p_swz[64];
580 slang_ref_type p_ref[64];
581 /*
582 const GLuint haveRetValue = _slang_function_has_return_value(fun);
583 */
584
585 /* TODO: fix this, allocate dynamically */
586 if (param_count > 64)
587 return GL_FALSE;
588
589 /* make room for the return value, if any */
590 if (fun->header.type.specifier.type != slang_spec_void) {
591 GLuint ret_size = 0;
592
593 if (!sizeof_variable(A, &fun->header.type.specifier,
594 slang_qual_none, 0, &ret_size))
595 return GL_FALSE;
596 if (!PLAB(A->file, slang_asm_local_alloc, ret_size))
597 return GL_FALSE;
598 }
599
600 /* push the actual parameters on the stack */
601 for (i = 0; i < param_count; i++) {
602 if (fun->parameters->variables[i /*+ haveRetValue*/].type.qualifier == slang_qual_inout ||
603 fun->parameters->variables[i /*+ haveRetValue*/].type.qualifier == slang_qual_out) {
604 if (!PLAB2(A->file, slang_asm_local_addr, A->local.addr_tmp, 4))
605 return GL_FALSE;
606 /* TODO: optimize the "out" parameter case */
607 if (!_slang_assemble_operation(A, &params[i], slang_ref_force))
608 return GL_FALSE;
609 p_swz[i] = A->swz;
610 p_ref[i] = A->ref;
611 if (!PUSH(A->file, slang_asm_addr_copy))
612 return GL_FALSE;
613 if (!PUSH(A->file, slang_asm_addr_deref))
614 return GL_FALSE;
615 if (i == 0 && assignment) {
616 /* duplicate the resulting address */
617 if (!PLAB2(A->file, slang_asm_local_addr, A->local.addr_tmp, 4))
618 return GL_FALSE;
619 if (!PUSH(A->file, slang_asm_addr_deref))
620 return GL_FALSE;
621 }
622 if (!_slang_dereference(A, &params[i]))
623 return GL_FALSE;
624 }
625 else {
626 if (!_slang_assemble_operation(A, &params[i], slang_ref_forbid))
627 return GL_FALSE;
628 p_swz[i] = A->swz;
629 p_ref[i] = A->ref;
630 }
631 }
632
633 /* call the function */
634 #if 0
635 printf("CALL FUNCTION %s\n", (char*) fun->header.a_name);
636 slang_print_var_scope(fun->parameters, fun->param_count);
637 #endif
638 if (!PLAB(A->file, slang_asm_call, fun->address))
639 return GL_FALSE;
640
641 /* pop the parameters from the stack */
642 for (i = param_count; i > 0; i--) {
643 GLuint j = i - 1;
644
645 A->swz = p_swz[j];
646 A->ref = p_ref[j];
647 if (fun->parameters->variables[j /*+ haveRetValue*/].type.qualifier == slang_qual_inout ||
648 fun->parameters->variables[j/* + haveRetValue*/].type.qualifier == slang_qual_out) {
649 /* for output parameter copy the contents of the formal parameter
650 * back to the original actual parameter
651 */
652 if (!_slang_assemble_assignment(A, &params[j]))
653 return GL_FALSE;
654 /* pop the actual parameter's address */
655 if (!PLAB(A->file, slang_asm_local_free, 4))
656 return GL_FALSE;
657 }
658 else {
659 /* pop the value of the parameter */
660 if (!_slang_cleanup_stack(A, &params[j]))
661 return GL_FALSE;
662 }
663 }
664
665 return GL_TRUE;
666 }
667
668
669 /**
670 * Assemble a function call, given the name of the function to call and a
671 * list of parameters.
672 */
673 GLboolean
674 _slang_assemble_function_call_name(slang_assemble_ctx * A, const char *name,
675 slang_operation * params,
676 GLuint param_count, GLboolean assignment)
677 {
678 slang_atom atom;
679 slang_function *fun;
680
681 atom = slang_atom_pool_atom(A->atoms, name);
682 if (atom == SLANG_ATOM_NULL)
683 return GL_FALSE;
684 fun =
685 _slang_locate_function(A->space.funcs, atom, params, param_count,
686 &A->space, A->atoms);
687 {
688 char *s = (char *) name;
689 if (strcmp(name, "vec4") == 0)
690 printf("LLLLLLLLLLLLLLL locate %s %p\n", s, (void*) fun);
691 }
692
693 if (fun == NULL)
694 return GL_FALSE;
695 return _slang_assemble_function_call(A, fun, params, param_count,
696 assignment);
697 }
698
699 static GLboolean
700 assemble_function_call_name_dummyint(slang_assemble_ctx * A, const char *name,
701 slang_operation * params)
702 {
703 slang_operation p[2];
704 GLboolean result;
705
706 p[0] = params[0];
707 if (!slang_operation_construct(&p[1]))
708 return GL_FALSE;
709 p[1].type = slang_oper_literal_int;
710 result = _slang_assemble_function_call_name(A, name, p, 2, GL_FALSE);
711 slang_operation_destruct(&p[1]);
712 return result;
713 }
714
715 static const struct
716 {
717 const char *name;
718 slang_assembly_type code1, code2;
719 } inst[] = {
720 /* core */
721 {"float_add", slang_asm_float_add, slang_asm_float_copy},
722 {"float_subtract", slang_asm_float_subtract, slang_asm_float_copy},
723 {"float_multiply", slang_asm_float_multiply, slang_asm_float_copy},
724 {"float_divide", slang_asm_float_divide, slang_asm_float_copy},
725 {"float_negate", slang_asm_float_negate, slang_asm_float_copy},
726 {"float_min", slang_asm_float_min, slang_asm_float_copy},
727 {"float_max", slang_asm_float_max, slang_asm_float_copy},
728 {"float_less", slang_asm_float_less, slang_asm_bool_copy},
729 {"float_equal", slang_asm_float_equal_exp, slang_asm_bool_copy},
730 {"float_to_int", slang_asm_float_to_int, slang_asm_int_copy},
731 {"float_sine", slang_asm_float_sine, slang_asm_float_copy},
732 {"float_cosine", slang_asm_float_cosine, slang_asm_float_copy},
733 {"float_arcsine", slang_asm_float_arcsine, slang_asm_float_copy},
734 {"float_arctan", slang_asm_float_arctan, slang_asm_float_copy},
735 {"float_power", slang_asm_float_power, slang_asm_float_copy},
736 {"float_exp", slang_asm_float_exp, slang_asm_float_copy},
737 {"float_exp2", slang_asm_float_exp2, slang_asm_float_copy},
738 {"float_rsq", slang_asm_float_rsq, slang_asm_float_copy},
739 {"float_rcp", slang_asm_float_rcp, slang_asm_float_copy},
740 {"float_log2", slang_asm_float_log2, slang_asm_float_copy},
741 {"float_ceil", slang_asm_float_ceil, slang_asm_float_copy},
742 {"float_noise1", slang_asm_float_noise1, slang_asm_float_copy},
743 {"float_noise2", slang_asm_float_noise2, slang_asm_float_copy},
744 {"float_noise3", slang_asm_float_noise3, slang_asm_float_copy},
745 {"float_noise4", slang_asm_float_noise4, slang_asm_float_copy},
746 {"int_to_float", slang_asm_int_to_float, slang_asm_float_copy},
747 {"vec4_tex1d", slang_asm_vec4_tex1d, slang_asm_none},
748 {"vec4_texb1d", slang_asm_vec4_tex1d, slang_asm_none},
749 {"vec4_texp1d", slang_asm_vec4_tex1d, slang_asm_none},
750 {"vec4_tex2d", slang_asm_vec4_tex2d, slang_asm_none},
751 {"vec4_texb2d", slang_asm_vec4_tex2d, slang_asm_none},
752 {"vec4_texp2d", slang_asm_vec4_tex2d, slang_asm_none},
753 {"vec4_tex3d", slang_asm_vec4_tex3d, slang_asm_none},
754 {"vec4_texb3d", slang_asm_vec4_tex3d, slang_asm_none},
755 {"vec4_texp3d", slang_asm_vec4_tex3d, slang_asm_none},
756 {"vec4_texcube", slang_asm_vec4_texcube, slang_asm_none},
757 {"vec4_shad1d", slang_asm_vec4_shad1d, slang_asm_none},
758 {"vec4_shad2d", slang_asm_vec4_shad2d, slang_asm_none},
759 {"vec4_ddx", 0, slang_asm_none},
760 {"vec4_ddy", 0, slang_asm_none},
761 /* GL_MESA_shader_debug */
762 {"float_print", slang_asm_float_deref, slang_asm_float_print},
763 {"int_print", slang_asm_int_deref, slang_asm_int_print},
764 {"bool_print", slang_asm_bool_deref, slang_asm_bool_print},
765 /* vec4 */
766 {"float_to_vec4", slang_asm_float_to_vec4, slang_asm_none},
767 {"vec4_add", slang_asm_vec4_add, slang_asm_float_copy},
768 {"vec4_subtract", slang_asm_vec4_subtract, slang_asm_float_copy},
769 {"vec4_multiply", slang_asm_vec4_multiply, slang_asm_float_copy},
770 {"vec4_min", slang_asm_vec4_min, slang_asm_float_copy},
771 {"vec4_max", slang_asm_vec4_max, slang_asm_float_copy},
772 {"vec4_seq", slang_asm_vec4_seq, slang_asm_float_copy},
773 {"vec4_sne", slang_asm_vec4_sne, slang_asm_float_copy},
774 {"vec4_sge", slang_asm_vec4_sge, slang_asm_float_copy},
775 {"vec4_sgt", slang_asm_vec4_sgt, slang_asm_float_copy},
776 {"vec4_floor", slang_asm_vec4_floor, slang_asm_float_copy},
777 {"vec4_frac", slang_asm_vec4_frac, slang_asm_float_copy},
778 {"vec4_abs", slang_asm_vec4_abs, slang_asm_float_copy},
779
780 {"vec4_divide", slang_asm_vec4_divide, slang_asm_none},
781 {"vec4_negate", slang_asm_vec4_negate, slang_asm_none},
782 {"vec4_dot", slang_asm_vec4_dot, slang_asm_float_copy},
783 {"vec3_dot", slang_asm_vec3_dot, slang_asm_float_copy},
784 {"vec3_cross", slang_asm_vec3_cross, slang_asm_float_copy},
785 {NULL, slang_asm_none, slang_asm_none}
786 };
787
788 static GLboolean
789 call_asm_instruction(slang_assemble_ctx * A, slang_atom a_name)
790 {
791 const char *id;
792 GLuint i;
793
794 id = slang_atom_pool_id(A->atoms, a_name);
795
796 for (i = 0; inst[i].name != NULL; i++)
797 if (slang_string_compare(id, inst[i].name) == 0)
798 break;
799 if (inst[i].name == NULL)
800 return GL_FALSE;
801
802 if (!PLAB2(A->file, inst[i].code1, 4, 0))
803 return GL_FALSE;
804 if (inst[i].code2 != slang_asm_none)
805 if (!PLAB2(A->file, inst[i].code2, 4, 0))
806 return GL_FALSE;
807
808 /* clean-up the stack from the remaining dst address */
809 if (!PLAB(A->file, slang_asm_local_free, 4))
810 return GL_FALSE;
811
812 return GL_TRUE;
813 }
814
815 static GLboolean
816 equality_aggregate(slang_assemble_ctx * A,
817 const slang_storage_aggregate * agg, GLuint * index,
818 GLuint size, GLuint z_label)
819 {
820 GLuint i;
821
822 for (i = 0; i < agg->count; i++) {
823 const slang_storage_array *arr = &agg->arrays[i];
824 GLuint j;
825
826 for (j = 0; j < arr->length; j++) {
827 if (arr->type == slang_stor_aggregate) {
828 if (!equality_aggregate(A, arr->aggregate, index, size, z_label))
829 return GL_FALSE;
830 }
831 else {
832 #if defined(USE_X86_ASM) || defined(SLANG_X86)
833 if (arr->type == slang_stor_vec4) {
834 if (!PLAB2(A->file, slang_asm_vec4_equal_int,
835 size + *index, *index))
836 return GL_FALSE;
837 }
838 else
839 #endif
840 if (!PLAB2(A->file, slang_asm_float_equal_int,
841 size + *index, *index))
842 return GL_FALSE;
843
844 *index += _slang_sizeof_type(arr->type);
845 if (!PLAB(A->file, slang_asm_jump_if_zero, z_label))
846 return GL_FALSE;
847 }
848 }
849 }
850
851 return GL_TRUE;
852 }
853
854 static GLboolean
855 equality(slang_assemble_ctx * A, slang_operation * op, GLboolean equal)
856 {
857 slang_assembly_typeinfo ti;
858 GLboolean result = GL_FALSE;
859 slang_storage_aggregate agg;
860 GLuint index, size;
861 GLuint skip_jump, true_label, true_jump, false_label, false_jump;
862
863 /* get type of operation */
864 if (!slang_assembly_typeinfo_construct(&ti))
865 RETURN_OUT_OF_MEMORY();
866 if (!_slang_typeof_operation(A, op, &ti))
867 goto end1;
868
869 /* convert it to an aggregate */
870 if (!slang_storage_aggregate_construct(&agg))
871 goto end1;
872 if (!_slang_aggregate_variable(&agg, &ti.spec, 0, A->space.funcs,
873 A->space.structs, A->space.vars,
874 A->mach, A->file, A->atoms))
875 goto end;
876
877 /* compute the size of the agregate - there are two such aggregates
878 * on the stack
879 */
880 size = _slang_sizeof_aggregate(&agg);
881
882 /* jump to the actual data-comparison code */
883 skip_jump = A->file->count;
884 if (!PUSH(A->file, slang_asm_jump))
885 goto end;
886
887 /* pop off the stack the compared data and push 1 */
888 true_label = A->file->count;
889 if (!PLAB(A->file, slang_asm_local_free, size * 2))
890 goto end;
891 if (!PLIT(A->file, slang_asm_bool_push, (GLfloat) 1))
892 goto end;
893 true_jump = A->file->count;
894 if (!PUSH(A->file, slang_asm_jump))
895 goto end;
896
897 false_label = A->file->count;
898 if (!PLAB(A->file, slang_asm_local_free, size * 2))
899 goto end;
900 if (!PLIT(A->file, slang_asm_bool_push, (GLfloat) 0))
901 goto end;
902 false_jump = A->file->count;
903 if (!PUSH(A->file, slang_asm_jump))
904 goto end;
905
906 A->file->code[skip_jump].param[0] = A->file->count;
907
908 /* compare the data on stack, it will eventually jump either to
909 * true or false label
910 */
911 index = 0;
912 if (!equality_aggregate(A, &agg, &index, size,
913 equal ? false_label : true_label))
914 goto end;
915 if (!PLAB(A->file, slang_asm_jump, equal ? true_label : false_label))
916 goto end;
917
918 A->file->code[true_jump].param[0] = A->file->count;
919 A->file->code[false_jump].param[0] = A->file->count;
920
921 result = GL_TRUE;
922 end:
923 slang_storage_aggregate_destruct(&agg);
924 end1:
925 slang_assembly_typeinfo_destruct(&ti);
926 return result;
927 }
928
929 static GLboolean
930 handle_subscript(slang_assemble_ctx * A, slang_assembly_typeinfo * tie,
931 slang_assembly_typeinfo * tia, slang_operation * op,
932 slang_ref_type ref)
933 {
934 GLuint asize = 0, esize = 0;
935
936 /* get type info of the master expression (matrix, vector or an array */
937 if (!_slang_typeof_operation(A, &op->children[0], tia))
938 return GL_FALSE;
939 if (!sizeof_variable(A, &tia->spec, slang_qual_none,
940 tia->array_len, &asize))
941 return GL_FALSE;
942
943 /* get type info of the result (matrix column, vector row or array element) */
944 if (!_slang_typeof_operation(A, op, tie))
945 return GL_FALSE;
946 if (!sizeof_variable(A, &tie->spec, slang_qual_none, 0, &esize))
947 return GL_FALSE;
948
949 /* assemble the master expression */
950 if (!_slang_assemble_operation(A, &op->children[0], ref))
951 return GL_FALSE;
952
953 /* when indexing an l-value swizzle, push the swizzle_tmp */
954 if (ref == slang_ref_force && tia->is_swizzled)
955 if (!PLAB2(A->file, slang_asm_local_addr, A->local.swizzle_tmp, 16))
956 return GL_FALSE;
957
958 /* assemble the subscript expression */
959 if (!_slang_assemble_operation(A, &op->children[1], slang_ref_forbid))
960 return GL_FALSE;
961
962 if (ref == slang_ref_force && tia->is_swizzled) {
963 GLuint i;
964
965 /* copy the swizzle indexes to the swizzle_tmp */
966 for (i = 0; i < tia->swz.num_components; i++) {
967 if (!PLAB2(A->file, slang_asm_local_addr, A->local.swizzle_tmp, 16))
968 return GL_FALSE;
969 if (!PLAB(A->file, slang_asm_addr_push, i * 4))
970 return GL_FALSE;
971 if (!PUSH(A->file, slang_asm_addr_add))
972 return GL_FALSE;
973 if (!PLAB(A->file, slang_asm_addr_push, tia->swz.swizzle[i]))
974 return GL_FALSE;
975 if (!PUSH(A->file, slang_asm_addr_copy))
976 return GL_FALSE;
977 if (!PLAB(A->file, slang_asm_local_free, 4))
978 return GL_FALSE;
979 }
980
981 /* offset the pushed swizzle_tmp address and dereference it */
982 if (!PUSH(A->file, slang_asm_int_to_addr))
983 return GL_FALSE;
984 if (!PLAB(A->file, slang_asm_addr_push, 4))
985 return GL_FALSE;
986 if (!PUSH(A->file, slang_asm_addr_multiply))
987 return GL_FALSE;
988 if (!PUSH(A->file, slang_asm_addr_add))
989 return GL_FALSE;
990 if (!PUSH(A->file, slang_asm_addr_deref))
991 return GL_FALSE;
992 }
993 else {
994 /* convert the integer subscript to a relative address */
995 if (!PUSH(A->file, slang_asm_int_to_addr))
996 return GL_FALSE;
997 }
998
999 if (!PLAB(A->file, slang_asm_addr_push, esize))
1000 return GL_FALSE;
1001 if (!PUSH(A->file, slang_asm_addr_multiply))
1002 return GL_FALSE;
1003
1004 if (ref == slang_ref_force) {
1005 /* offset the base address with the relative address */
1006 if (!PUSH(A->file, slang_asm_addr_add))
1007 return GL_FALSE;
1008 }
1009 else {
1010 GLuint i;
1011
1012 /* move the selected element to the beginning of the master expression */
1013 for (i = 0; i < esize; i += 4)
1014 if (!PLAB2(A->file, slang_asm_float_move,
1015 asize - esize + i + 4, i + 4))
1016 return GL_FALSE;
1017 if (!PLAB(A->file, slang_asm_local_free, 4))
1018 return GL_FALSE;
1019
1020 /* free the rest of the master expression */
1021 if (!PLAB(A->file, slang_asm_local_free, asize - esize))
1022 return GL_FALSE;
1023 }
1024
1025 return GL_TRUE;
1026 }
1027
1028 static GLboolean
1029 handle_field(slang_assemble_ctx * A, slang_assembly_typeinfo * tia,
1030 slang_assembly_typeinfo * tib, slang_operation * op,
1031 slang_ref_type ref)
1032 {
1033 /* get type info of the result (field or swizzle) */
1034 if (!_slang_typeof_operation(A, op, tia))
1035 RETURN_NIL();
1036
1037 /* get type info of the master expression being accessed (struct or vector) */
1038 if (!_slang_typeof_operation(A, &op->children[0], tib))
1039 RETURN_NIL();
1040
1041 /* if swizzling a vector in-place, the swizzle temporary is needed */
1042 if (ref == slang_ref_forbid && tia->is_swizzled)
1043 if (!PLAB2(A->file, slang_asm_local_addr, A->local.swizzle_tmp, 16))
1044 RETURN_OUT_OF_MEMORY();
1045
1046 /* assemble the master expression */
1047 if (!_slang_assemble_operation(A, &op->children[0], ref))
1048 RETURN_NIL();
1049
1050 /* assemble the field expression */
1051 if (tia->is_swizzled) {
1052 if (ref == slang_ref_force) {
1053 #if 0
1054 if (tia->swz.num_components == 1) {
1055 /* simple case - adjust the vector's address to point to
1056 * the selected component
1057 */
1058 if (!PLAB(file, slang_asm_addr_push, tia->swz.swizzle[0] * 4))
1059 RETURN_OUT_OF_MEMORY();
1060 if (!PUSH(file, slang_asm_addr_add))
1061 RETURN_OUT_OF_MEMORY();
1062 }
1063 else
1064 #endif
1065 {
1066 /* two or more vector components are being referenced -
1067 * the so-called write mask must be passed to the upper
1068 * operations and applied when assigning value to this swizzle
1069 */
1070 A->swz = tia->swz;
1071 }
1072 }
1073 else {
1074 /* swizzle the vector in-place using the swizzle temporary */
1075 if (!_slang_assemble_constructor_from_swizzle(A, &tia->swz,
1076 &tia->spec, &tib->spec))
1077 RETURN_NIL();
1078 }
1079 }
1080 else {
1081 GLuint i, struct_size = 0, field_offset = 0, field_size = 0;
1082
1083 /*
1084 * Calculate struct size, field offset and field size.
1085 */
1086 for (i = 0; i < tib->spec._struct->fields->num_variables; i++) {
1087 slang_variable *field;
1088 slang_storage_aggregate agg;
1089 GLuint size;
1090
1091 field = &tib->spec._struct->fields->variables[i];
1092 if (!slang_storage_aggregate_construct(&agg))
1093 RETURN_NIL();
1094 if (!_slang_aggregate_variable(&agg, &field->type.specifier,
1095 field->array_len, A->space.funcs,
1096 A->space.structs, A->space.vars,
1097 A->mach, A->file, A->atoms)) {
1098 slang_storage_aggregate_destruct(&agg);
1099 RETURN_NIL();
1100 }
1101 size = _slang_sizeof_aggregate(&agg);
1102 slang_storage_aggregate_destruct(&agg);
1103
1104 if (op->a_id == field->a_name) {
1105 field_size = size;
1106 field_offset = struct_size;
1107 }
1108 struct_size += size;
1109 }
1110
1111 if (ref == slang_ref_force) {
1112 GLboolean shift;
1113
1114 /*
1115 * OPTIMIZATION: If selecting first field, no address shifting
1116 * is needed.
1117 */
1118 shift = (field_offset != 0);
1119
1120 if (shift) {
1121 if (!PLAB(A->file, slang_asm_addr_push, field_offset))
1122 RETURN_OUT_OF_MEMORY();
1123 if (!PUSH(A->file, slang_asm_addr_add))
1124 RETURN_OUT_OF_MEMORY();
1125 }
1126 }
1127 else {
1128 GLboolean relocate, shrink;
1129 GLuint free_b = 0;
1130
1131 /*
1132 * OPTIMIZATION: If selecting last field, no relocation is needed.
1133 */
1134 relocate = (field_offset != (struct_size - field_size));
1135
1136 /*
1137 * OPTIMIZATION: If field and struct sizes are equal, no partial
1138 * free is needed.
1139 */
1140 shrink = (field_size != struct_size);
1141
1142 if (relocate) {
1143 GLuint i;
1144
1145 /*
1146 * Move the selected element to the end of the master expression.
1147 * Do it in reverse order to avoid overwriting itself.
1148 */
1149 if (!PLAB(A->file, slang_asm_addr_push, field_offset))
1150 RETURN_OUT_OF_MEMORY();
1151 for (i = field_size; i > 0; i -= 4)
1152 if (!PLAB2(A->file, slang_asm_float_move,
1153 struct_size - field_size + i, i))
1154 RETURN_OUT_OF_MEMORY();
1155 free_b += 4;
1156 }
1157
1158 if (shrink) {
1159 /* free the rest of the master expression */
1160 free_b += struct_size - field_size;
1161 }
1162
1163 if (free_b) {
1164 if (!PLAB(A->file, slang_asm_local_free, free_b))
1165 RETURN_OUT_OF_MEMORY();
1166 }
1167 }
1168 }
1169
1170 return GL_TRUE;
1171 }
1172
1173 GLboolean
1174 _slang_assemble_operation(slang_assemble_ctx * A, slang_operation * op,
1175 slang_ref_type ref)
1176 {
1177 /* set default results */
1178 A->ref = /*(ref == slang_ref_freelance) ? slang_ref_force : */ ref;
1179 A->swz.num_components = 0;
1180
1181 switch (op->type) {
1182 case slang_oper_block_no_new_scope:
1183 case slang_oper_block_new_scope:
1184 {
1185 GLuint i;
1186
1187 for (i = 0; i < op->num_children; i++) {
1188 if (!_slang_assemble_operation(A, &op->children[i],
1189 slang_ref_forbid /*slang_ref_freelance */ ))
1190 RETURN_NIL();
1191 if (!_slang_cleanup_stack(A, &op->children[i]))
1192 RETURN_NIL();
1193 }
1194 }
1195 break;
1196 case slang_oper_variable_decl:
1197 {
1198 GLuint i;
1199 slang_operation assign;
1200 GLboolean result;
1201
1202 /* Construct assignment expression placeholder. */
1203 if (!slang_operation_construct(&assign))
1204 RETURN_NIL();
1205 assign.type = slang_oper_assign;
1206 assign.children = slang_operation_new(2);
1207 if (assign.children == NULL) {
1208 slang_operation_destruct(&assign);
1209 RETURN_NIL();
1210 }
1211 for (assign.num_children = 0; assign.num_children < 2;
1212 assign.num_children++)
1213 if (!slang_operation_construct(&assign.children
1214 [assign.num_children])) {
1215 slang_operation_destruct(&assign);
1216 RETURN_OUT_OF_MEMORY();
1217 }
1218
1219 result = GL_TRUE;
1220 for (i = 0; i < op->num_children; i++) {
1221 slang_variable *var;
1222
1223 var =
1224 _slang_locate_variable(op->children[i].locals,
1225 op->children[i].a_id, GL_TRUE);
1226 if (var == NULL) {
1227 result = GL_FALSE;
1228 break;
1229 }
1230 if (var->initializer == NULL)
1231 continue;
1232
1233 if (!slang_operation_copy(&assign.children[0], &op->children[i])
1234 || !slang_operation_copy(&assign.children[1],
1235 var->initializer)
1236 || !_slang_assemble_assign(A, &assign, "=", slang_ref_forbid)
1237 || !_slang_cleanup_stack(A, &assign)) {
1238 result = GL_FALSE;
1239 break;
1240 }
1241 }
1242 slang_operation_destruct(&assign);
1243 if (!result)
1244 RETURN_NIL();
1245 }
1246 break;
1247 case slang_oper_asm:
1248 {
1249 GLuint i;
1250 if (!_slang_assemble_operation(A, &op->children[0], slang_ref_force))
1251 RETURN_NIL();
1252 for (i = 1; i < op->num_children; i++)
1253 if (!_slang_assemble_operation(A, &op->children[i],
1254 slang_ref_forbid))
1255 RETURN_NIL();
1256 if (!call_asm_instruction(A, op->a_id))
1257 RETURN_ERROR2("Unknown __asm call", (char*) op->a_id, 0);
1258 }
1259 break;
1260 case slang_oper_break:
1261 if (!PLAB(A->file, slang_asm_jump, A->flow.loop_end))
1262 RETURN_OUT_OF_MEMORY();
1263 break;
1264 case slang_oper_continue:
1265 if (!PLAB(A->file, slang_asm_jump, A->flow.loop_start))
1266 RETURN_OUT_OF_MEMORY();
1267 break;
1268 case slang_oper_discard:
1269 if (!PUSH(A->file, slang_asm_discard))
1270 RETURN_OUT_OF_MEMORY();
1271 if (!PUSH(A->file, slang_asm_exit))
1272 RETURN_OUT_OF_MEMORY();
1273 break;
1274 case slang_oper_return:
1275 if (A->local.ret_size != 0) {
1276 /* push the result's address */
1277 if (!PLAB2(A->file, slang_asm_local_addr, 0, A->local.ret_size))
1278 RETURN_OUT_OF_MEMORY();
1279 if (!_slang_assemble_operation(A, &op->children[0], slang_ref_forbid))
1280 RETURN_NIL();
1281
1282 A->swz.num_components = 0;
1283 /* assign the operation to the function result (it was reserved on the stack) */
1284 if (!_slang_assemble_assignment(A, op->children))
1285 RETURN_NIL();
1286
1287 if (!PLAB(A->file, slang_asm_local_free, 4))
1288 RETURN_OUT_OF_MEMORY();
1289 }
1290 if (!PLAB(A->file, slang_asm_jump, A->flow.function_end))
1291 RETURN_OUT_OF_MEMORY();
1292 break;
1293 case slang_oper_expression:
1294 if (ref == slang_ref_force)
1295 RETURN_NIL();
1296 if (!_slang_assemble_operation(A, &op->children[0], ref))
1297 RETURN_NIL();
1298 break;
1299 case slang_oper_if:
1300 if (!_slang_assemble_if(A, op))
1301 RETURN_NIL();
1302 break;
1303 case slang_oper_while:
1304 if (!_slang_assemble_while(A, op))
1305 RETURN_NIL();
1306 break;
1307 case slang_oper_do:
1308 if (!_slang_assemble_do(A, op))
1309 RETURN_NIL();
1310 break;
1311 case slang_oper_for:
1312 if (!_slang_assemble_for(A, op))
1313 RETURN_NIL();
1314 break;
1315 case slang_oper_void:
1316 break;
1317 case slang_oper_literal_bool:
1318 if (ref == slang_ref_force)
1319 RETURN_NIL();
1320 if (!PLIT(A->file, slang_asm_bool_push, op->literal[0]))
1321 RETURN_OUT_OF_MEMORY();
1322 A->ref = slang_ref_forbid;
1323 break;
1324 case slang_oper_literal_int:
1325 if (ref == slang_ref_force)
1326 RETURN_NIL();
1327 if (!PLIT(A->file, slang_asm_int_push, op->literal[0]))
1328 RETURN_OUT_OF_MEMORY();
1329 A->ref = slang_ref_forbid;
1330 break;
1331 case slang_oper_literal_float:
1332 if (ref == slang_ref_force)
1333 RETURN_NIL();
1334 if (!PLIT(A->file, slang_asm_float_push, op->literal[0]))
1335 RETURN_OUT_OF_MEMORY();
1336 A->ref = slang_ref_forbid;
1337 break;
1338 case slang_oper_identifier:
1339 {
1340 slang_variable *var;
1341 GLuint size;
1342
1343 /* find the variable and calculate its size */
1344 var = _slang_locate_variable(op->locals, op->a_id, GL_TRUE);
1345 if (var == NULL)
1346 RETURN_ERROR2("undefined variable", (char *) op->a_id, 0);
1347 size = 0;
1348 if (!sizeof_variable(A, &var->type.specifier, slang_qual_none,
1349 var->array_len, &size))
1350 RETURN_OUT_OF_MEMORY();
1351
1352 /* prepare stack for dereferencing */
1353 if (ref == slang_ref_forbid)
1354 if (!PLAB2(A->file, slang_asm_local_addr, A->local.addr_tmp, 4))
1355 RETURN_OUT_OF_MEMORY();
1356
1357 /* push the variable's address */
1358 if (var->global) {
1359 if (!PLAB(A->file, slang_asm_global_addr, var->address))
1360 RETURN_OUT_OF_MEMORY();
1361 }
1362 else {
1363 if (!PLAB2(A->file, slang_asm_local_addr, var->address, size))
1364 RETURN_OUT_OF_MEMORY();
1365 }
1366
1367 /* perform the dereference */
1368 if (ref == slang_ref_forbid) {
1369 if (!PUSH(A->file, slang_asm_addr_copy))
1370 RETURN_OUT_OF_MEMORY();
1371 if (!PLAB(A->file, slang_asm_local_free, 4))
1372 RETURN_OUT_OF_MEMORY();
1373 if (!_slang_dereference(A, op))
1374 RETURN_NIL();
1375 }
1376 }
1377 break;
1378 case slang_oper_sequence:
1379 if (ref == slang_ref_force)
1380 RETURN_NIL();
1381 if (!_slang_assemble_operation(A, &op->children[0],
1382 slang_ref_forbid /*slang_ref_freelance */ ))
1383 RETURN_NIL();
1384 if (!_slang_cleanup_stack(A, &op->children[0]))
1385 RETURN_NIL();
1386 if (!_slang_assemble_operation(A, &op->children[1], slang_ref_forbid))
1387 RETURN_NIL();
1388 A->ref = slang_ref_forbid;
1389 break;
1390 case slang_oper_assign:
1391 if (!_slang_assemble_assign(A, op, "=", ref))
1392 RETURN_NIL();
1393 break;
1394 case slang_oper_addassign:
1395 if (!_slang_assemble_assign(A, op, "+=", ref))
1396 RETURN_NIL();
1397 A->ref = ref;
1398 break;
1399 case slang_oper_subassign:
1400 if (!_slang_assemble_assign(A, op, "-=", ref))
1401 RETURN_NIL();
1402 A->ref = ref;
1403 break;
1404 case slang_oper_mulassign:
1405 if (!_slang_assemble_assign(A, op, "*=", ref))
1406 RETURN_NIL();
1407 A->ref = ref;
1408 break;
1409 /*case slang_oper_modassign: */
1410 /*case slang_oper_lshassign: */
1411 /*case slang_oper_rshassign: */
1412 /*case slang_oper_orassign: */
1413 /*case slang_oper_xorassign: */
1414 /*case slang_oper_andassign: */
1415 case slang_oper_divassign:
1416 if (!_slang_assemble_assign(A, op, "/=", ref))
1417 RETURN_NIL();
1418 A->ref = ref;
1419 break;
1420 case slang_oper_select:
1421 if (!_slang_assemble_select(A, op))
1422 RETURN_NIL();
1423 A->ref = slang_ref_forbid;
1424 break;
1425 case slang_oper_logicalor:
1426 if (!_slang_assemble_logicalor(A, op))
1427 RETURN_NIL();
1428 A->ref = slang_ref_forbid;
1429 break;
1430 case slang_oper_logicaland:
1431 if (!_slang_assemble_logicaland(A, op))
1432 RETURN_NIL();
1433 A->ref = slang_ref_forbid;
1434 break;
1435 case slang_oper_logicalxor:
1436 if (!_slang_assemble_function_call_name(A, "^^", op->children, 2, GL_FALSE))
1437 RETURN_NIL();
1438 A->ref = slang_ref_forbid;
1439 break;
1440 /*case slang_oper_bitor: */
1441 /*case slang_oper_bitxor: */
1442 /*case slang_oper_bitand: */
1443 case slang_oper_less:
1444 if (!_slang_assemble_function_call_name(A, "<", op->children, 2, GL_FALSE))
1445 RETURN_NIL();
1446 A->ref = slang_ref_forbid;
1447 break;
1448 case slang_oper_greater:
1449 if (!_slang_assemble_function_call_name(A, ">", op->children, 2, GL_FALSE))
1450 RETURN_NIL();
1451 A->ref = slang_ref_forbid;
1452 break;
1453 case slang_oper_lessequal:
1454 if (!_slang_assemble_function_call_name(A, "<=", op->children, 2, GL_FALSE))
1455 RETURN_NIL();
1456 A->ref = slang_ref_forbid;
1457 break;
1458 case slang_oper_greaterequal:
1459 if (!_slang_assemble_function_call_name(A, ">=", op->children, 2, GL_FALSE))
1460 RETURN_NIL();
1461 A->ref = slang_ref_forbid;
1462 break;
1463 /*case slang_oper_lshift: */
1464 /*case slang_oper_rshift: */
1465 case slang_oper_add:
1466 if (!_slang_assemble_function_call_name(A, "+", op->children, 2, GL_FALSE))
1467 RETURN_NIL();
1468 A->ref = slang_ref_forbid;
1469 break;
1470 case slang_oper_subtract:
1471 if (!_slang_assemble_function_call_name(A, "-", op->children, 2, GL_FALSE))
1472 RETURN_NIL();
1473 A->ref = slang_ref_forbid;
1474 break;
1475 case slang_oper_multiply:
1476 if (!_slang_assemble_function_call_name(A, "*", op->children, 2, GL_FALSE))
1477 RETURN_NIL();
1478 A->ref = slang_ref_forbid;
1479 break;
1480 /*case slang_oper_modulus: */
1481 case slang_oper_divide:
1482 if (!_slang_assemble_function_call_name(A, "/", op->children, 2, GL_FALSE))
1483 RETURN_NIL();
1484 A->ref = slang_ref_forbid;
1485 break;
1486 case slang_oper_equal:
1487 if (!_slang_assemble_operation(A, &op->children[0], slang_ref_forbid))
1488 RETURN_NIL();
1489 if (!_slang_assemble_operation(A, &op->children[1], slang_ref_forbid))
1490 RETURN_NIL();
1491 if (!equality(A, op->children, GL_TRUE))
1492 RETURN_NIL();
1493 A->ref = slang_ref_forbid;
1494 break;
1495 case slang_oper_notequal:
1496 if (!_slang_assemble_operation(A, &op->children[0], slang_ref_forbid))
1497 RETURN_NIL();
1498 if (!_slang_assemble_operation(A, &op->children[1], slang_ref_forbid))
1499 RETURN_NIL();
1500 if (!equality(A, op->children, GL_FALSE))
1501 RETURN_NIL();
1502 A->ref = slang_ref_forbid;
1503 break;
1504 case slang_oper_preincrement:
1505 if (!_slang_assemble_assign(A, op, "++", ref))
1506 RETURN_NIL();
1507 A->ref = ref;
1508 break;
1509 case slang_oper_predecrement:
1510 if (!_slang_assemble_assign(A, op, "--", ref))
1511 RETURN_NIL();
1512 A->ref = ref;
1513 break;
1514 case slang_oper_plus:
1515 if (!_slang_dereference(A, op))
1516 RETURN_NIL();
1517 A->ref = slang_ref_forbid;
1518 break;
1519 case slang_oper_minus:
1520 if (!_slang_assemble_function_call_name(A, "-", op->children, 1, GL_FALSE))
1521 RETURN_NIL();
1522 A->ref = slang_ref_forbid;
1523 break;
1524 /*case slang_oper_complement: */
1525 case slang_oper_not:
1526 if (!_slang_assemble_function_call_name(A, "!", op->children, 1, GL_FALSE))
1527 RETURN_NIL();
1528 A->ref = slang_ref_forbid;
1529 break;
1530 case slang_oper_subscript:
1531 {
1532 slang_assembly_typeinfo ti_arr, ti_elem;
1533
1534 if (!slang_assembly_typeinfo_construct(&ti_arr))
1535 RETURN_OUT_OF_MEMORY();
1536 if (!slang_assembly_typeinfo_construct(&ti_elem)) {
1537 slang_assembly_typeinfo_destruct(&ti_arr);
1538 RETURN_OUT_OF_MEMORY();
1539 }
1540 if (!handle_subscript(A, &ti_elem, &ti_arr, op, ref)) {
1541 slang_assembly_typeinfo_destruct(&ti_arr);
1542 slang_assembly_typeinfo_destruct(&ti_elem);
1543 RETURN_NIL();
1544 }
1545 slang_assembly_typeinfo_destruct(&ti_arr);
1546 slang_assembly_typeinfo_destruct(&ti_elem);
1547 }
1548 break;
1549 case slang_oper_call:
1550 {
1551 slang_function *fun
1552 = _slang_locate_function(A->space.funcs, op->a_id, op->children,
1553 op->num_children, &A->space, A->atoms);
1554 if (fun == NULL) {
1555 if (!_slang_assemble_constructor(A, op))
1556 RETURN_OUT_OF_MEMORY();
1557 }
1558 else {
1559 if (!_slang_assemble_function_call(A, fun, op->children,
1560 op->num_children, GL_FALSE))
1561 RETURN_NIL();
1562 }
1563 A->ref = slang_ref_forbid;
1564 }
1565 break;
1566 case slang_oper_field:
1567 {
1568 slang_assembly_typeinfo ti_after, ti_before;
1569
1570 if (!slang_assembly_typeinfo_construct(&ti_after))
1571 RETURN_OUT_OF_MEMORY();
1572 if (!slang_assembly_typeinfo_construct(&ti_before)) {
1573 slang_assembly_typeinfo_destruct(&ti_after);
1574 RETURN_OUT_OF_MEMORY();
1575 }
1576 if (!handle_field(A, &ti_after, &ti_before, op, ref)) {
1577 slang_assembly_typeinfo_destruct(&ti_after);
1578 slang_assembly_typeinfo_destruct(&ti_before);
1579 RETURN_NIL();
1580 }
1581 slang_assembly_typeinfo_destruct(&ti_after);
1582 slang_assembly_typeinfo_destruct(&ti_before);
1583 }
1584 break;
1585 case slang_oper_postincrement:
1586 if (!assemble_function_call_name_dummyint(A, "++", op->children))
1587 RETURN_NIL();
1588 A->ref = slang_ref_forbid;
1589 break;
1590 case slang_oper_postdecrement:
1591 if (!assemble_function_call_name_dummyint(A, "--", op->children))
1592 RETURN_NIL();
1593 A->ref = slang_ref_forbid;
1594 break;
1595 default:
1596 RETURN_NIL();
1597 }
1598
1599 return GL_TRUE;
1600 }