initial code to get texture sampling limping along
[mesa.git] / src / mesa / shader / slang / slang_codegen.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.3
4 *
5 * Copyright (C) 2005-2007 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_codegen.c
27 * Mesa GLSL code generator. Convert AST to IR tree.
28 * \author Brian Paul
29 */
30
31 #include "imports.h"
32 #include "macros.h"
33 #include "slang_assemble.h"
34 #include "slang_codegen.h"
35 #include "slang_compile.h"
36 #include "slang_storage.h"
37 #include "slang_error.h"
38 #include "slang_simplify.h"
39 #include "slang_emit.h"
40 #include "slang_ir.h"
41 #include "mtypes.h"
42 #include "program.h"
43 #include "prog_instruction.h"
44 #include "prog_parameter.h"
45 #include "slang_print.h"
46
47
48 /**
49 * XXX move these into the slang_assemble_ctx struct
50 */
51 static slang_function *CurFunction = NULL;
52 static slang_atom CurLoopBreak = 0;
53 static slang_atom CurLoopCont = 0;
54
55
56 static slang_ir_node *
57 _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper);
58
59
60 /**
61 * Map "_asm foo" to IR_FOO, etc.
62 */
63 typedef struct
64 {
65 const char *Name;
66 slang_ir_opcode Opcode;
67 GLuint HaveRetValue, NumParams;
68 } slang_asm_info;
69
70
71 static slang_asm_info AsmInfo[] = {
72 /* vec4 binary op */
73 { "vec4_add", IR_ADD, 1, 2 },
74 { "vec4_multiply", IR_MUL, 1, 2 },
75 { "vec4_dot", IR_DOT4, 1, 2 },
76 { "vec3_dot", IR_DOT3, 1, 2 },
77 { "vec3_cross", IR_CROSS, 1, 2 },
78 { "vec4_min", IR_MIN, 1, 2 },
79 { "vec4_max", IR_MAX, 1, 2 },
80 { "vec4_seq", IR_SEQ, 1, 2 },
81 { "vec4_sge", IR_SGE, 1, 2 },
82 { "vec4_sgt", IR_SGT, 1, 2 },
83 /* vec4 unary */
84 { "vec4_floor", IR_FLOOR, 1, 1 },
85 { "vec4_frac", IR_FRAC, 1, 1 },
86 { "vec4_abs", IR_ABS, 1, 1 },
87 { "vec4_negate", IR_NEG, 1, 1 },
88 /* float binary op */
89 { "float_add", IR_ADD, 1, 2 },
90 { "float_subtract", IR_SUB, 1, 2 },
91 { "float_multiply", IR_MUL, 1, 2 },
92 { "float_divide", IR_DIV, 1, 2 },
93 { "float_power", IR_POW, 1, 2 },
94 /* texture / sampler */
95 { "vec4_tex2d", IR_TEX, 1, 1 },
96 { "vec4_texb2d", IR_TEXB, 1, 3 },
97 /* unary op */
98 { "int_to_float", IR_I_TO_F, 1, 1 },
99 { "float_exp", IR_EXP, 1, 1 },
100 { "float_exp2", IR_EXP2, 1, 1 },
101 { "float_log2", IR_LOG2, 1, 1 },
102 { "float_rsq", IR_RSQ, 1, 1 },
103 { "float_rcp", IR_RCP, 1, 1 },
104 { "float_sine", IR_SIN, 1, 1 },
105 { "float_cosine", IR_COS, 1, 1 },
106 { NULL, IR_NOP, 0, 0 }
107 };
108
109
110
111 static slang_ir_node *
112 new_node(slang_ir_opcode op, slang_ir_node *left, slang_ir_node *right)
113 {
114 slang_ir_node *n = (slang_ir_node *) calloc(1, sizeof(slang_ir_node));
115 if (n) {
116 n->Opcode = op;
117 n->Children[0] = left;
118 n->Children[1] = right;
119 n->Swizzle = SWIZZLE_NOOP;
120 n->Writemask = WRITEMASK_XYZW;
121 }
122 return n;
123 }
124
125 static slang_ir_node *
126 new_seq(slang_ir_node *left, slang_ir_node *right)
127 {
128 /* XXX if either left or right is null, just return pointer to other?? */
129 assert(left);
130 assert(right);
131 return new_node(IR_SEQ, left, right);
132 }
133
134 static slang_ir_node *
135 new_label(slang_atom labName)
136 {
137 slang_ir_node *n = new_node(IR_LABEL, NULL, NULL);
138 n->Target = (char *) labName; /*_mesa_strdup(name);*/
139 return n;
140 }
141
142 static slang_ir_node *
143 new_float_literal(float x, float y, float z, float w)
144 {
145 slang_ir_node *n = new_node(IR_FLOAT, NULL, NULL);
146 n->Value[0] = x;
147 n->Value[1] = y;
148 n->Value[2] = z;
149 n->Value[3] = w;
150 return n;
151 }
152
153 /**
154 * XXX maybe pass an IR node as second param to indicate the jump target???
155 */
156 static slang_ir_node *
157 new_cjump(slang_atom target)
158 {
159 slang_ir_node *n = new_node(IR_CJUMP, NULL, NULL);
160 if (n)
161 n->Target = (char *) target;
162 return n;
163 }
164
165 /**
166 * XXX maybe pass an IR node as second param to indicate the jump target???
167 */
168 static slang_ir_node *
169 new_jump(slang_atom target)
170 {
171 slang_ir_node *n = new_node(IR_JUMP, NULL, NULL);
172 if (n)
173 n->Target = (char *) target;
174 return n;
175 }
176
177
178 /**
179 * New IR_VAR node - a reference to a previously declared variable.
180 */
181 static slang_ir_node *
182 new_var(slang_assemble_ctx *A, slang_operation *oper,
183 slang_atom name, GLuint swizzle)
184 {
185 slang_variable *v = _slang_locate_variable(oper->locals, name, GL_TRUE);
186 slang_ir_node *n = new_node(IR_VAR, NULL, NULL);
187 if (!v) {
188 printf("VAR NOT FOUND %s\n", (char *) name);
189 assert(v);
190 }
191 /**
192 assert(v->declared);
193 **/
194 assert(!oper->var || oper->var == v);
195 v->used = GL_TRUE;
196 oper->var = v;
197 n->Swizzle = swizzle;
198 n->Var = v;
199 slang_resolve_storage(A->codegen/**NULL**/, n, A->program);
200 return n;
201 }
202
203
204 static GLboolean
205 slang_is_writemask(const char *field, GLuint *mask)
206 {
207 const GLuint n = 4;
208 GLuint i, bit, c = 0;
209
210 for (i = 0; i < n && field[i]; i++) {
211 switch (field[i]) {
212 case 'x':
213 case 'r':
214 bit = WRITEMASK_X;
215 break;
216 case 'y':
217 case 'g':
218 bit = WRITEMASK_Y;
219 break;
220 case 'z':
221 case 'b':
222 bit = WRITEMASK_Z;
223 break;
224 case 'w':
225 case 'a':
226 bit = WRITEMASK_W;
227 break;
228 default:
229 return GL_FALSE;
230 }
231 if (c & bit)
232 return GL_FALSE;
233 c |= bit;
234 }
235 *mask = c;
236 return GL_TRUE;
237 }
238
239
240 /**
241 * Check if the given function is really just a wrapper for an
242 * basic assembly instruction.
243 */
244 static GLboolean
245 slang_is_asm_function(const slang_function *fun)
246 {
247 if (fun->body->type == slang_oper_block_no_new_scope &&
248 fun->body->num_children == 1 &&
249 fun->body->children[0].type == slang_oper_asm) {
250 return GL_TRUE;
251 }
252 return GL_FALSE;
253 }
254
255
256 /**
257 * Produce inline code for a call to an assembly instruction.
258 */
259 static slang_operation *
260 slang_inline_asm_function(slang_assemble_ctx *A,
261 slang_function *fun, slang_operation *oper)
262 {
263 const int numArgs = oper->num_children;
264 const slang_operation *args = oper->children;
265 GLuint i;
266 slang_operation *inlined = slang_operation_new(1);
267
268 /*assert(oper->type == slang_oper_call); or vec4_add, etc */
269
270 inlined->type = fun->body->children[0].type;
271 inlined->a_id = fun->body->children[0].a_id;
272 inlined->num_children = numArgs;
273 inlined->children = slang_operation_new(numArgs);
274 #if 0
275 inlined->locals = slang_variable_scope_copy(oper->locals);
276 #else
277 assert(inlined->locals);
278 inlined->locals->outer_scope = oper->locals->outer_scope;
279 #endif
280
281 for (i = 0; i < numArgs; i++) {
282 slang_operation_copy(inlined->children + i, args + i);
283 }
284
285 return inlined;
286 }
287
288
289 static void
290 slang_resolve_variable(slang_operation *oper)
291 {
292 if (oper->type != slang_oper_identifier)
293 return;
294 if (!oper->var) {
295 oper->var = _slang_locate_variable(oper->locals,
296 (const slang_atom) oper->a_id,
297 GL_TRUE);
298 if (oper->var)
299 oper->var->used = GL_TRUE;
300 }
301 }
302
303
304 /**
305 * Replace particular variables (slang_oper_identifier) with new expressions.
306 */
307 static void
308 slang_substitute(slang_assemble_ctx *A, slang_operation *oper,
309 GLuint substCount, slang_variable **substOld,
310 slang_operation **substNew, GLboolean isLHS)
311 {
312 switch (oper->type) {
313 case slang_oper_variable_decl:
314 {
315 slang_variable *v = _slang_locate_variable(oper->locals,
316 oper->a_id, GL_TRUE);
317 assert(v);
318 if (v->initializer && oper->num_children == 0) {
319 /* set child of oper to copy of initializer */
320 oper->num_children = 1;
321 oper->children = slang_operation_new(1);
322 slang_operation_copy(&oper->children[0], v->initializer);
323 }
324 if (oper->num_children == 1) {
325 /* the initializer */
326 slang_substitute(A, &oper->children[0], substCount, substOld, substNew, GL_FALSE);
327 }
328 }
329 break;
330 case slang_oper_identifier:
331 assert(oper->num_children == 0);
332 if (1/**!isLHS XXX FIX */) {
333 slang_atom id = oper->a_id;
334 slang_variable *v;
335 GLuint i;
336 v = _slang_locate_variable(oper->locals, id, GL_TRUE);
337 if (!v) {
338 printf("var %s not found!\n", (char *) oper->a_id);
339 break;
340 }
341
342 /* look for a substitution */
343 for (i = 0; i < substCount; i++) {
344 if (v == substOld[i]) {
345 /* OK, replace this slang_oper_identifier with a new expr */
346 assert(substNew[i]->type == slang_oper_identifier ||
347 substNew[i]->type == slang_oper_literal_float);
348 #if 0 /* DEBUG only */
349 if (substNew[i]->type == slang_oper_identifier) {
350 assert(substNew[i]->var);
351 assert(substNew[i]->var->a_name);
352 printf("Substitute %s with %s in id node %p\n",
353 (char*)v->a_name, (char*) substNew[i]->var->a_name,
354 (void*) oper);
355 }
356 else
357 printf("Substitute %s with %f in id node %p\n",
358 (char*)v->a_name, substNew[i]->literal[0],
359 (void*) oper);
360 #endif
361 slang_operation_copy(oper, substNew[i]);
362 break;
363 }
364 }
365 }
366 break;
367 #if 0 /* XXX rely on default case below */
368 case slang_oper_return:
369 /* do return replacement here too */
370 assert(oper->num_children == 0 || oper->num_children == 1);
371 if (oper->num_children == 1) {
372 slang_substitute(A, &oper->children[0],
373 substCount, substOld, substNew, GL_FALSE);
374 }
375 break;
376 #endif
377 case slang_oper_assign:
378 case slang_oper_subscript:
379 /* special case:
380 * child[0] can't have substitutions but child[1] can.
381 */
382 slang_substitute(A, &oper->children[0],
383 substCount, substOld, substNew, GL_TRUE);
384 slang_substitute(A, &oper->children[1],
385 substCount, substOld, substNew, GL_FALSE);
386 break;
387 case slang_oper_field:
388 /* XXX NEW - test */
389 slang_substitute(A, &oper->children[0],
390 substCount, substOld, substNew, GL_TRUE);
391 break;
392 default:
393 {
394 GLuint i;
395 for (i = 0; i < oper->num_children; i++)
396 slang_substitute(A, &oper->children[i],
397 substCount, substOld, substNew, GL_FALSE);
398 }
399 }
400 }
401
402
403
404 /**
405 * Inline the given function call operation.
406 * Return a new slang_operation that corresponds to the inlined code.
407 */
408 static slang_operation *
409 slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun,
410 slang_operation *oper, slang_operation *returnOper)
411 {
412 typedef enum {
413 SUBST = 1,
414 COPY_IN,
415 COPY_OUT
416 } ParamMode;
417 ParamMode *paramMode;
418 const GLboolean haveRetValue = _slang_function_has_return_value(fun);
419 const GLuint numArgs = oper->num_children;
420 const GLuint totalArgs = numArgs + haveRetValue;
421 slang_operation *args = oper->children;
422 slang_operation *inlined, *top;
423 slang_variable **substOld;
424 slang_operation **substNew;
425 GLuint substCount, numCopyIn, i;
426
427 /*assert(oper->type == slang_oper_call); (or (matrix) multiply, etc) */
428 assert(fun->param_count == totalArgs);
429
430 /* allocate temporary arrays */
431 paramMode = (ParamMode *)
432 _mesa_calloc(totalArgs * sizeof(ParamMode));
433 substOld = (slang_variable **)
434 _mesa_calloc(totalArgs * sizeof(slang_variable *));
435 substNew = (slang_operation **)
436 _mesa_calloc(totalArgs * sizeof(slang_operation *));
437
438 printf("\nInline call to %s (total vars=%d nparams=%d)\n",
439 (char *) fun->header.a_name,
440 fun->parameters->num_variables, numArgs);
441
442
443 if (haveRetValue && !returnOper) {
444 /* Create comma sequence for inlined code, the left child will be the
445 * function body and the right child will be a variable (__retVal)
446 * that will get the return value.
447 */
448 slang_operation *commaSeq;
449 slang_operation *declOper = NULL;
450 slang_variable *resultVar;
451
452 commaSeq = slang_operation_new(1);
453 commaSeq->type = slang_oper_sequence;
454 assert(commaSeq->locals);
455 commaSeq->locals->outer_scope = oper->locals->outer_scope;
456 commaSeq->num_children = 3;
457 commaSeq->children = slang_operation_new(3);
458 /* allocate the return var */
459 resultVar = slang_variable_scope_grow(commaSeq->locals);
460 /*
461 printf("ALLOC __retVal from scope %p\n", (void*) commaSeq->locals);
462 */
463 printf("Alloc __resultTemp in scope %p for retval of calling %s\n",
464 (void*)commaSeq->locals, (char *) fun->header.a_name);
465
466 resultVar->a_name = slang_atom_pool_atom(A->atoms, "__resultTmp");
467 resultVar->type = fun->header.type; /* XXX copy? */
468 /*resultVar->type.qualifier = slang_qual_out;*/
469
470 /* child[0] = __resultTmp declaration */
471 declOper = &commaSeq->children[0];
472 declOper->type = slang_oper_variable_decl;
473 declOper->a_id = resultVar->a_name;
474 declOper->locals->outer_scope = commaSeq->locals; /*** ??? **/
475
476 /* child[1] = function body */
477 inlined = &commaSeq->children[1];
478 /* XXXX this may be inappropriate!!!!: */
479 inlined->locals->outer_scope = commaSeq->locals;
480
481 /* child[2] = __resultTmp reference */
482 returnOper = &commaSeq->children[2];
483 returnOper->type = slang_oper_identifier;
484 returnOper->a_id = resultVar->a_name;
485 returnOper->locals->outer_scope = commaSeq->locals;
486 declOper->locals->outer_scope = commaSeq->locals;
487
488 top = commaSeq;
489 }
490 else {
491 top = inlined = slang_operation_new(1);
492 /* XXXX this may be inappropriate!!!! */
493 inlined->locals->outer_scope = oper->locals->outer_scope;
494 }
495
496
497 assert(inlined->locals);
498
499 /* Examine the parameters, look for inout/out params, look for possible
500 * substitutions, etc:
501 * param type behaviour
502 * in copy actual to local
503 * const in substitute param with actual
504 * out copy out
505 */
506 substCount = 0;
507 for (i = 0; i < totalArgs; i++) {
508 slang_variable *p = &fun->parameters->variables[i];
509 printf("Param %d: %s %s \n", i,
510 slang_type_qual_string(p->type.qualifier),
511 (char *) p->a_name);
512 if (p->type.qualifier == slang_qual_inout ||
513 p->type.qualifier == slang_qual_out) {
514 /* an output param */
515 slang_operation *arg;
516 if (i < numArgs)
517 arg = &args[i];
518 else
519 arg = returnOper;
520 paramMode[i] = SUBST;
521 assert(arg->type == slang_oper_identifier
522 /*||arg->type == slang_oper_variable_decl*/);
523 slang_resolve_variable(arg);
524 /* replace parameter 'p' with argument 'arg' */
525 substOld[substCount] = p;
526 substNew[substCount] = arg; /* will get copied */
527 substCount++;
528 }
529 else if (p->type.qualifier == slang_qual_const) {
530 /* a constant input param */
531 if (args[i].type == slang_oper_identifier ||
532 args[i].type == slang_oper_literal_float) {
533 /* replace all occurances of this parameter variable with the
534 * actual argument variable or a literal.
535 */
536 paramMode[i] = SUBST;
537 slang_resolve_variable(&args[i]);
538 substOld[substCount] = p;
539 substNew[substCount] = &args[i]; /* will get copied */
540 substCount++;
541 }
542 else {
543 paramMode[i] = COPY_IN;
544 }
545 }
546 else {
547 paramMode[i] = COPY_IN;
548 }
549 assert(paramMode[i]);
550 }
551
552 #if 00
553 printf("ABOUT to inline body %p with checksum %d\n",
554 (char *) fun->body, slang_checksum_tree(fun->body));
555 #endif
556
557 /* actual code inlining: */
558 slang_operation_copy(inlined, fun->body);
559
560 #if 000
561 printf("======================= orig body code ======================\n");
562 printf("=== params scope = %p\n", (void*) fun->parameters);
563 slang_print_tree(fun->body, 8);
564 printf("======================= copied code =========================\n");
565 slang_print_tree(inlined, 8);
566 #endif
567
568 /* do parameter substitution in inlined code: */
569 slang_substitute(A, inlined, substCount, substOld, substNew, GL_FALSE);
570
571 #if 000
572 printf("======================= subst code ==========================\n");
573 slang_print_tree(inlined, 8);
574 printf("=============================================================\n");
575 #endif
576
577 /* New prolog statements: (inserted before the inlined code)
578 * Copy the 'in' arguments.
579 */
580 numCopyIn = 0;
581 for (i = 0; i < numArgs; i++) {
582 if (paramMode[i] == COPY_IN) {
583 slang_variable *p = &fun->parameters->variables[i];
584 /* declare parameter 'p' */
585 slang_operation *decl = slang_operation_insert(&inlined->num_children,
586 &inlined->children,
587 numCopyIn);
588 printf("COPY_IN %s from expr\n", (char*)p->a_name);
589 decl->type = slang_oper_variable_decl;
590 assert(decl->locals);
591 decl->locals = fun->parameters;
592 decl->a_id = p->a_name;
593 decl->num_children = 1;
594 decl->children = slang_operation_new(1);
595
596 /* child[0] is the var's initializer */
597 slang_operation_copy(&decl->children[0], args + i);
598
599 numCopyIn++;
600 }
601 }
602
603 /* New epilog statements:
604 * 1. Create end of function label to jump to from return statements.
605 * 2. Copy the 'out' parameter vars
606 */
607 {
608 slang_operation *lab = slang_operation_insert(&inlined->num_children,
609 &inlined->children,
610 inlined->num_children);
611 lab->type = slang_oper_label;
612 lab->a_id = slang_atom_pool_atom(A->atoms, CurFunction->end_label);
613 }
614
615 for (i = 0; i < totalArgs; i++) {
616 if (paramMode[i] == COPY_OUT) {
617 const slang_variable *p = &fun->parameters->variables[i];
618 /* actualCallVar = outParam */
619 /*if (i > 0 || !haveRetValue)*/
620 slang_operation *ass = slang_operation_insert(&inlined->num_children,
621 &inlined->children,
622 inlined->num_children);
623 ass->type = slang_oper_assign;
624 ass->num_children = 2;
625 ass->locals = _slang_variable_scope_new(inlined->locals);
626 assert(ass->locals);
627 ass->children = slang_operation_new(2);
628 ass->children[0] = args[i]; /*XXX copy */
629 ass->children[1].type = slang_oper_identifier;
630 ass->children[1].a_id = p->a_name;
631 ass->children[1].locals = _slang_variable_scope_new(ass->locals);
632 }
633 }
634
635 _mesa_free(paramMode);
636 _mesa_free(substOld);
637 _mesa_free(substNew);
638
639 printf("Done Inline call to %s (total vars=%d nparams=%d)\n",
640 (char *) fun->header.a_name,
641 fun->parameters->num_variables, numArgs);
642
643 return top;
644 }
645
646
647 static slang_ir_node *
648 _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun,
649 slang_operation *oper, slang_operation *dest)
650 {
651 slang_ir_node *n;
652 slang_operation *inlined;
653 slang_function *prevFunc;
654
655 prevFunc = CurFunction;
656 CurFunction = fun;
657
658 if (!CurFunction->end_label) {
659 char name[200];
660 sprintf(name, "__endOfFunc_%s_", (char *) CurFunction->header.a_name);
661 CurFunction->end_label = slang_atom_pool_gen(A->atoms, name);
662 }
663
664 if (slang_is_asm_function(fun) && !dest) {
665 /* assemble assembly function - tree style */
666 inlined = slang_inline_asm_function(A, fun, oper);
667 }
668 else {
669 /* non-assembly function */
670 inlined = slang_inline_function_call(A, fun, oper, dest);
671 }
672
673 /* Replace the function call with the inlined block */
674 #if 0
675 slang_operation_construct(oper);
676 slang_operation_copy(oper, inlined);
677 #else
678 *oper = *inlined;
679 #endif
680
681
682 #if 0
683 assert(inlined->locals);
684 printf("*** Inlined code for call to %s:\n",
685 (char*) fun->header.a_name);
686
687 slang_print_tree(oper, 10);
688 printf("\n");
689 #endif
690
691 /* assemble what we just made XXX here??? */
692 n = _slang_gen_operation(A, oper);
693
694 CurFunction = prevFunc;
695
696 return n;
697 }
698
699
700 static slang_asm_info *
701 slang_find_asm_info(const char *name)
702 {
703 GLuint i;
704 for (i = 0; AsmInfo[i].Name; i++) {
705 if (_mesa_strcmp(AsmInfo[i].Name, name) == 0) {
706 return AsmInfo + i;
707 }
708 }
709 return NULL;
710 }
711
712
713 static GLuint
714 make_writemask(char *field)
715 {
716 GLuint mask = 0x0;
717 while (*field) {
718 switch (*field) {
719 case 'x':
720 mask |= WRITEMASK_X;
721 break;
722 case 'y':
723 mask |= WRITEMASK_Y;
724 break;
725 case 'z':
726 mask |= WRITEMASK_Z;
727 break;
728 case 'w':
729 mask |= WRITEMASK_W;
730 break;
731 default:
732 abort();
733 }
734 field++;
735 }
736 if (mask == 0x0)
737 return WRITEMASK_XYZW;
738 else
739 return mask;
740 }
741
742
743 /**
744 * Generate IR tree for an asm instruction/operation such as:
745 * __asm vec4_dot __retVal.x, v1, v2;
746 */
747 static slang_ir_node *
748 _slang_gen_asm(slang_assemble_ctx *A, slang_operation *oper,
749 slang_operation *dest)
750 {
751 const slang_asm_info *info;
752 slang_ir_node *kids[2], *n;
753 GLuint j, firstOperand;
754
755 assert(oper->type == slang_oper_asm);
756
757 info = slang_find_asm_info((char *) oper->a_id);
758 assert(info);
759 assert(info->NumParams <= 2);
760
761 if (info->NumParams == oper->num_children) {
762 /* storage for result not specified */
763 firstOperand = 0;
764 }
765 else {
766 /* storage for result (child[0]) is specified */
767 firstOperand = 1;
768 }
769
770 /* assemble child(ren) */
771 kids[0] = kids[1] = NULL;
772 for (j = 0; j < info->NumParams; j++) {
773 kids[j] = _slang_gen_operation(A, &oper->children[firstOperand + j]);
774 }
775
776 n = new_node(info->Opcode, kids[0], kids[1]);
777
778 if (firstOperand) {
779 /* Setup n->Store to be a particular location. Otherwise, storage
780 * for the result (a temporary) will be allocated later.
781 */
782 GLuint writemask = WRITEMASK_XYZW;
783 slang_operation *dest_oper;
784 slang_ir_node *n0;
785
786 dest_oper = &oper->children[0];
787 if (dest_oper->type == slang_oper_field) {
788 /* writemask */
789 writemask = make_writemask((char*) dest_oper->a_id);
790 dest_oper = &dest_oper->children[0];
791 }
792
793 assert(dest_oper->type == slang_oper_identifier);
794 n0 = _slang_gen_operation(A, dest_oper);
795 assert(n0->Var);
796 assert(n0->Store);
797
798 n->Store = n0->Store;
799 n->Writemask = writemask;
800
801 free(n0);
802 }
803
804 if (info->Opcode == IR_TEX || info->Opcode == IR_TEXB) {
805 n->TexTarget = TEXTURE_2D_INDEX;
806 }
807
808 return n;
809 }
810
811
812
813 static GLboolean
814 _slang_is_noop(const slang_operation *oper)
815 {
816 if (!oper ||
817 oper->type == slang_oper_void ||
818 (oper->num_children == 1 && oper->children[0].type == slang_oper_void))
819 return GL_TRUE;
820 else
821 return GL_FALSE;
822 }
823
824
825 static slang_ir_node *
826 _slang_gen_cond(slang_ir_node *n)
827 {
828 slang_ir_node *c = new_node(IR_COND, n, NULL);
829 return c;
830 }
831
832
833 /**
834 * Assemble a function call, given a particular function name.
835 * \param name the function's name (operators like '*' are possible).
836 */
837 static slang_ir_node *
838 _slang_gen_function_call_name(slang_assemble_ctx *A, const char *name,
839 slang_operation *oper, slang_operation *dest)
840 {
841 slang_operation *params = oper->children;
842 const GLuint param_count = oper->num_children;
843 slang_atom atom;
844 slang_function *fun;
845
846 atom = slang_atom_pool_atom(A->atoms, name);
847 if (atom == SLANG_ATOM_NULL)
848 return NULL;
849
850 fun = _slang_locate_function(A->space.funcs, atom, params, param_count,
851 &A->space, A->atoms);
852 if (!fun) {
853 RETURN_ERROR2("Undefined function", name, 0);
854 }
855
856 return _slang_gen_function_call(A, fun, oper, dest);
857 }
858
859
860 /**
861 * Generate IR tree for a while-loop.
862 */
863 static slang_ir_node *
864 _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
865 {
866 /*
867 * label "__startWhile"
868 * eval expr (child[0]), updating condcodes
869 * branch if false to "__endWhile"
870 * code body
871 * jump "__startWhile"
872 * label "__endWhile"
873 */
874 slang_atom startAtom = slang_atom_pool_gen(A->atoms, "__startWhile");
875 slang_atom endAtom = slang_atom_pool_gen(A->atoms, "__endWhile");
876 slang_ir_node *startLab, *cond, *bra, *body, *jump, *endLab, *tree;
877 slang_atom prevLoopBreak = CurLoopBreak;
878 slang_atom prevLoopCont = CurLoopCont;
879
880 /* Push this loop */
881 CurLoopBreak = endAtom;
882 CurLoopCont = startAtom;
883
884 startLab = new_label(startAtom);
885 cond = _slang_gen_operation(A, &oper->children[0]);
886 cond = _slang_gen_cond(cond);
887 tree = new_seq(startLab, cond);
888
889 bra = new_cjump(endAtom);
890 tree = new_seq(tree, bra);
891
892 body = _slang_gen_operation(A, &oper->children[1]);
893 tree = new_seq(tree, body);
894
895 jump = new_jump(startAtom);
896 tree = new_seq(tree, jump);
897
898 endLab = new_label(endAtom);
899 tree = new_seq(tree, endLab);
900
901 /* Pop this loop */
902 CurLoopBreak = prevLoopBreak;
903 CurLoopCont = prevLoopCont;
904
905 return tree;
906 }
907
908
909 /**
910 * Generate IR tree for a for-loop.
911 */
912 static slang_ir_node *
913 _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
914 {
915 /*
916 * init code (child[0])
917 * label "__startFor"
918 * eval expr (child[1]), updating condcodes
919 * branch if false to "__endFor"
920 * code body (child[3])
921 * label "__continueFor"
922 * incr code (child[2])
923 * jump "__startFor"
924 * label "__endFor"
925 */
926 slang_atom startAtom = slang_atom_pool_gen(A->atoms, "__startFor");
927 slang_atom contAtom = slang_atom_pool_gen(A->atoms, "__continueFor");
928 slang_atom endAtom = slang_atom_pool_gen(A->atoms, "__endFor");
929 slang_ir_node *init, *startLab, *cond, *bra, *body, *contLab;
930 slang_ir_node *incr, *jump, *endLab, *tree;
931 slang_atom prevLoopBreak = CurLoopBreak;
932 slang_atom prevLoopCont = CurLoopCont;
933
934 /* Push this loop */
935 CurLoopBreak = endAtom;
936 CurLoopCont = contAtom;
937
938 init = _slang_gen_operation(A, &oper->children[0]);
939 startLab = new_label(startAtom);
940 tree = new_seq(init, startLab);
941
942 cond = _slang_gen_operation(A, &oper->children[1]);
943 cond = _slang_gen_cond(cond);
944 tree = new_seq(tree, cond);
945
946 bra = new_cjump(endAtom);
947 tree = new_seq(tree, bra);
948
949 body = _slang_gen_operation(A, &oper->children[3]);
950 tree = new_seq(tree, body);
951
952 contLab = new_label(contAtom);
953 tree = new_seq(tree, contLab);
954
955 incr = _slang_gen_operation(A, &oper->children[2]);
956 tree = new_seq(tree, incr);
957
958 jump = new_jump(startAtom);
959 tree = new_seq(tree, jump);
960
961 endLab = new_label(endAtom);
962 tree = new_seq(tree, endLab);
963
964 /* Pop this loop */
965 CurLoopBreak = prevLoopBreak;
966 CurLoopCont = prevLoopCont;
967
968 return tree;
969 }
970
971
972 /**
973 * Generate IR tree for an if/then/else conditional.
974 */
975 static slang_ir_node *
976 _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper)
977 {
978 /*
979 * eval expr (child[0]), updating condcodes
980 * branch if false to _else or _endif
981 * "true" code block
982 * if haveElseClause clause:
983 * jump "__endif"
984 * label "__else"
985 * "false" code block
986 * label "__endif"
987 */
988 const GLboolean haveElseClause = !_slang_is_noop(&oper->children[2]);
989 slang_ir_node *cond, *bra, *trueBody, *endifLab, *tree;
990 slang_atom elseAtom = slang_atom_pool_gen(A->atoms, "__else");
991 slang_atom endifAtom = slang_atom_pool_gen(A->atoms, "__endif");
992
993 cond = _slang_gen_operation(A, &oper->children[0]);
994 cond = _slang_gen_cond(cond);
995 /*assert(cond->Store);*/
996 bra = new_cjump(haveElseClause ? elseAtom : endifAtom);
997 tree = new_seq(cond, bra);
998
999 trueBody = _slang_gen_operation(A, &oper->children[1]);
1000 tree = new_seq(tree, trueBody);
1001
1002 if (haveElseClause) {
1003 /* else clause */
1004 slang_ir_node *jump, *elseLab, *falseBody;
1005 jump = new_jump(endifAtom);
1006 tree = new_seq(tree, jump);
1007
1008 elseLab = new_label(elseAtom);
1009 tree = new_seq(tree, elseLab);
1010
1011 falseBody = _slang_gen_operation(A, &oper->children[2]);
1012 tree = new_seq(tree, falseBody);
1013 }
1014
1015 endifLab = new_label(endifAtom);
1016 tree = new_seq(tree, endifLab);
1017
1018 return tree;
1019 }
1020
1021
1022 /**
1023 * Generate IR tree for a return statement.
1024 */
1025 static slang_ir_node *
1026 _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper)
1027 {
1028 if (oper->num_children == 0 ||
1029 (oper->num_children == 1 &&
1030 oper->children[0].type == slang_oper_void)) {
1031 /* Convert from:
1032 * return;
1033 * To:
1034 * goto __endOfFunction;
1035 */
1036 slang_ir_node *n;
1037 slang_operation gotoOp;
1038 slang_operation_construct(&gotoOp);
1039 gotoOp.type = slang_oper_goto;
1040 gotoOp.a_id = slang_atom_pool_atom(A->atoms, CurFunction->end_label);
1041 /* assemble the new code */
1042 n = _slang_gen_operation(A, &gotoOp);
1043 /* destroy temp code */
1044 slang_operation_destruct(&gotoOp);
1045 return n;
1046 }
1047 else {
1048 /*
1049 * Convert from:
1050 * return expr;
1051 * To:
1052 * __retVal = expr;
1053 * goto __endOfFunction;
1054 */
1055 slang_operation *block, *assign, *jump;
1056 slang_atom a_retVal;
1057 slang_ir_node *n;
1058
1059 a_retVal = slang_atom_pool_atom(A->atoms, "__retVal");
1060 assert(a_retVal);
1061
1062 #if 1 /* DEBUG */
1063 {
1064 slang_variable *v
1065 = _slang_locate_variable(oper->locals, a_retVal, GL_TRUE);
1066 assert(v);
1067 }
1068 #endif
1069
1070 block = slang_operation_new(1);
1071 block->type = slang_oper_block_no_new_scope;
1072 block->num_children = 2;
1073 block->children = slang_operation_new(2);
1074 assert(block->locals);
1075 block->locals->outer_scope = oper->locals->outer_scope;
1076
1077 /* child[0]: __retVal = expr; */
1078 assign = &block->children[0];
1079 assign->type = slang_oper_assign;
1080 assign->locals->outer_scope = block->locals;
1081 assign->num_children = 2;
1082 assign->children = slang_operation_new(2);
1083 /* lhs (__retVal) */
1084 assign->children[0].type = slang_oper_identifier;
1085 assign->children[0].a_id = a_retVal;
1086 assign->children[0].locals->outer_scope = assign->locals;
1087 /* rhs (expr) */
1088 /* XXX we might be able to avoid this copy someday */
1089 slang_operation_copy(&assign->children[1], &oper->children[0]);
1090
1091 /* child[1]: goto __endOfFunction */
1092 jump = &block->children[1];
1093 jump->type = slang_oper_goto;
1094 assert(CurFunction->end_label);
1095 jump->a_id = slang_atom_pool_atom(A->atoms, CurFunction->end_label);
1096
1097 #if 0 /* debug */
1098 printf("NEW RETURN:\n");
1099 slang_print_tree(block, 0);
1100 #endif
1101
1102 /* assemble the new code */
1103 n = _slang_gen_operation(A, block);
1104 slang_operation_delete(block);
1105 return n;
1106 }
1107 }
1108
1109
1110 /**
1111 * Generate IR tree for a variable declaration.
1112 */
1113 static slang_ir_node *
1114 _slang_gen_declaration(slang_assemble_ctx *A, slang_operation *oper)
1115 {
1116 slang_ir_node *n;
1117 slang_ir_node *varDecl;
1118 slang_variable *v;
1119
1120 assert(oper->num_children == 0 || oper->num_children == 1);
1121
1122 v = _slang_locate_variable(oper->locals, oper->a_id, GL_TRUE);
1123 assert(v);
1124
1125 varDecl = new_node(IR_VAR_DECL, NULL, NULL);
1126 if (!varDecl)
1127 return NULL;
1128
1129 varDecl->Var = v;
1130 v->declared = GL_TRUE;
1131
1132 slang_resolve_storage(A->codegen, varDecl, A->program);
1133
1134 if (oper->num_children > 0) {
1135 /* child is initializer */
1136 slang_ir_node *var, *init, *rhs;
1137 assert(oper->num_children == 1);
1138 var = new_var(A, oper, oper->a_id, SWIZZLE_NOOP);
1139 /* XXX make copy of this initializer? */
1140 /*
1141 printf("\n*** ASSEMBLE INITIALIZER %p\n", (void*) v->initializer);
1142 */
1143 rhs = _slang_gen_operation(A, &oper->children[0]);
1144 init = new_node(IR_MOVE, var, rhs);
1145 /*assert(rhs->Opcode != IR_SEQ);*/
1146 n = new_seq(varDecl, init);
1147 }
1148 else if (v->initializer) {
1149 slang_ir_node *var, *init, *rhs;
1150 var = new_var(A, oper, oper->a_id, SWIZZLE_NOOP);
1151 /* XXX make copy of this initializer? */
1152 /*
1153 printf("\n*** ASSEMBLE INITIALIZER %p\n", (void*) v->initializer);
1154 */
1155 rhs = _slang_gen_operation(A, v->initializer);
1156 init = new_node(IR_MOVE, var, rhs);
1157 /*
1158 assert(rhs->Opcode != IR_SEQ);
1159 */
1160 n = new_seq(varDecl, init);
1161 }
1162 else {
1163 n = varDecl;
1164 }
1165 return n;
1166 }
1167
1168
1169 /**
1170 * Generate IR tree for a variable (such as in an expression).
1171 */
1172 static slang_ir_node *
1173 _slang_gen_variable(slang_assemble_ctx * A, slang_operation *oper)
1174 {
1175 /* If there's a variable associated with this oper (from inlining)
1176 * use it. Otherwise, use the oper's var id.
1177 */
1178 slang_atom aVar = oper->var ? oper->var->a_name : oper->a_id;
1179 slang_ir_node *n = new_var(A, oper, aVar, SWIZZLE_NOOP);
1180 assert(oper->var);
1181 return n;
1182 }
1183
1184
1185 /**
1186 * Generate IR tree for an assignment (=).
1187 */
1188 static slang_ir_node *
1189 _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper)
1190 {
1191 if (oper->children[0].type == slang_oper_identifier &&
1192 oper->children[1].type == slang_oper_call) {
1193 /* Sspecial case of: x = f(a, b)
1194 * Replace with f(a, b, x) (where x == hidden __retVal out param)
1195 */
1196 slang_ir_node *n;
1197 n = _slang_gen_function_call_name(A,
1198 (const char *) oper->children[1].a_id,
1199 &oper->children[1], &oper->children[0]);
1200 return n;
1201 }
1202 else {
1203 slang_operation *lhs = &oper->children[0];
1204 slang_ir_node *n, *c0, *c1;
1205 GLuint mask = WRITEMASK_XYZW;
1206 if (lhs->type == slang_oper_field) {
1207 /* XXXX this is a hack! */
1208 /* writemask */
1209 if (!slang_is_writemask((char *) lhs->a_id, &mask))
1210 mask = WRITEMASK_XYZW;
1211 lhs = &lhs->children[0];
1212 }
1213 c0 = _slang_gen_operation(A, lhs);
1214 c1 = _slang_gen_operation(A, &oper->children[1]);
1215
1216 n = new_node(IR_MOVE, c0, c1);
1217 /*
1218 assert(c1->Opcode != IR_SEQ);
1219 */
1220 if (c0->Writemask != WRITEMASK_XYZW)
1221 /* XXX this is a hack! */
1222 n->Writemask = c0->Writemask;
1223 else
1224 n->Writemask = mask;
1225 return n;
1226 }
1227 }
1228
1229
1230 /**
1231 * Generate IR tree for referencing a field in a struct (or basic vector type)
1232 */
1233 static slang_ir_node *
1234 _slang_gen_field(slang_assemble_ctx * A, slang_operation *oper)
1235 {
1236 slang_assembly_typeinfo ti;
1237
1238 slang_assembly_typeinfo_construct(&ti);
1239 _slang_typeof_operation(A, &oper->children[0], &ti);
1240
1241 if (_slang_type_is_vector(ti.spec.type)) {
1242 /* the field should be a swizzle */
1243 const GLuint rows = _slang_type_dim(ti.spec.type);
1244 slang_swizzle swz;
1245 slang_ir_node *n;
1246 if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) {
1247 RETURN_ERROR("Bad swizzle", 0);
1248 }
1249 n = _slang_gen_operation(A, &oper->children[0]);
1250 n->Swizzle = MAKE_SWIZZLE4(swz.swizzle[0],
1251 swz.swizzle[1],
1252 swz.swizzle[2],
1253 swz.swizzle[3]);
1254 return n;
1255 }
1256 else if (ti.spec.type == slang_spec_float) {
1257 const GLuint rows = 1;
1258 slang_swizzle swz;
1259 slang_ir_node *n;
1260 if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) {
1261 RETURN_ERROR("Bad swizzle", 0);
1262 }
1263 n = _slang_gen_operation(A, &oper->children[0]);
1264 n->Swizzle = MAKE_SWIZZLE4(swz.swizzle[0],
1265 swz.swizzle[1],
1266 swz.swizzle[2],
1267 swz.swizzle[3]);
1268 return n;
1269 }
1270 else {
1271 /* the field is a structure member */
1272 abort();
1273 }
1274 }
1275
1276
1277 /**
1278 * Generate IR tree for an array element reference.
1279 */
1280 static slang_ir_node *
1281 _slang_gen_subscript(slang_assemble_ctx * A, slang_operation *oper)
1282 {
1283 if (oper->children[1].type == slang_oper_literal_int) {
1284 /* compile-time constant index - OK */
1285 slang_assembly_typeinfo array_ti, elem_ti;
1286 slang_ir_node *base;
1287 GLint index;
1288
1289 /* get type of array element */
1290 slang_assembly_typeinfo_construct(&elem_ti);
1291 _slang_typeof_operation(A, oper, &elem_ti);
1292
1293 /* get type of array */
1294 slang_assembly_typeinfo_construct(&array_ti);
1295 _slang_typeof_operation(A, &oper->children[0], &array_ti);
1296
1297
1298 base = _slang_gen_operation(A, &oper->children[0]);
1299 assert(base->Opcode == IR_VAR);
1300 assert(base->Store);
1301
1302 index = (GLint) oper->children[1].literal[0];
1303 /*printf("element[%d]\n", index);*/
1304 /* new storage info since we don't want to change the original */
1305 base->Store = _slang_clone_ir_storage(base->Store);
1306 if (_slang_type_is_vector(array_ti.spec.type)) {
1307 /* scalar element (float) of a basic vector (vec3) */
1308 const GLuint max = _slang_type_dim(array_ti.spec.type);
1309 if (index >= max) {
1310 RETURN_ERROR("array index out of bounds", 0);
1311 }
1312 assert(index < 4);
1313 /* use swizzle to access the element */
1314 base->Swizzle = SWIZZLE_X + index;
1315 base->Writemask = WRITEMASK_X << index;
1316 }
1317 else {
1318 /* bias Index by array subscript, update storage size */
1319 base->Store->Index += index;
1320 base->Store->Size = _slang_sizeof_type_specifier(&elem_ti.spec);
1321 }
1322 return base;
1323 }
1324 else {
1325 /* run-time index - not supported yet - TBD */
1326 abort();
1327 return NULL;
1328 }
1329 }
1330
1331
1332 /**
1333 * Generate IR tree for a slang_operation (AST node)
1334 */
1335 static slang_ir_node *
1336 _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
1337 {
1338 switch (oper->type) {
1339 case slang_oper_block_no_new_scope:
1340 case slang_oper_block_new_scope:
1341 /* list of operations */
1342 assert(oper->num_children > 0);
1343 {
1344 slang_ir_node *n, *tree = NULL;
1345 GLuint i;
1346 for (i = 0; i < oper->num_children; i++) {
1347 n = _slang_gen_operation(A, &oper->children[i]);
1348 if (!n)
1349 return NULL; /* error must have occured */
1350 tree = tree ? new_seq(tree, n) : n;
1351 }
1352 return tree;
1353 }
1354 break;
1355 case slang_oper_expression:
1356 return _slang_gen_operation(A, &oper->children[0]);
1357 break;
1358 case slang_oper_while:
1359 return _slang_gen_while(A, oper);
1360 case slang_oper_for:
1361 return _slang_gen_for(A, oper);
1362 case slang_oper_break:
1363 if (!CurLoopBreak) {
1364 RETURN_ERROR("'break' not in loop", 0);
1365 }
1366 return new_jump(CurLoopBreak);
1367 case slang_oper_continue:
1368 if (!CurLoopCont) {
1369 RETURN_ERROR("'continue' not in loop", 0);
1370 }
1371 return new_jump(CurLoopCont);
1372 case slang_oper_equal:
1373 return new_node(IR_SEQUAL,
1374 _slang_gen_operation(A, &oper->children[0]),
1375 _slang_gen_operation(A, &oper->children[1]));
1376 case slang_oper_notequal:
1377 return new_node(IR_SNEQUAL,
1378 _slang_gen_operation(A, &oper->children[0]),
1379 _slang_gen_operation(A, &oper->children[1]));
1380 case slang_oper_greater:
1381 return new_node(IR_SGT,
1382 _slang_gen_operation(A, &oper->children[0]),
1383 _slang_gen_operation(A, &oper->children[1]));
1384 case slang_oper_less:
1385 /* child[0] < child[1] ----> child[1] > child[0] */
1386 #if 0
1387 {
1388 slang_ir_node *n;
1389 assert(oper->num_children == 2);
1390 /* XXX tranpose children */
1391 n = _slang_gen_function_call_name(A, "<", oper, NULL);
1392 return n;
1393 }
1394 #else
1395 /** the operands must be ints or floats, not vectors */
1396 return new_node(IR_SGT,
1397 _slang_gen_operation(A, &oper->children[1]),
1398 _slang_gen_operation(A, &oper->children[0]));
1399 #endif
1400 case slang_oper_greaterequal:
1401 return new_node(IR_SGE,
1402 _slang_gen_operation(A, &oper->children[0]),
1403 _slang_gen_operation(A, &oper->children[1]));
1404 case slang_oper_lessequal:
1405 /* child[0] <= child[1] ----> child[1] >= child[0] */
1406 return new_node(IR_SGE,
1407 _slang_gen_operation(A, &oper->children[1]),
1408 _slang_gen_operation(A, &oper->children[0]));
1409 case slang_oper_add:
1410 {
1411 slang_ir_node *n;
1412 assert(oper->num_children == 2);
1413 n = _slang_gen_function_call_name(A, "+", oper, NULL);
1414 return n;
1415 }
1416 case slang_oper_subtract:
1417 {
1418 slang_ir_node *n;
1419 assert(oper->num_children == 2);
1420 n = _slang_gen_function_call_name(A, "-", oper, NULL);
1421 return n;
1422 }
1423 case slang_oper_multiply:
1424 {
1425 slang_ir_node *n;
1426 assert(oper->num_children == 2);
1427 n = _slang_gen_function_call_name(A, "*", oper, NULL);
1428 return n;
1429 }
1430 case slang_oper_divide:
1431 {
1432 slang_ir_node *n;
1433 assert(oper->num_children == 2);
1434 n = _slang_gen_function_call_name(A, "/", oper, NULL);
1435 return n;
1436 }
1437 case slang_oper_minus:
1438 {
1439 slang_ir_node *n;
1440 assert(oper->num_children == 1);
1441 n = _slang_gen_function_call_name(A, "-", oper, NULL);
1442 return n;
1443 }
1444 case slang_oper_plus:
1445 /* +expr --> do nothing */
1446 return _slang_gen_operation(A, &oper->children[0]);
1447 case slang_oper_variable_decl:
1448 return _slang_gen_declaration(A, oper);
1449 case slang_oper_assign:
1450 return _slang_gen_assignment(A, oper);
1451 case slang_oper_addassign:
1452 {
1453 slang_ir_node *n;
1454 assert(oper->num_children == 2);
1455 n = _slang_gen_function_call_name(A, "+=", oper, NULL);
1456 /* The result of this operation should be stored back into child[0] */
1457 assert(n->Children[0]->Store);
1458 n->Store = n->Children[0]->Store;
1459 return n;
1460 }
1461 case slang_oper_subassign:
1462 {
1463 slang_ir_node *n;
1464 assert(oper->num_children == 2);
1465 n = _slang_gen_function_call_name(A, "-=", oper, NULL);
1466 /* The result of this operation should be stored back into child[0] */
1467 assert(n->Children[0]->Store);
1468 n->Store = n->Children[0]->Store;
1469 return n;
1470 }
1471 break;
1472 case slang_oper_mulassign:
1473 {
1474 slang_ir_node *n;
1475 assert(oper->num_children == 2);
1476 n = _slang_gen_function_call_name(A, "*=", oper, NULL);
1477 /* The result of this operation should be stored back into child[0] */
1478 assert(n->Children[0]->Store);
1479 n->Store = n->Children[0]->Store;
1480 return n;
1481 }
1482 case slang_oper_divassign:
1483 {
1484 slang_ir_node *n;
1485 assert(oper->num_children == 2);
1486 n = _slang_gen_function_call_name(A, "/=", oper, NULL);
1487 /* The result of this operation should be stored back into child[0] */
1488 assert(n->Children[0]->Store);
1489 n->Store = n->Children[0]->Store;
1490 return n;
1491 }
1492 case slang_oper_asm:
1493 return _slang_gen_asm(A, oper, NULL);
1494 case slang_oper_call:
1495 return _slang_gen_function_call_name(A, (const char *) oper->a_id,
1496 oper, NULL);
1497 case slang_oper_return:
1498 return _slang_gen_return(A, oper);
1499 case slang_oper_goto:
1500 return new_jump((char*) oper->a_id);
1501 case slang_oper_label:
1502 return new_label((char*) oper->a_id);
1503 case slang_oper_identifier:
1504 return _slang_gen_variable(A, oper);
1505 case slang_oper_if:
1506 return _slang_gen_if(A, oper);
1507 case slang_oper_field:
1508 return _slang_gen_field(A, oper);
1509 case slang_oper_subscript:
1510 return _slang_gen_subscript(A, oper);
1511 case slang_oper_literal_float:
1512 return new_float_literal(oper->literal[0], oper->literal[1],
1513 oper->literal[2], oper->literal[3]);
1514 case slang_oper_literal_int:
1515 return new_float_literal(oper->literal[0], 0, 0, 0);
1516 case slang_oper_literal_bool:
1517 return new_float_literal(oper->literal[0], 0, 0, 0);
1518 case slang_oper_postincrement:
1519 /* XXX not 100% about this */
1520 {
1521 slang_ir_node *var = _slang_gen_operation(A, &oper->children[0]);
1522 slang_ir_node *one = new_float_literal(1.0, 1.0, 1.0, 1.0);
1523 slang_ir_node *sum = new_node(IR_ADD, var, one);
1524 slang_ir_node *assign = new_node(IR_MOVE, var, sum);
1525 assert(sum->Opcode != IR_SEQ);
1526 return assign;
1527 }
1528 break;
1529 case slang_oper_sequence:
1530 {
1531 slang_ir_node *tree = NULL;
1532 GLuint i;
1533 for (i = 0; i < oper->num_children; i++) {
1534 slang_ir_node *n = _slang_gen_operation(A, &oper->children[i]);
1535 tree = tree ? new_seq(tree, n) : n;
1536 }
1537 return tree;
1538 }
1539 break;
1540 case slang_oper_none:
1541 return NULL;
1542 default:
1543 printf("Unhandled node type %d\n", oper->type);
1544 abort();
1545 return new_node(IR_NOP, NULL, NULL);
1546 }
1547 abort();
1548 return NULL;
1549 }
1550
1551
1552 /**
1553 * Produce an IR tree from a function AST.
1554 * Then call the code emitter to convert the IR tree into a gl_program.
1555 */
1556 struct slang_ir_node_ *
1557 _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun)
1558 {
1559 slang_ir_node *n, *endLabel;
1560
1561 if (_mesa_strcmp((char *) fun->header.a_name, "main") != 0 &&
1562 _mesa_strcmp((char *) fun->header.a_name, "foo") != 0 &&
1563 _mesa_strcmp((char *) fun->header.a_name, "bar") != 0)
1564 return 0;
1565
1566 printf("\n*********** Assemble function2(%s)\n", (char*)fun->header.a_name);
1567 #if 1
1568 slang_print_function(fun, 1);
1569 #endif
1570
1571 A->program->Parameters = _mesa_new_parameter_list();
1572 A->program->Varying = _mesa_new_parameter_list();
1573 A->codegen = _slang_new_codegen_context();
1574
1575 /*printf("** Begin Simplify\n");*/
1576 slang_simplify(fun->body, &A->space, A->atoms);
1577 /*printf("** End Simplify\n");*/
1578
1579 CurFunction = fun;
1580
1581 if (!CurFunction->end_label)
1582 CurFunction->end_label = slang_atom_pool_gen(A->atoms, "__endOfFunc_main_");
1583
1584 n = _slang_gen_operation(A, fun->body);
1585
1586 if (n) {
1587 endLabel = new_label(fun->end_label);
1588 n = new_seq(n, endLabel);
1589 }
1590
1591 CurFunction = NULL;
1592
1593
1594 #if 1
1595 printf("************* New body for %s *****\n", (char*)fun->header.a_name);
1596 slang_print_function(fun, 1);
1597
1598 printf("************* IR for %s *******\n", (char*)fun->header.a_name);
1599 slang_print_ir(n, 0);
1600 printf("************* End assemble function2 ************\n\n");
1601 #endif
1602
1603 if (_mesa_strcmp((char*) fun->header.a_name, "main") == 0) {
1604 _slang_emit_code(n, A->codegen, A->program);
1605 }
1606
1607 return n;
1608 }
1609
1610