a23d4e16d001bda0dcbff8e80da36d8b05950d81
[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_typeinfo.h"
34 #include "slang_builtin.h"
35 #include "slang_codegen.h"
36 #include "slang_compile.h"
37 #include "slang_storage.h"
38 #include "slang_error.h"
39 #include "slang_simplify.h"
40 #include "slang_emit.h"
41 #include "slang_vartable.h"
42 #include "slang_ir.h"
43 #include "mtypes.h"
44 #include "program.h"
45 #include "prog_instruction.h"
46 #include "prog_parameter.h"
47 #include "prog_statevars.h"
48 #include "slang_print.h"
49
50
51 static slang_ir_node *
52 _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper);
53
54
55
56
57 /**
58 * Lookup a named constant and allocate storage for the parameter in
59 * the given parameter list.
60 * \param swizzleOut returns swizzle mask for accessing the constant
61 * \return position of the constant in the paramList.
62 */
63 static GLint
64 slang_lookup_constant(const char *name,
65 struct gl_program_parameter_list *paramList,
66 GLuint *swizzleOut)
67 {
68 GLint value = _slang_lookup_constant(name);
69 if (value >= 0) {
70 /* XXX named constant! */
71 GLfloat fvalue = (GLfloat) value;
72 GLint pos;
73 pos = _mesa_add_unnamed_constant(paramList, &fvalue, 1, swizzleOut);
74 return pos;
75 }
76 return -1;
77 }
78
79
80 static GLboolean
81 is_sampler_type(const slang_fully_specified_type *t)
82 {
83 switch (t->specifier.type) {
84 case SLANG_SPEC_SAMPLER1D:
85 case SLANG_SPEC_SAMPLER2D:
86 case SLANG_SPEC_SAMPLER3D:
87 case SLANG_SPEC_SAMPLERCUBE:
88 case SLANG_SPEC_SAMPLER1DSHADOW:
89 case SLANG_SPEC_SAMPLER2DSHADOW:
90 return GL_TRUE;
91 default:
92 return GL_FALSE;
93 }
94 }
95
96
97 GLuint
98 _slang_sizeof_type_specifier(const slang_type_specifier *spec)
99 {
100 switch (spec->type) {
101 case SLANG_SPEC_VOID:
102 return 0;
103 case SLANG_SPEC_BOOL:
104 return 1;
105 case SLANG_SPEC_BVEC2:
106 return 2;
107 case SLANG_SPEC_BVEC3:
108 return 3;
109 case SLANG_SPEC_BVEC4:
110 return 4;
111 case SLANG_SPEC_INT:
112 return 1;
113 case SLANG_SPEC_IVEC2:
114 return 2;
115 case SLANG_SPEC_IVEC3:
116 return 3;
117 case SLANG_SPEC_IVEC4:
118 return 4;
119 case SLANG_SPEC_FLOAT:
120 return 1;
121 case SLANG_SPEC_VEC2:
122 return 2;
123 case SLANG_SPEC_VEC3:
124 return 3;
125 case SLANG_SPEC_VEC4:
126 return 4;
127 case SLANG_SPEC_MAT2:
128 return 2 * 2;
129 case SLANG_SPEC_MAT3:
130 return 3 * 3;
131 case SLANG_SPEC_MAT4:
132 return 4 * 4;
133 case SLANG_SPEC_SAMPLER1D:
134 case SLANG_SPEC_SAMPLER2D:
135 case SLANG_SPEC_SAMPLER3D:
136 case SLANG_SPEC_SAMPLERCUBE:
137 case SLANG_SPEC_SAMPLER1DSHADOW:
138 case SLANG_SPEC_SAMPLER2DSHADOW:
139 return 1; /* special case */
140 case SLANG_SPEC_STRUCT:
141 {
142 GLuint sum = 0, i;
143 for (i = 0; i < spec->_struct->fields->num_variables; i++) {
144 slang_variable *v = spec->_struct->fields->variables[i];
145 GLuint sz = _slang_sizeof_type_specifier(&v->type.specifier);
146 /* XXX verify padding */
147 if (sz < 4)
148 sz = 4;
149 sum += sz;
150 }
151 return sum;
152 }
153 case SLANG_SPEC_ARRAY:
154 return _slang_sizeof_type_specifier(spec->_array);
155 default:
156 _mesa_problem(NULL, "Unexpected type in _slang_sizeof_type_specifier()");
157 return 0;
158 }
159 return 0;
160 }
161
162
163 /**
164 * Allocate storage info for an IR node (n->Store).
165 * If n is an IR_VAR_DECL, allocate a temporary for the variable.
166 * Otherwise, if n is an IR_VAR, check if it's a uniform or constant
167 * that needs to have storage allocated.
168 */
169 static void
170 slang_allocate_storage(slang_assemble_ctx *A, slang_ir_node *n)
171 {
172 assert(A->vartable);
173 assert(n);
174
175 if (!n->Store) {
176 /* allocate storage info for this node */
177 if (n->Var && n->Var->aux) {
178 /* node storage info = var storage info */
179 n->Store = (slang_ir_storage *) n->Var->aux;
180 }
181 else {
182 /* alloc new storage info */
183 n->Store = _slang_new_ir_storage(PROGRAM_UNDEFINED, -1, -5);
184 if (n->Var)
185 n->Var->aux = n->Store;
186 assert(n->Var->aux);
187 }
188 }
189
190 if (n->Opcode == IR_VAR_DECL) {
191 /* variable declaration */
192 assert(n->Var);
193 assert(!is_sampler_type(&n->Var->type));
194 n->Store->File = PROGRAM_TEMPORARY;
195 n->Store->Size = _slang_sizeof_type_specifier(&n->Var->type.specifier);
196 assert(n->Store->Size > 0);
197 return;
198 }
199 else {
200 assert(n->Opcode == IR_VAR);
201 assert(n->Var);
202
203 if (n->Store->Index < 0) {
204 const char *varName = (char *) n->Var->a_name;
205 struct gl_program *prog = A->program;
206 assert(prog);
207
208 /* determine storage location for this var.
209 * This is probably a pre-defined uniform or constant.
210 * We don't allocate storage for these until they're actually
211 * used to avoid wasting registers.
212 */
213 if (n->Store->File == PROGRAM_STATE_VAR) {
214 GLint i = _slang_lookup_statevar(varName, 0, prog->Parameters,
215 &n->Store->Swizzle);
216 assert(i >= 0);
217 n->Store->Index = i;
218 }
219 else if (n->Store->File == PROGRAM_CONSTANT) {
220 /* XXX compile-time constants should be converted to literals */
221 GLint i = slang_lookup_constant(varName, prog->Parameters,
222 &n->Store->Swizzle);
223 assert(i >= 0);
224 assert(n->Store->Size == 1);
225 n->Store->Index = i;
226 }
227 }
228 }
229 }
230
231
232 /**
233 * Return the TEXTURE_*_INDEX value that corresponds to a sampler type,
234 * or -1 if the type is not a sampler.
235 */
236 static GLint
237 sampler_to_texture_index(const slang_type_specifier_type type)
238 {
239 switch (type) {
240 case SLANG_SPEC_SAMPLER1D:
241 return TEXTURE_1D_INDEX;
242 case SLANG_SPEC_SAMPLER2D:
243 return TEXTURE_2D_INDEX;
244 case SLANG_SPEC_SAMPLER3D:
245 return TEXTURE_3D_INDEX;
246 case SLANG_SPEC_SAMPLERCUBE:
247 return TEXTURE_CUBE_INDEX;
248 case SLANG_SPEC_SAMPLER1DSHADOW:
249 return TEXTURE_1D_INDEX; /* XXX fix */
250 case SLANG_SPEC_SAMPLER2DSHADOW:
251 return TEXTURE_2D_INDEX; /* XXX fix */
252 default:
253 return -1;
254 }
255 }
256
257
258 /**
259 * Return the VERT_ATTRIB_* or FRAG_ATTRIB_* value that corresponds to
260 * a vertex or fragment program input variable. Return -1 if the input
261 * name is invalid.
262 * XXX return size too
263 */
264 static GLint
265 _slang_input_index(const char *name, GLenum target)
266 {
267 struct input_info {
268 const char *Name;
269 GLuint Attrib;
270 };
271 static const struct input_info vertInputs[] = {
272 { "gl_Vertex", VERT_ATTRIB_POS },
273 { "gl_Normal", VERT_ATTRIB_NORMAL },
274 { "gl_Color", VERT_ATTRIB_COLOR0 },
275 { "gl_SecondaryColor", VERT_ATTRIB_COLOR1 },
276 { "gl_FogCoord", VERT_ATTRIB_FOG },
277 { "gl_MultiTexCoord0", VERT_ATTRIB_TEX0 },
278 { "gl_MultiTexCoord1", VERT_ATTRIB_TEX1 },
279 { "gl_MultiTexCoord2", VERT_ATTRIB_TEX2 },
280 { "gl_MultiTexCoord3", VERT_ATTRIB_TEX3 },
281 { "gl_MultiTexCoord4", VERT_ATTRIB_TEX4 },
282 { "gl_MultiTexCoord5", VERT_ATTRIB_TEX5 },
283 { "gl_MultiTexCoord6", VERT_ATTRIB_TEX6 },
284 { "gl_MultiTexCoord7", VERT_ATTRIB_TEX7 },
285 { NULL, 0 }
286 };
287 static const struct input_info fragInputs[] = {
288 { "gl_FragCoord", FRAG_ATTRIB_WPOS },
289 { "gl_Color", FRAG_ATTRIB_COL0 },
290 { "gl_SecondaryColor", FRAG_ATTRIB_COL1 },
291 { "gl_FogFragCoord", FRAG_ATTRIB_FOGC },
292 { "gl_TexCoord", FRAG_ATTRIB_TEX0 },
293 { NULL, 0 }
294 };
295 GLuint i;
296 const struct input_info *inputs
297 = (target == GL_VERTEX_PROGRAM_ARB) ? vertInputs : fragInputs;
298
299 ASSERT(MAX_TEXTURE_UNITS == 8); /* if this fails, fix vertInputs above */
300
301 for (i = 0; inputs[i].Name; i++) {
302 if (strcmp(inputs[i].Name, name) == 0) {
303 /* found */
304 return inputs[i].Attrib;
305 }
306 }
307 return -1;
308 }
309
310
311 /**
312 * Return the VERT_RESULT_* or FRAG_RESULT_* value that corresponds to
313 * a vertex or fragment program output variable. Return -1 for an invalid
314 * output name.
315 */
316 static GLint
317 _slang_output_index(const char *name, GLenum target)
318 {
319 struct output_info {
320 const char *Name;
321 GLuint Attrib;
322 };
323 static const struct output_info vertOutputs[] = {
324 { "gl_Position", VERT_RESULT_HPOS },
325 { "gl_FrontColor", VERT_RESULT_COL0 },
326 { "gl_BackColor", VERT_RESULT_BFC0 },
327 { "gl_FrontSecondaryColor", VERT_RESULT_COL1 },
328 { "gl_BackSecondaryColor", VERT_RESULT_BFC1 },
329 { "gl_TexCoord", VERT_RESULT_TEX0 }, /* XXX indexed */
330 { "gl_FogFragCoord", VERT_RESULT_FOGC },
331 { "gl_PointSize", VERT_RESULT_PSIZ },
332 { NULL, 0 }
333 };
334 static const struct output_info fragOutputs[] = {
335 { "gl_FragColor", FRAG_RESULT_COLR },
336 { "gl_FragDepth", FRAG_RESULT_DEPR },
337 { NULL, 0 }
338 };
339 GLuint i;
340 const struct output_info *outputs
341 = (target == GL_VERTEX_PROGRAM_ARB) ? vertOutputs : fragOutputs;
342
343 for (i = 0; outputs[i].Name; i++) {
344 if (strcmp(outputs[i].Name, name) == 0) {
345 /* found */
346 return outputs[i].Attrib;
347 }
348 }
349 return -1;
350 }
351
352
353
354 /**********************************************************************/
355
356
357 /**
358 * Map "_asm foo" to IR_FOO, etc.
359 */
360 typedef struct
361 {
362 const char *Name;
363 slang_ir_opcode Opcode;
364 GLuint HaveRetValue, NumParams;
365 } slang_asm_info;
366
367
368 static slang_asm_info AsmInfo[] = {
369 /* vec4 binary op */
370 { "vec4_add", IR_ADD, 1, 2 },
371 { "vec4_subtract", IR_SUB, 1, 2 },
372 { "vec4_multiply", IR_MUL, 1, 2 },
373 { "vec4_dot", IR_DOT4, 1, 2 },
374 { "vec3_dot", IR_DOT3, 1, 2 },
375 { "vec3_cross", IR_CROSS, 1, 2 },
376 { "vec4_lrp", IR_LRP, 1, 3 },
377 { "vec4_min", IR_MIN, 1, 2 },
378 { "vec4_max", IR_MAX, 1, 2 },
379 { "vec4_clamp", IR_CLAMP, 1, 3 },
380 { "vec4_seq", IR_SEQ, 1, 2 },
381 { "vec4_sge", IR_SGE, 1, 2 },
382 { "vec4_sgt", IR_SGT, 1, 2 },
383 /* vec4 unary */
384 { "vec4_floor", IR_FLOOR, 1, 1 },
385 { "vec4_frac", IR_FRAC, 1, 1 },
386 { "vec4_abs", IR_ABS, 1, 1 },
387 { "vec4_negate", IR_NEG, 1, 1 },
388 { "vec4_ddx", IR_DDX, 1, 1 },
389 { "vec4_ddy", IR_DDY, 1, 1 },
390 /* float binary op */
391 { "float_add", IR_ADD, 1, 2 },
392 { "float_multiply", IR_MUL, 1, 2 },
393 { "float_divide", IR_DIV, 1, 2 },
394 { "float_power", IR_POW, 1, 2 },
395 /* texture / sampler */
396 { "vec4_tex1d", IR_TEX, 1, 2 },
397 { "vec4_texb1d", IR_TEXB, 1, 2 }, /* 1d w/ bias */
398 { "vec4_texp1d", IR_TEXP, 1, 2 }, /* 1d w/ projection */
399 { "vec4_tex2d", IR_TEX, 1, 2 },
400 { "vec4_texb2d", IR_TEXB, 1, 2 }, /* 2d w/ bias */
401 { "vec4_texp2d", IR_TEXP, 1, 2 }, /* 2d w/ projection */
402 { "vec4_tex3d", IR_TEX, 1, 2 },
403 { "vec4_texb3d", IR_TEXB, 1, 2 }, /* 3d w/ bias */
404 { "vec4_texp3d", IR_TEXP, 1, 2 }, /* 3d w/ projection */
405 { "vec4_texcube", IR_TEX, 1, 2 }, /* cubemap */
406
407 /* unary op */
408 { "int_to_float", IR_I_TO_F, 1, 1 },
409 { "float_to_int", IR_F_TO_I, 1, 1 },
410 { "float_exp", IR_EXP, 1, 1 },
411 { "float_exp2", IR_EXP2, 1, 1 },
412 { "float_log2", IR_LOG2, 1, 1 },
413 { "float_rsq", IR_RSQ, 1, 1 },
414 { "float_rcp", IR_RCP, 1, 1 },
415 { "float_sine", IR_SIN, 1, 1 },
416 { "float_cosine", IR_COS, 1, 1 },
417 { "float_noise1", IR_NOISE1, 1, 1},
418 { "float_noise2", IR_NOISE2, 1, 1},
419 { "float_noise3", IR_NOISE3, 1, 1},
420 { "float_noise4", IR_NOISE4, 1, 1},
421
422 { NULL, IR_NOP, 0, 0 }
423 };
424
425
426 /**
427 * Recursively free an IR tree.
428 */
429 static void
430 _slang_free_ir_tree(slang_ir_node *n)
431 {
432 #if 1
433 GLuint i;
434 if (!n)
435 return;
436 for (i = 0; i < 3; i++)
437 _slang_free_ir_tree(n->Children[i]);
438 /* Do not free n->BranchNode since it's a child elsewhere */
439 free(n);
440 #endif
441 }
442
443
444 static slang_ir_node *
445 new_node3(slang_ir_opcode op,
446 slang_ir_node *c0, slang_ir_node *c1, slang_ir_node *c2)
447 {
448 slang_ir_node *n = (slang_ir_node *) calloc(1, sizeof(slang_ir_node));
449 if (n) {
450 n->Opcode = op;
451 n->Children[0] = c0;
452 n->Children[1] = c1;
453 n->Children[2] = c2;
454 n->Writemask = WRITEMASK_XYZW;
455 n->InstLocation = -1;
456 }
457 return n;
458 }
459
460 static slang_ir_node *
461 new_node2(slang_ir_opcode op, slang_ir_node *c0, slang_ir_node *c1)
462 {
463 return new_node3(op, c0, c1, NULL);
464 }
465
466 static slang_ir_node *
467 new_node1(slang_ir_opcode op, slang_ir_node *c0)
468 {
469 return new_node3(op, c0, NULL, NULL);
470 }
471
472 static slang_ir_node *
473 new_node0(slang_ir_opcode op)
474 {
475 return new_node3(op, NULL, NULL, NULL);
476 }
477
478
479 static slang_ir_node *
480 new_seq(slang_ir_node *left, slang_ir_node *right)
481 {
482 if (!left)
483 return right;
484 if (!right)
485 return left;
486 return new_node2(IR_SEQ, left, right);
487 }
488
489 static slang_ir_node *
490 new_label(slang_atom labName)
491 {
492 slang_ir_node *n = new_node0(IR_LABEL);
493 n->Target = (char *) labName; /*_mesa_strdup(name);*/
494 return n;
495 }
496
497 static slang_ir_node *
498 new_float_literal(const float v[4])
499 {
500 const GLuint size = (v[0] == v[1] && v[0] == v[2] && v[0] == v[3]) ? 1 : 4;
501 slang_ir_node *n = new_node0(IR_FLOAT);
502 COPY_4V(n->Value, v);
503 /* allocate a storage object, but compute actual location (Index) later */
504 n->Store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, size);
505 return n;
506 }
507
508 /**
509 * Conditional jump.
510 * \param zeroOrOne indicates if the jump is to be taken on zero, or non-zero
511 * condition code state.
512 * XXX maybe pass an IR node as second param to indicate the jump target???
513 */
514 static slang_ir_node *
515 new_cjump(slang_atom target, GLuint zeroOrOne)
516 {
517 slang_ir_node *n = new_node0(zeroOrOne ? IR_CJUMP1 : IR_CJUMP0);
518 if (n)
519 n->Target = (char *) target;
520 return n;
521 }
522
523 /**
524 * Unconditional jump.
525 * XXX maybe pass an IR node as second param to indicate the jump target???
526 */
527 static slang_ir_node *
528 new_jump(slang_atom target)
529 {
530 slang_ir_node *n = new_node0(IR_JUMP);
531 if (n)
532 n->Target = (char *) target;
533 return n;
534 }
535
536
537 static slang_ir_node *
538 new_loop(slang_ir_node *body)
539 {
540 return new_node1(IR_LOOP, body);
541 }
542
543
544 static slang_ir_node *
545 new_break(slang_ir_node *loopNode)
546 {
547 slang_ir_node *n = new_node0(IR_BREAK);
548 assert(loopNode);
549 assert(loopNode->Opcode == IR_LOOP);
550 if (n) {
551 /* insert this node at head of linked list */
552 n->BranchNode = loopNode->BranchNode;
553 loopNode->BranchNode = n;
554 }
555 return n;
556 }
557
558
559 /**
560 * Make new IR_BREAK_IF_TRUE or IR_BREAK_IF_FALSE node.
561 */
562 static slang_ir_node *
563 new_break_if(slang_ir_node *loopNode, slang_ir_node *cond, GLboolean breakTrue)
564 {
565 slang_ir_node *n;
566 assert(loopNode);
567 assert(loopNode->Opcode == IR_LOOP);
568 n = new_node1(breakTrue ? IR_BREAK_IF_TRUE : IR_BREAK_IF_FALSE, cond);
569 if (n) {
570 /* insert this node at head of linked list */
571 n->BranchNode = loopNode->BranchNode;
572 loopNode->BranchNode = n;
573 }
574 return n;
575 }
576
577
578 /**
579 * Make new IR_CONT_IF_TRUE or IR_CONT_IF_FALSE node.
580 */
581 static slang_ir_node *
582 new_cont_if(slang_ir_node *loopNode, slang_ir_node *cond, GLboolean contTrue)
583 {
584 slang_ir_node *n;
585 assert(loopNode);
586 assert(loopNode->Opcode == IR_LOOP);
587 n = new_node1(contTrue ? IR_CONT_IF_TRUE : IR_CONT_IF_FALSE, cond);
588 if (n) {
589 /* insert this node at head of linked list */
590 n->BranchNode = loopNode->BranchNode;
591 loopNode->BranchNode = n;
592 }
593 return n;
594 }
595
596
597 static slang_ir_node *
598 new_cont(slang_ir_node *loopNode)
599 {
600 slang_ir_node *n = new_node0(IR_CONT);
601 assert(loopNode);
602 assert(loopNode->Opcode == IR_LOOP);
603 if (n) {
604 /* insert this node at head of linked list */
605 n->BranchNode = loopNode->BranchNode;
606 loopNode->BranchNode = n;
607 }
608 return n;
609 }
610
611
612 static slang_ir_node *
613 new_cond(slang_ir_node *n)
614 {
615 slang_ir_node *c = new_node1(IR_COND, n);
616 return c;
617 }
618
619
620 static slang_ir_node *
621 new_if(slang_ir_node *cond, slang_ir_node *ifPart, slang_ir_node *elsePart)
622 {
623 return new_node3(IR_IF, cond, ifPart, elsePart);
624 }
625
626
627 /**
628 * New IR_VAR node - a reference to a previously declared variable.
629 */
630 static slang_ir_node *
631 new_var(slang_assemble_ctx *A, slang_operation *oper, slang_atom name)
632 {
633 slang_variable *v = _slang_locate_variable(oper->locals, name, GL_TRUE);
634 slang_ir_node *n = new_node0(IR_VAR);
635 if (!v)
636 return NULL;
637 assert(!oper->var || oper->var == v);
638 v->used = GL_TRUE;
639 n->Var = v;
640 slang_allocate_storage(A, n);
641
642 return n;
643 }
644
645
646 /**
647 * Check if the given function is really just a wrapper for a
648 * basic assembly instruction.
649 */
650 static GLboolean
651 slang_is_asm_function(const slang_function *fun)
652 {
653 if (fun->body->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE &&
654 fun->body->num_children == 1 &&
655 fun->body->children[0].type == SLANG_OPER_ASM) {
656 return GL_TRUE;
657 }
658 return GL_FALSE;
659 }
660
661
662 /**
663 * Produce inline code for a call to an assembly instruction.
664 */
665 static slang_operation *
666 slang_inline_asm_function(slang_assemble_ctx *A,
667 slang_function *fun, slang_operation *oper)
668 {
669 const GLuint numArgs = oper->num_children;
670 const slang_operation *args = oper->children;
671 GLuint i;
672 slang_operation *inlined = slang_operation_new(1);
673
674 /*assert(oper->type == SLANG_OPER_CALL); or vec4_add, etc */
675 /*
676 printf("Inline asm %s\n", (char*) fun->header.a_name);
677 */
678 inlined->type = fun->body->children[0].type;
679 inlined->a_id = fun->body->children[0].a_id;
680 inlined->num_children = numArgs;
681 inlined->children = slang_operation_new(numArgs);
682 #if 0
683 inlined->locals = slang_variable_scope_copy(oper->locals);
684 #else
685 assert(inlined->locals);
686 inlined->locals->outer_scope = oper->locals->outer_scope;
687 #endif
688
689 for (i = 0; i < numArgs; i++) {
690 slang_operation_copy(inlined->children + i, args + i);
691 }
692
693 return inlined;
694 }
695
696
697 static void
698 slang_resolve_variable(slang_operation *oper)
699 {
700 if (oper->type != SLANG_OPER_IDENTIFIER)
701 return;
702 if (!oper->var) {
703 oper->var = _slang_locate_variable(oper->locals,
704 (const slang_atom) oper->a_id,
705 GL_TRUE);
706 if (oper->var)
707 oper->var->used = GL_TRUE;
708 }
709 }
710
711
712 /**
713 * Replace particular variables (SLANG_OPER_IDENTIFIER) with new expressions.
714 */
715 static void
716 slang_substitute(slang_assemble_ctx *A, slang_operation *oper,
717 GLuint substCount, slang_variable **substOld,
718 slang_operation **substNew, GLboolean isLHS)
719 {
720 switch (oper->type) {
721 case SLANG_OPER_VARIABLE_DECL:
722 {
723 slang_variable *v = _slang_locate_variable(oper->locals,
724 oper->a_id, GL_TRUE);
725 assert(v);
726 if (v->initializer && oper->num_children == 0) {
727 /* set child of oper to copy of initializer */
728 oper->num_children = 1;
729 oper->children = slang_operation_new(1);
730 slang_operation_copy(&oper->children[0], v->initializer);
731 }
732 if (oper->num_children == 1) {
733 /* the initializer */
734 slang_substitute(A, &oper->children[0], substCount, substOld, substNew, GL_FALSE);
735 }
736 }
737 break;
738 case SLANG_OPER_IDENTIFIER:
739 assert(oper->num_children == 0);
740 if (1/**!isLHS XXX FIX */) {
741 slang_atom id = oper->a_id;
742 slang_variable *v;
743 GLuint i;
744 v = _slang_locate_variable(oper->locals, id, GL_TRUE);
745 if (!v) {
746 printf("var %s not found!\n", (char *) oper->a_id);
747 _slang_print_var_scope(oper->locals, 6);
748
749 abort();
750 break;
751 }
752
753 /* look for a substitution */
754 for (i = 0; i < substCount; i++) {
755 if (v == substOld[i]) {
756 /* OK, replace this SLANG_OPER_IDENTIFIER with a new expr */
757 #if 0 /* DEBUG only */
758 if (substNew[i]->type == SLANG_OPER_IDENTIFIER) {
759 assert(substNew[i]->var);
760 assert(substNew[i]->var->a_name);
761 printf("Substitute %s with %s in id node %p\n",
762 (char*)v->a_name, (char*) substNew[i]->var->a_name,
763 (void*) oper);
764 }
765 else {
766 printf("Substitute %s with %f in id node %p\n",
767 (char*)v->a_name, substNew[i]->literal[0],
768 (void*) oper);
769 }
770 #endif
771 slang_operation_copy(oper, substNew[i]);
772 break;
773 }
774 }
775 }
776 break;
777 #if 1 /* XXX rely on default case below */
778 case SLANG_OPER_RETURN:
779 /* do return replacement here too */
780 assert(oper->num_children == 0 || oper->num_children == 1);
781 if (oper->num_children == 1) {
782 /* replace:
783 * return expr;
784 * with:
785 * __retVal = expr;
786 * return;
787 * then do substitutions on the assignment.
788 */
789 slang_operation *blockOper, *assignOper, *returnOper;
790 blockOper = slang_operation_new(1);
791 blockOper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE;
792 blockOper->num_children = 2;
793 blockOper->children = slang_operation_new(2);
794 assignOper = blockOper->children + 0;
795 returnOper = blockOper->children + 1;
796
797 assignOper->type = SLANG_OPER_ASSIGN;
798 assignOper->num_children = 2;
799 assignOper->children = slang_operation_new(2);
800 assignOper->children[0].type = SLANG_OPER_IDENTIFIER;
801 assignOper->children[0].a_id = slang_atom_pool_atom(A->atoms, "__retVal");
802 assignOper->children[0].locals->outer_scope = oper->locals;
803 assignOper->locals = oper->locals;
804 slang_operation_copy(&assignOper->children[1],
805 &oper->children[0]);
806
807 returnOper->type = SLANG_OPER_RETURN;
808 assert(returnOper->num_children == 0);
809
810 /* do substitutions on the "__retVal = expr" sub-tree */
811 slang_substitute(A, assignOper,
812 substCount, substOld, substNew, GL_FALSE);
813
814 /* install new code */
815 slang_operation_copy(oper, blockOper);
816 slang_operation_destruct(blockOper);
817 }
818 break;
819 #endif
820 case SLANG_OPER_ASSIGN:
821 case SLANG_OPER_SUBSCRIPT:
822 /* special case:
823 * child[0] can't have substitutions but child[1] can.
824 */
825 slang_substitute(A, &oper->children[0],
826 substCount, substOld, substNew, GL_TRUE);
827 slang_substitute(A, &oper->children[1],
828 substCount, substOld, substNew, GL_FALSE);
829 break;
830 case SLANG_OPER_FIELD:
831 /* XXX NEW - test */
832 slang_substitute(A, &oper->children[0],
833 substCount, substOld, substNew, GL_TRUE);
834 break;
835 default:
836 {
837 GLuint i;
838 for (i = 0; i < oper->num_children; i++)
839 slang_substitute(A, &oper->children[i],
840 substCount, substOld, substNew, GL_FALSE);
841 }
842 }
843 }
844
845
846
847 /**
848 * Inline the given function call operation.
849 * Return a new slang_operation that corresponds to the inlined code.
850 */
851 static slang_operation *
852 slang_inline_function_call(slang_assemble_ctx * A, slang_function *fun,
853 slang_operation *oper, slang_operation *returnOper)
854 {
855 typedef enum {
856 SUBST = 1,
857 COPY_IN,
858 COPY_OUT
859 } ParamMode;
860 ParamMode *paramMode;
861 const GLboolean haveRetValue = _slang_function_has_return_value(fun);
862 const GLuint numArgs = oper->num_children;
863 const GLuint totalArgs = numArgs + haveRetValue;
864 slang_operation *args = oper->children;
865 slang_operation *inlined, *top;
866 slang_variable **substOld;
867 slang_operation **substNew;
868 GLuint substCount, numCopyIn, i;
869
870 /*assert(oper->type == SLANG_OPER_CALL); (or (matrix) multiply, etc) */
871 assert(fun->param_count == totalArgs);
872
873 /* allocate temporary arrays */
874 paramMode = (ParamMode *)
875 _mesa_calloc(totalArgs * sizeof(ParamMode));
876 substOld = (slang_variable **)
877 _mesa_calloc(totalArgs * sizeof(slang_variable *));
878 substNew = (slang_operation **)
879 _mesa_calloc(totalArgs * sizeof(slang_operation *));
880
881 #if 0
882 printf("Inline call to %s (total vars=%d nparams=%d)\n",
883 (char *) fun->header.a_name,
884 fun->parameters->num_variables, numArgs);
885 #endif
886
887 if (haveRetValue && !returnOper) {
888 /* Create 3-child comma sequence for inlined code:
889 * child[0]: declare __resultTmp
890 * child[1]: inlined function body
891 * child[2]: __resultTmp
892 */
893 slang_operation *commaSeq;
894 slang_operation *declOper = NULL;
895 slang_variable *resultVar;
896
897 commaSeq = slang_operation_new(1);
898 commaSeq->type = SLANG_OPER_SEQUENCE;
899 assert(commaSeq->locals);
900 commaSeq->locals->outer_scope = oper->locals->outer_scope;
901 commaSeq->num_children = 3;
902 commaSeq->children = slang_operation_new(3);
903 /* allocate the return var */
904 resultVar = slang_variable_scope_grow(commaSeq->locals);
905 /*
906 printf("Alloc __resultTmp in scope %p for retval of calling %s\n",
907 (void*)commaSeq->locals, (char *) fun->header.a_name);
908 */
909
910 resultVar->a_name = slang_atom_pool_atom(A->atoms, "__resultTmp");
911 resultVar->type = fun->header.type; /* XXX copy? */
912 resultVar->isTemp = GL_TRUE;
913
914 /* child[0] = __resultTmp declaration */
915 declOper = &commaSeq->children[0];
916 declOper->type = SLANG_OPER_VARIABLE_DECL;
917 declOper->a_id = resultVar->a_name;
918 declOper->locals->outer_scope = commaSeq->locals; /*** ??? **/
919
920 /* child[1] = function body */
921 inlined = &commaSeq->children[1];
922 /* XXXX this may be inappropriate!!!!: */
923 inlined->locals->outer_scope = commaSeq->locals;
924
925 /* child[2] = __resultTmp reference */
926 returnOper = &commaSeq->children[2];
927 returnOper->type = SLANG_OPER_IDENTIFIER;
928 returnOper->a_id = resultVar->a_name;
929 returnOper->locals->outer_scope = commaSeq->locals;
930 declOper->locals->outer_scope = commaSeq->locals;
931
932 top = commaSeq;
933 }
934 else {
935 top = inlined = slang_operation_new(1);
936 /* XXXX this may be inappropriate!!!! */
937 inlined->locals->outer_scope = oper->locals->outer_scope;
938 }
939
940
941 assert(inlined->locals);
942
943 /* Examine the parameters, look for inout/out params, look for possible
944 * substitutions, etc:
945 * param type behaviour
946 * in copy actual to local
947 * const in substitute param with actual
948 * out copy out
949 */
950 substCount = 0;
951 for (i = 0; i < totalArgs; i++) {
952 slang_variable *p = fun->parameters->variables[i];
953 /*
954 printf("Param %d: %s %s \n", i,
955 slang_type_qual_string(p->type.qualifier),
956 (char *) p->a_name);
957 */
958 if (p->type.qualifier == SLANG_QUAL_INOUT ||
959 p->type.qualifier == SLANG_QUAL_OUT) {
960 /* an output param */
961 slang_operation *arg;
962 if (i < numArgs)
963 arg = &args[i];
964 else
965 arg = returnOper;
966 paramMode[i] = SUBST;
967
968 if (arg->type == SLANG_OPER_IDENTIFIER)
969 slang_resolve_variable(arg);
970
971 /* replace parameter 'p' with argument 'arg' */
972 substOld[substCount] = p;
973 substNew[substCount] = arg; /* will get copied */
974 substCount++;
975 }
976 else if (p->type.qualifier == SLANG_QUAL_CONST) {
977 /* a constant input param */
978 if (args[i].type == SLANG_OPER_IDENTIFIER ||
979 args[i].type == SLANG_OPER_LITERAL_FLOAT) {
980 /* replace all occurances of this parameter variable with the
981 * actual argument variable or a literal.
982 */
983 paramMode[i] = SUBST;
984 slang_resolve_variable(&args[i]);
985 substOld[substCount] = p;
986 substNew[substCount] = &args[i]; /* will get copied */
987 substCount++;
988 }
989 else {
990 paramMode[i] = COPY_IN;
991 }
992 }
993 else {
994 paramMode[i] = COPY_IN;
995 }
996 assert(paramMode[i]);
997 }
998
999 /* actual code inlining: */
1000 slang_operation_copy(inlined, fun->body);
1001
1002 /*** XXX review this */
1003 assert(inlined->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE);
1004 inlined->type = SLANG_OPER_BLOCK_NEW_SCOPE;
1005
1006 #if 0
1007 printf("======================= orig body code ======================\n");
1008 printf("=== params scope = %p\n", (void*) fun->parameters);
1009 slang_print_tree(fun->body, 8);
1010 printf("======================= copied code =========================\n");
1011 slang_print_tree(inlined, 8);
1012 #endif
1013
1014 /* do parameter substitution in inlined code: */
1015 slang_substitute(A, inlined, substCount, substOld, substNew, GL_FALSE);
1016
1017 #if 0
1018 printf("======================= subst code ==========================\n");
1019 slang_print_tree(inlined, 8);
1020 printf("=============================================================\n");
1021 #endif
1022
1023 /* New prolog statements: (inserted before the inlined code)
1024 * Copy the 'in' arguments.
1025 */
1026 numCopyIn = 0;
1027 for (i = 0; i < numArgs; i++) {
1028 if (paramMode[i] == COPY_IN) {
1029 slang_variable *p = fun->parameters->variables[i];
1030 /* declare parameter 'p' */
1031 slang_operation *decl = slang_operation_insert(&inlined->num_children,
1032 &inlined->children,
1033 numCopyIn);
1034 /*
1035 printf("COPY_IN %s from expr\n", (char*)p->a_name);
1036 */
1037 decl->type = SLANG_OPER_VARIABLE_DECL;
1038 assert(decl->locals);
1039 decl->locals = fun->parameters;
1040 decl->a_id = p->a_name;
1041 decl->num_children = 1;
1042 decl->children = slang_operation_new(1);
1043
1044 /* child[0] is the var's initializer */
1045 slang_operation_copy(&decl->children[0], args + i);
1046
1047 numCopyIn++;
1048 }
1049 }
1050
1051 /* New epilog statements:
1052 * 1. Create end of function label to jump to from return statements.
1053 * 2. Copy the 'out' parameter vars
1054 */
1055 {
1056 slang_operation *lab = slang_operation_insert(&inlined->num_children,
1057 &inlined->children,
1058 inlined->num_children);
1059 lab->type = SLANG_OPER_LABEL;
1060 lab->a_id = slang_atom_pool_atom(A->atoms,
1061 (char *) A->CurFunction->end_label);
1062 }
1063
1064 for (i = 0; i < totalArgs; i++) {
1065 if (paramMode[i] == COPY_OUT) {
1066 const slang_variable *p = fun->parameters->variables[i];
1067 /* actualCallVar = outParam */
1068 /*if (i > 0 || !haveRetValue)*/
1069 slang_operation *ass = slang_operation_insert(&inlined->num_children,
1070 &inlined->children,
1071 inlined->num_children);
1072 ass->type = SLANG_OPER_ASSIGN;
1073 ass->num_children = 2;
1074 ass->locals = _slang_variable_scope_new(inlined->locals);
1075 assert(ass->locals);
1076 ass->children = slang_operation_new(2);
1077 ass->children[0] = args[i]; /*XXX copy */
1078 ass->children[1].type = SLANG_OPER_IDENTIFIER;
1079 ass->children[1].a_id = p->a_name;
1080 ass->children[1].locals = _slang_variable_scope_new(ass->locals);
1081 }
1082 }
1083
1084 _mesa_free(paramMode);
1085 _mesa_free(substOld);
1086 _mesa_free(substNew);
1087
1088 #if 0
1089 printf("Done Inline call to %s (total vars=%d nparams=%d)\n",
1090 (char *) fun->header.a_name,
1091 fun->parameters->num_variables, numArgs);
1092 slang_print_tree(top, 0);
1093 #endif
1094 return top;
1095 }
1096
1097
1098 static slang_ir_node *
1099 _slang_gen_function_call(slang_assemble_ctx *A, slang_function *fun,
1100 slang_operation *oper, slang_operation *dest)
1101 {
1102 slang_ir_node *n;
1103 slang_operation *inlined;
1104 slang_function *prevFunc;
1105
1106 prevFunc = A->CurFunction;
1107 A->CurFunction = fun;
1108
1109 if (!A->CurFunction->end_label) {
1110 char name[200];
1111 sprintf(name, "__endOfFunc_%s_", (char *) A->CurFunction->header.a_name);
1112 A->CurFunction->end_label = slang_atom_pool_gen(A->atoms, name);
1113 }
1114
1115 if (slang_is_asm_function(fun) && !dest) {
1116 /* assemble assembly function - tree style */
1117 inlined = slang_inline_asm_function(A, fun, oper);
1118 }
1119 else {
1120 /* non-assembly function */
1121 inlined = slang_inline_function_call(A, fun, oper, dest);
1122 }
1123
1124 /* Replace the function call with the inlined block */
1125 #if 0
1126 slang_operation_construct(oper);
1127 slang_operation_copy(oper, inlined);
1128 #else
1129 *oper = *inlined;
1130 #endif
1131
1132
1133 #if 0
1134 assert(inlined->locals);
1135 printf("*** Inlined code for call to %s:\n",
1136 (char*) fun->header.a_name);
1137 slang_print_tree(oper, 10);
1138 printf("\n");
1139 #endif
1140
1141 n = _slang_gen_operation(A, oper);
1142
1143 A->CurFunction->end_label = NULL;
1144
1145 A->CurFunction = prevFunc;
1146
1147 return n;
1148 }
1149
1150
1151 static slang_asm_info *
1152 slang_find_asm_info(const char *name)
1153 {
1154 GLuint i;
1155 for (i = 0; AsmInfo[i].Name; i++) {
1156 if (_mesa_strcmp(AsmInfo[i].Name, name) == 0) {
1157 return AsmInfo + i;
1158 }
1159 }
1160 return NULL;
1161 }
1162
1163
1164 static GLuint
1165 make_writemask(char *field)
1166 {
1167 GLuint mask = 0x0;
1168 while (*field) {
1169 switch (*field) {
1170 case 'x':
1171 mask |= WRITEMASK_X;
1172 break;
1173 case 'y':
1174 mask |= WRITEMASK_Y;
1175 break;
1176 case 'z':
1177 mask |= WRITEMASK_Z;
1178 break;
1179 case 'w':
1180 mask |= WRITEMASK_W;
1181 break;
1182 default:
1183 abort();
1184 }
1185 field++;
1186 }
1187 if (mask == 0x0)
1188 return WRITEMASK_XYZW;
1189 else
1190 return mask;
1191 }
1192
1193
1194 /**
1195 * Generate IR tree for an asm instruction/operation such as:
1196 * __asm vec4_dot __retVal.x, v1, v2;
1197 */
1198 static slang_ir_node *
1199 _slang_gen_asm(slang_assemble_ctx *A, slang_operation *oper,
1200 slang_operation *dest)
1201 {
1202 const slang_asm_info *info;
1203 slang_ir_node *kids[3], *n;
1204 GLuint j, firstOperand;
1205
1206 assert(oper->type == SLANG_OPER_ASM);
1207
1208 info = slang_find_asm_info((char *) oper->a_id);
1209 if (!info) {
1210 _mesa_problem(NULL, "undefined __asm function %s\n",
1211 (char *) oper->a_id);
1212 assert(info);
1213 }
1214 assert(info->NumParams <= 3);
1215
1216 if (info->NumParams == oper->num_children) {
1217 /* Storage for result is not specified.
1218 * Children[0], [1] are the operands.
1219 */
1220 firstOperand = 0;
1221 }
1222 else {
1223 /* Storage for result (child[0]) is specified.
1224 * Children[1], [2] are the operands.
1225 */
1226 firstOperand = 1;
1227 }
1228
1229 /* assemble child(ren) */
1230 kids[0] = kids[1] = kids[2] = NULL;
1231 for (j = 0; j < info->NumParams; j++) {
1232 kids[j] = _slang_gen_operation(A, &oper->children[firstOperand + j]);
1233 }
1234
1235 n = new_node3(info->Opcode, kids[0], kids[1], kids[2]);
1236
1237 if (firstOperand) {
1238 /* Setup n->Store to be a particular location. Otherwise, storage
1239 * for the result (a temporary) will be allocated later.
1240 */
1241 GLuint writemask = WRITEMASK_XYZW;
1242 slang_operation *dest_oper;
1243 slang_ir_node *n0;
1244
1245 dest_oper = &oper->children[0];
1246 while /*if*/ (dest_oper->type == SLANG_OPER_FIELD) {
1247 /* writemask */
1248 writemask &= /*=*/make_writemask((char*) dest_oper->a_id);
1249 dest_oper = &dest_oper->children[0];
1250 }
1251
1252 n0 = _slang_gen_operation(A, dest_oper);
1253 assert(n0->Var);
1254 assert(n0->Store);
1255 assert(!n->Store);
1256 n->Store = n0->Store;
1257 n->Writemask = writemask;
1258
1259 free(n0);
1260 }
1261
1262 return n;
1263 }
1264
1265
1266
1267 static GLboolean
1268 _slang_is_noop(const slang_operation *oper)
1269 {
1270 if (!oper ||
1271 oper->type == SLANG_OPER_VOID ||
1272 (oper->num_children == 1 && oper->children[0].type == SLANG_OPER_VOID))
1273 return GL_TRUE;
1274 else
1275 return GL_FALSE;
1276 }
1277
1278
1279 static void
1280 print_funcs(struct slang_function_scope_ *scope, const char *name)
1281 {
1282 GLuint i;
1283 for (i = 0; i < scope->num_functions; i++) {
1284 slang_function *f = &scope->functions[i];
1285 if (!name || strcmp(name, (char*) f->header.a_name) == 0)
1286 printf(" %s (%d args)\n", name, f->param_count);
1287
1288 }
1289 if (scope->outer_scope)
1290 print_funcs(scope->outer_scope, name);
1291 }
1292
1293
1294 /**
1295 * Return first function in the scope that has the given name.
1296 * This is the function we'll try to call when there is no exact match
1297 * between function parameters and call arguments.
1298 *
1299 * XXX we should really create a list of candidate functions and try
1300 * all of them...
1301 */
1302 static slang_function *
1303 _slang_first_function(struct slang_function_scope_ *scope, const char *name)
1304 {
1305 GLuint i;
1306 for (i = 0; i < scope->num_functions; i++) {
1307 slang_function *f = &scope->functions[i];
1308 if (strcmp(name, (char*) f->header.a_name) == 0)
1309 return f;
1310 }
1311 if (scope->outer_scope)
1312 return _slang_first_function(scope->outer_scope, name);
1313 return NULL;
1314 }
1315
1316
1317
1318 /**
1319 * Assemble a function call, given a particular function name.
1320 * \param name the function's name (operators like '*' are possible).
1321 */
1322 static slang_ir_node *
1323 _slang_gen_function_call_name(slang_assemble_ctx *A, const char *name,
1324 slang_operation *oper, slang_operation *dest)
1325 {
1326 slang_operation *params = oper->children;
1327 const GLuint param_count = oper->num_children;
1328 slang_atom atom;
1329 slang_function *fun;
1330
1331 atom = slang_atom_pool_atom(A->atoms, name);
1332 if (atom == SLANG_ATOM_NULL)
1333 return NULL;
1334
1335 /*
1336 * Use 'name' to find the function to call
1337 */
1338 fun = _slang_locate_function(A->space.funcs, atom, params, param_count,
1339 &A->space, A->atoms);
1340 if (!fun) {
1341 /* A function with exactly the right parameters/types was not found.
1342 * Try adapting the parameters.
1343 */
1344 fun = _slang_first_function(A->space.funcs, name);
1345 if (!_slang_adapt_call(oper, fun, &A->space, A->atoms)) {
1346 RETURN_ERROR2("Undefined function (or no matching parameters)",
1347 name, 0);
1348 }
1349 assert(fun);
1350 }
1351
1352 return _slang_gen_function_call(A, fun, oper, dest);
1353 }
1354
1355
1356 static GLboolean
1357 _slang_is_constant_cond(const slang_operation *oper, GLboolean *value)
1358 {
1359 if (oper->type == SLANG_OPER_LITERAL_FLOAT ||
1360 oper->type == SLANG_OPER_LITERAL_INT ||
1361 oper->type == SLANG_OPER_LITERAL_BOOL) {
1362 if (oper->literal[0])
1363 *value = GL_TRUE;
1364 else
1365 *value = GL_FALSE;
1366 return GL_TRUE;
1367 }
1368 else if (oper->type == SLANG_OPER_EXPRESSION &&
1369 oper->num_children == 1) {
1370 return _slang_is_constant_cond(&oper->children[0], value);
1371 }
1372 return GL_FALSE;
1373 }
1374
1375
1376
1377 /**
1378 * Generate loop code using high-level IR_LOOP instruction
1379 */
1380 static slang_ir_node *
1381 _slang_gen_while(slang_assemble_ctx * A, const slang_operation *oper)
1382 {
1383 /*
1384 * LOOP:
1385 * BREAK if !expr (child[0])
1386 * body code (child[1])
1387 */
1388 slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body;
1389 GLboolean isConst, constTrue;
1390
1391 /* Check if loop condition is a constant */
1392 isConst = _slang_is_constant_cond(&oper->children[0], &constTrue);
1393
1394 if (isConst && !constTrue) {
1395 /* loop is never executed! */
1396 return new_node0(IR_NOP);
1397 }
1398
1399 loop = new_loop(NULL);
1400
1401 /* save old, push new loop */
1402 prevLoop = A->CurLoop;
1403 A->CurLoop = loop;
1404
1405 cond = new_cond(_slang_gen_operation(A, &oper->children[0]));
1406 if (isConst && constTrue) {
1407 /* while(nonzero constant), no conditional break */
1408 breakIf = NULL;
1409 }
1410 else {
1411 breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
1412 }
1413 body = _slang_gen_operation(A, &oper->children[1]);
1414 loop->Children[0] = new_seq(breakIf, body);
1415
1416 /* Do infinite loop detection */
1417 if (loop->BranchNode == 0 && isConst && constTrue) {
1418 /* infinite loop detected */
1419 A->CurLoop = prevLoop; /* clean-up */
1420 RETURN_ERROR("Infinite loop detected!", 0);
1421 }
1422
1423 /* pop loop, restore prev */
1424 A->CurLoop = prevLoop;
1425
1426 return loop;
1427 }
1428
1429
1430 /**
1431 * Generate IR tree for a do-while loop using high-level LOOP, IF instructions.
1432 */
1433 static slang_ir_node *
1434 _slang_gen_do(slang_assemble_ctx * A, const slang_operation *oper)
1435 {
1436 /*
1437 * LOOP:
1438 * body code (child[0])
1439 * BREAK if !expr (child[1])
1440 */
1441 slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body;
1442 GLboolean isConst, constTrue;
1443
1444 /* Check if loop condition is a constant */
1445 isConst = _slang_is_constant_cond(&oper->children[0], &constTrue);
1446
1447 loop = new_loop(NULL);
1448
1449 /* save old, push new loop */
1450 prevLoop = A->CurLoop;
1451 A->CurLoop = loop;
1452
1453 body = _slang_gen_operation(A, &oper->children[0]);
1454 cond = new_cond(_slang_gen_operation(A, &oper->children[1]));
1455 if (isConst && constTrue) {
1456 /* while(nonzero constant), no conditional break */
1457 breakIf = NULL;
1458 }
1459 else {
1460 breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
1461 }
1462 loop->Children[0] = new_seq(body, breakIf);
1463
1464 /* pop loop, restore prev */
1465 A->CurLoop = prevLoop;
1466
1467 return loop;
1468 }
1469
1470
1471 /**
1472 * Generate for-loop using high-level IR_LOOP instruction.
1473 */
1474 static slang_ir_node *
1475 _slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
1476 {
1477 /*
1478 * init (child[0])
1479 * LOOP:
1480 * BREAK if !expr (child[1])
1481 * body code (child[3])
1482 * incr code (child[2]) // XXX continue here
1483 */
1484 slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body, *init, *incr;
1485
1486 init = _slang_gen_operation(A, &oper->children[0]);
1487 loop = new_loop(NULL);
1488
1489 /* save old, push new loop */
1490 prevLoop = A->CurLoop;
1491 A->CurLoop = loop;
1492
1493 cond = new_cond(_slang_gen_operation(A, &oper->children[1]));
1494 breakIf = new_break_if(A->CurLoop, cond, GL_FALSE);
1495 body = _slang_gen_operation(A, &oper->children[3]);
1496 incr = _slang_gen_operation(A, &oper->children[2]);
1497 loop->Children[0] = new_seq(breakIf,
1498 new_seq(body, incr));
1499
1500 /* pop loop, restore prev */
1501 A->CurLoop = prevLoop;
1502
1503 return new_seq(init, loop);
1504 }
1505
1506
1507 /**
1508 * Generate IR tree for an if/then/else conditional using BRAnch instructions.
1509 */
1510 static slang_ir_node *
1511 _slang_gen_if(slang_assemble_ctx * A, const slang_operation *oper)
1512 {
1513 /*
1514 * eval expr (child[0]), updating condcodes
1515 * branch if false to _else or _endif
1516 * "true" code block
1517 * if haveElseClause clause:
1518 * jump "__endif"
1519 * label "__else"
1520 * "false" code block
1521 * label "__endif"
1522 */
1523 const GLboolean haveElseClause = !_slang_is_noop(&oper->children[2]);
1524 slang_ir_node *cond, *bra, *trueBody, *endifLab, *tree;
1525 slang_atom elseAtom = slang_atom_pool_gen(A->atoms, "__else");
1526 slang_atom endifAtom = slang_atom_pool_gen(A->atoms, "__endif");
1527
1528 cond = _slang_gen_operation(A, &oper->children[0]);
1529 cond = new_cond(cond);
1530 /*assert(cond->Store);*/
1531 bra = new_cjump(haveElseClause ? elseAtom : endifAtom, 0);
1532 tree = new_seq(cond, bra);
1533
1534 trueBody = _slang_gen_operation(A, &oper->children[1]);
1535 tree = new_seq(tree, trueBody);
1536
1537 if (haveElseClause) {
1538 /* else clause */
1539 slang_ir_node *jump, *elseLab, *falseBody;
1540 jump = new_jump(endifAtom);
1541 tree = new_seq(tree, jump);
1542
1543 elseLab = new_label(elseAtom);
1544 tree = new_seq(tree, elseLab);
1545
1546 falseBody = _slang_gen_operation(A, &oper->children[2]);
1547 tree = new_seq(tree, falseBody);
1548 }
1549
1550 endifLab = new_label(endifAtom);
1551 tree = new_seq(tree, endifLab);
1552
1553 return tree;
1554 }
1555
1556
1557 /**
1558 * Determine if the given operation is of a specific type.
1559 */
1560 static GLboolean
1561 is_operation_type(const const slang_operation *oper, slang_operation_type type)
1562 {
1563 if (oper->type == type)
1564 return GL_TRUE;
1565 else if ((oper->type == SLANG_OPER_BLOCK_NEW_SCOPE ||
1566 oper->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) &&
1567 oper->num_children == 1)
1568 return is_operation_type(&oper->children[0], type);
1569 else
1570 return GL_FALSE;
1571 }
1572
1573
1574 /**
1575 * Generate IR tree for an if/then/else conditional using high-level
1576 * IR_IF instruction.
1577 */
1578 static slang_ir_node *
1579 _slang_gen_hl_if(slang_assemble_ctx * A, const slang_operation *oper)
1580 {
1581 /*
1582 * eval expr (child[0]), updating condcodes
1583 * IF expr THEN
1584 * if-body code
1585 * ELSE
1586 * else-body code
1587 * ENDIF
1588 */
1589 const GLboolean haveElseClause = !_slang_is_noop(&oper->children[2]);
1590 slang_ir_node *ifNode, *cond, *ifBody, *elseBody;
1591
1592 cond = _slang_gen_operation(A, &oper->children[0]);
1593 cond = new_cond(cond);
1594
1595 if (is_operation_type(&oper->children[1], SLANG_OPER_BREAK)) {
1596 /* Special case: generate a conditional break */
1597 ifBody = new_break_if(A->CurLoop, cond, GL_TRUE);
1598 if (haveElseClause) {
1599 elseBody = _slang_gen_operation(A, &oper->children[2]);
1600 return new_seq(ifBody, elseBody);
1601 }
1602 return ifBody;
1603 }
1604 else if (is_operation_type(&oper->children[1], SLANG_OPER_CONTINUE)) {
1605 /* Special case: generate a conditional break */
1606 ifBody = new_cont_if(A->CurLoop, cond, GL_TRUE);
1607 if (haveElseClause) {
1608 elseBody = _slang_gen_operation(A, &oper->children[2]);
1609 return new_seq(ifBody, elseBody);
1610 }
1611 return ifBody;
1612 }
1613 else {
1614 /* general case */
1615 ifBody = _slang_gen_operation(A, &oper->children[1]);
1616 if (haveElseClause)
1617 elseBody = _slang_gen_operation(A, &oper->children[2]);
1618 else
1619 elseBody = NULL;
1620 ifNode = new_if(cond, ifBody, elseBody);
1621 return ifNode;
1622 }
1623 }
1624
1625
1626
1627 /**
1628 * Generate IR node for storage of a temporary of given size.
1629 */
1630 static slang_ir_node *
1631 _slang_gen_temporary(GLint size)
1632 {
1633 slang_ir_storage *store;
1634 slang_ir_node *n;
1635
1636 store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, size);
1637 if (store) {
1638 n = new_node0(IR_VAR_DECL);
1639 if (n) {
1640 n->Store = store;
1641 }
1642 else {
1643 free(store);
1644 }
1645 }
1646 return n;
1647 }
1648
1649
1650 /**
1651 * Generate IR node for allocating/declaring a variable.
1652 */
1653 static slang_ir_node *
1654 _slang_gen_var_decl(slang_assemble_ctx *A, slang_variable *var)
1655 {
1656 slang_ir_node *n;
1657 n = new_node0(IR_VAR_DECL);
1658 if (n) {
1659 n->Var = var;
1660 slang_allocate_storage(A, n);
1661 assert(n->Store);
1662 assert(n->Store->Index < 0);
1663 assert(n->Store->Size > 0);
1664 assert(var->aux);
1665 assert(n->Store == var->aux);
1666 }
1667 return n;
1668 }
1669
1670
1671
1672
1673 /**
1674 * Generate code for a selection expression: b ? x : y
1675 * XXX in some cases we could implement a selection expression
1676 * with an LRP instruction (use the boolean as the interpolant).
1677 */
1678 static slang_ir_node *
1679 _slang_gen_select(slang_assemble_ctx *A, slang_operation *oper)
1680 {
1681 slang_atom altAtom = slang_atom_pool_gen(A->atoms, "__selectAlt");
1682 slang_atom endAtom = slang_atom_pool_gen(A->atoms, "__selectEnd");
1683 slang_ir_node *altLab, *endLab;
1684 slang_ir_node *tree, *tmpDecl, *tmpVar, *cond, *cjump, *jump;
1685 slang_ir_node *bodx, *body, *assignx, *assigny;
1686 slang_typeinfo type;
1687 int size;
1688
1689 assert(oper->type == SLANG_OPER_SELECT);
1690 assert(oper->num_children == 3);
1691
1692 /* size of x or y's type */
1693 slang_typeinfo_construct(&type);
1694 _slang_typeof_operation(A, &oper->children[1], &type);
1695 size = _slang_sizeof_type_specifier(&type.spec);
1696 assert(size > 0);
1697
1698 /* temporary var */
1699 tmpDecl = _slang_gen_temporary(size);
1700
1701 /* eval condition */
1702 cond = _slang_gen_operation(A, &oper->children[0]);
1703 cond = new_cond(cond);
1704 tree = new_seq(tmpDecl, cond);
1705
1706 /* jump if false to "alt" label */
1707 cjump = new_cjump(altAtom, 0);
1708 tree = new_seq(tree, cjump);
1709
1710 /* evaluate child 1 (x) and assign to tmp */
1711 tmpVar = new_node0(IR_VAR);
1712 tmpVar->Store = tmpDecl->Store;
1713 body = _slang_gen_operation(A, &oper->children[1]);
1714 assigny = new_node2(IR_MOVE, tmpVar, body);
1715 tree = new_seq(tree, assigny);
1716
1717 /* jump to "end" label */
1718 jump = new_jump(endAtom);
1719 tree = new_seq(tree, jump);
1720
1721 /* "alt" label */
1722 altLab = new_label(altAtom);
1723 tree = new_seq(tree, altLab);
1724
1725 /* evaluate child 2 (y) and assign to tmp */
1726 tmpVar = new_node0(IR_VAR);
1727 tmpVar->Store = tmpDecl->Store;
1728 bodx = _slang_gen_operation(A, &oper->children[2]);
1729 assignx = new_node2(IR_MOVE, tmpVar, bodx);
1730 tree = new_seq(tree, assignx);
1731
1732 /* "end" label */
1733 endLab = new_label(endAtom);
1734 tree = new_seq(tree, endLab);
1735
1736 /* tmp var value */
1737 tmpVar = new_node0(IR_VAR);
1738 tmpVar->Store = tmpDecl->Store;
1739 tree = new_seq(tree, tmpVar);
1740
1741 return tree;
1742 }
1743
1744
1745 /**
1746 * Generate code for &&.
1747 */
1748 static slang_ir_node *
1749 _slang_gen_logical_and(slang_assemble_ctx *A, slang_operation *oper)
1750 {
1751 /* rewrite "a && b" as "a ? b : false" */
1752 slang_operation *select;
1753 slang_ir_node *n;
1754
1755 select = slang_operation_new(1);
1756 select->type = SLANG_OPER_SELECT;
1757 select->num_children = 3;
1758 select->children = slang_operation_new(3);
1759
1760 slang_operation_copy(&select->children[0], &oper->children[0]);
1761 slang_operation_copy(&select->children[1], &oper->children[1]);
1762 select->children[2].type = SLANG_OPER_LITERAL_BOOL;
1763 ASSIGN_4V(select->children[2].literal, 0, 0, 0, 0);
1764 select->children[2].literal_size = 2;
1765
1766 n = _slang_gen_select(A, select);
1767
1768 /* xxx wrong */
1769 free(select->children);
1770 free(select);
1771
1772 return n;
1773 }
1774
1775
1776 /**
1777 * Generate code for ||.
1778 */
1779 static slang_ir_node *
1780 _slang_gen_logical_or(slang_assemble_ctx *A, slang_operation *oper)
1781 {
1782 /* rewrite "a || b" as "a ? true : b" */
1783 slang_operation *select;
1784 slang_ir_node *n;
1785
1786 select = slang_operation_new(1);
1787 select->type = SLANG_OPER_SELECT;
1788 select->num_children = 3;
1789 select->children = slang_operation_new(3);
1790
1791 slang_operation_copy(&select->children[0], &oper->children[0]);
1792 select->children[1].type = SLANG_OPER_LITERAL_BOOL;
1793 ASSIGN_4V(select->children[2].literal, 1, 1, 1, 1);
1794 slang_operation_copy(&select->children[2], &oper->children[1]);
1795 select->children[2].literal_size = 2;
1796
1797 n = _slang_gen_select(A, select);
1798
1799 /* xxx wrong */
1800 free(select->children);
1801 free(select);
1802
1803 return n;
1804 }
1805
1806
1807
1808 /**
1809 * Generate IR tree for a return statement.
1810 */
1811 static slang_ir_node *
1812 _slang_gen_return(slang_assemble_ctx * A, slang_operation *oper)
1813 {
1814 if (oper->num_children == 0 ||
1815 (oper->num_children == 1 &&
1816 oper->children[0].type == SLANG_OPER_VOID)) {
1817 /* Convert from:
1818 * return;
1819 * To:
1820 * goto __endOfFunction;
1821 */
1822 slang_ir_node *n;
1823 slang_operation gotoOp;
1824 slang_operation_construct(&gotoOp);
1825 gotoOp.type = SLANG_OPER_GOTO;
1826 /* XXX don't call function? */
1827 gotoOp.a_id = slang_atom_pool_atom(A->atoms,
1828 (char *) A->CurFunction->end_label);
1829 /* assemble the new code */
1830 n = _slang_gen_operation(A, &gotoOp);
1831 /* destroy temp code */
1832 slang_operation_destruct(&gotoOp);
1833 return n;
1834 }
1835 else {
1836 /*
1837 * Convert from:
1838 * return expr;
1839 * To:
1840 * __retVal = expr;
1841 * goto __endOfFunction;
1842 */
1843 slang_operation *block, *assign, *jump;
1844 slang_atom a_retVal;
1845 slang_ir_node *n;
1846
1847 a_retVal = slang_atom_pool_atom(A->atoms, "__retVal");
1848 assert(a_retVal);
1849
1850 #if 1 /* DEBUG */
1851 {
1852 slang_variable *v
1853 = _slang_locate_variable(oper->locals, a_retVal, GL_TRUE);
1854 assert(v);
1855 }
1856 #endif
1857
1858 block = slang_operation_new(1);
1859 block->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE;
1860 block->num_children = 2;
1861 block->children = slang_operation_new(2);
1862 assert(block->locals);
1863 block->locals->outer_scope = oper->locals->outer_scope;
1864
1865 /* child[0]: __retVal = expr; */
1866 assign = &block->children[0];
1867 assign->type = SLANG_OPER_ASSIGN;
1868 assign->locals->outer_scope = block->locals;
1869 assign->num_children = 2;
1870 assign->children = slang_operation_new(2);
1871 /* lhs (__retVal) */
1872 assign->children[0].type = SLANG_OPER_IDENTIFIER;
1873 assign->children[0].a_id = a_retVal;
1874 assign->children[0].locals->outer_scope = assign->locals;
1875 /* rhs (expr) */
1876 /* XXX we might be able to avoid this copy someday */
1877 slang_operation_copy(&assign->children[1], &oper->children[0]);
1878
1879 /* child[1]: goto __endOfFunction */
1880 jump = &block->children[1];
1881 jump->type = SLANG_OPER_GOTO;
1882 assert(A->CurFunction->end_label);
1883 /* XXX don't call function? */
1884 jump->a_id = slang_atom_pool_atom(A->atoms,
1885 (char *) A->CurFunction->end_label);
1886
1887 #if 0 /* debug */
1888 printf("NEW RETURN:\n");
1889 slang_print_tree(block, 0);
1890 #endif
1891
1892 /* assemble the new code */
1893 n = _slang_gen_operation(A, block);
1894 slang_operation_delete(block);
1895 return n;
1896 }
1897 }
1898
1899
1900 /**
1901 * Generate IR tree for a variable declaration.
1902 */
1903 static slang_ir_node *
1904 _slang_gen_declaration(slang_assemble_ctx *A, slang_operation *oper)
1905 {
1906 slang_ir_node *n;
1907 slang_ir_node *varDecl;
1908 slang_variable *v;
1909 const char *varName = (char *) oper->a_id;
1910
1911 assert(oper->num_children == 0 || oper->num_children == 1);
1912
1913 v = _slang_locate_variable(oper->locals, oper->a_id, GL_TRUE);
1914 assert(v);
1915
1916 varDecl = _slang_gen_var_decl(A, v);
1917
1918 if (oper->num_children > 0) {
1919 /* child is initializer */
1920 slang_ir_node *var, *init, *rhs;
1921 assert(oper->num_children == 1);
1922 var = new_var(A, oper, oper->a_id);
1923 if (!var) {
1924 RETURN_ERROR2("Undefined variable:", varName, 0);
1925 }
1926 /* XXX make copy of this initializer? */
1927 rhs = _slang_gen_operation(A, &oper->children[0]);
1928 assert(rhs);
1929 init = new_node2(IR_MOVE, var, rhs);
1930 /*assert(rhs->Opcode != IR_SEQ);*/
1931 n = new_seq(varDecl, init);
1932 }
1933 else if (v->initializer) {
1934 slang_ir_node *var, *init, *rhs;
1935 var = new_var(A, oper, oper->a_id);
1936 if (!var) {
1937 RETURN_ERROR2("Undefined variable:", varName, 0);
1938 }
1939 #if 0
1940 /* XXX make copy of this initializer? */
1941 {
1942 slang_operation dup;
1943 slang_operation_construct(&dup);
1944 slang_operation_copy(&dup, v->initializer);
1945 _slang_simplify(&dup, &A->space, A->atoms);
1946 rhs = _slang_gen_operation(A, &dup);
1947 }
1948 #else
1949 _slang_simplify(v->initializer, &A->space, A->atoms);
1950 rhs = _slang_gen_operation(A, v->initializer);
1951 #endif
1952 assert(rhs);
1953 init = new_node2(IR_MOVE, var, rhs);
1954 /*
1955 assert(rhs->Opcode != IR_SEQ);
1956 */
1957 n = new_seq(varDecl, init);
1958 }
1959 else {
1960 n = varDecl;
1961 }
1962 return n;
1963 }
1964
1965
1966 /**
1967 * Generate IR tree for a variable (such as in an expression).
1968 */
1969 static slang_ir_node *
1970 _slang_gen_variable(slang_assemble_ctx * A, slang_operation *oper)
1971 {
1972 /* If there's a variable associated with this oper (from inlining)
1973 * use it. Otherwise, use the oper's var id.
1974 */
1975 slang_atom aVar = oper->var ? oper->var->a_name : oper->a_id;
1976 slang_ir_node *n = new_var(A, oper, aVar);
1977 if (!n) {
1978 RETURN_ERROR2("Undefined variable:", (char *) aVar, 0);
1979 }
1980 return n;
1981 }
1982
1983
1984 /**
1985 * Some write-masked assignments are simple, but others are hard.
1986 * Simple example:
1987 * vec3 v;
1988 * v.xy = vec2(a, b);
1989 * Hard example:
1990 * vec3 v;
1991 * v.yz = vec2(a, b);
1992 * this would have to be transformed/swizzled into:
1993 * v.yz = vec2(a, b).*xy* (* = don't care)
1994 * Instead, we'll effectively do this:
1995 * v.y = vec2(a, b).xxxx;
1996 * v.z = vec2(a, b).yyyy;
1997 *
1998 */
1999 static GLboolean
2000 _slang_simple_writemask(GLuint writemask)
2001 {
2002 switch (writemask) {
2003 case WRITEMASK_X:
2004 case WRITEMASK_Y:
2005 case WRITEMASK_Z:
2006 case WRITEMASK_W:
2007 case WRITEMASK_XY:
2008 case WRITEMASK_XYZ:
2009 case WRITEMASK_XYZW:
2010 return GL_TRUE;
2011 default:
2012 return GL_FALSE;
2013 }
2014 }
2015
2016
2017 /**
2018 * Convert the given swizzle into a writemask. In some cases this
2019 * is trivial, in other cases, we'll need to also swizzle the right
2020 * hand side to put components in the right places.
2021 * \param swizzle the incoming swizzle
2022 * \param writemaskOut returns the writemask
2023 * \param swizzleOut swizzle to apply to the right-hand-side
2024 * \return GL_FALSE for simple writemasks, GL_TRUE for non-simple
2025 */
2026 static GLboolean
2027 swizzle_to_writemask(GLuint swizzle,
2028 GLuint *writemaskOut, GLuint *swizzleOut)
2029 {
2030 GLuint mask = 0x0, newSwizzle[4];
2031 GLint i, size;
2032
2033 /* make new dst writemask, compute size */
2034 for (i = 0; i < 4; i++) {
2035 const GLuint swz = GET_SWZ(swizzle, i);
2036 if (swz == SWIZZLE_NIL) {
2037 /* end */
2038 break;
2039 }
2040 assert(swz >= 0 && swz <= 3);
2041 mask |= (1 << swz);
2042 }
2043 assert(mask <= 0xf);
2044 size = i; /* number of components in mask/swizzle */
2045
2046 *writemaskOut = mask;
2047
2048 /* make new src swizzle, by inversion */
2049 for (i = 0; i < 4; i++) {
2050 newSwizzle[i] = i; /*identity*/
2051 }
2052 for (i = 0; i < size; i++) {
2053 const GLuint swz = GET_SWZ(swizzle, i);
2054 newSwizzle[swz] = i;
2055 }
2056 *swizzleOut = MAKE_SWIZZLE4(newSwizzle[0],
2057 newSwizzle[1],
2058 newSwizzle[2],
2059 newSwizzle[3]);
2060
2061 if (_slang_simple_writemask(mask)) {
2062 if (size >= 1)
2063 assert(GET_SWZ(*swizzleOut, 0) == SWIZZLE_X);
2064 if (size >= 2)
2065 assert(GET_SWZ(*swizzleOut, 1) == SWIZZLE_Y);
2066 if (size >= 3)
2067 assert(GET_SWZ(*swizzleOut, 2) == SWIZZLE_Z);
2068 if (size >= 4)
2069 assert(GET_SWZ(*swizzleOut, 3) == SWIZZLE_W);
2070 return GL_TRUE;
2071 }
2072 else
2073 return GL_FALSE;
2074 }
2075
2076
2077 static slang_ir_node *
2078 _slang_gen_swizzle(slang_ir_node *child, GLuint swizzle)
2079 {
2080 slang_ir_node *n = new_node1(IR_SWIZZLE, child);
2081 if (n) {
2082 n->Store = _slang_new_ir_storage(PROGRAM_UNDEFINED, -1, -1);
2083 n->Store->Swizzle = swizzle;
2084 }
2085 return n;
2086 }
2087
2088
2089 /**
2090 * Generate IR tree for an assignment (=).
2091 */
2092 static slang_ir_node *
2093 _slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper)
2094 {
2095 if (oper->children[0].type == SLANG_OPER_IDENTIFIER &&
2096 oper->children[1].type == SLANG_OPER_CALL) {
2097 /* Special case of: x = f(a, b)
2098 * Replace with f(a, b, x) (where x == hidden __retVal out param)
2099 *
2100 * XXX this could be even more effective if we could accomodate
2101 * cases such as "v.x = f();" - would help with typical vertex
2102 * transformation.
2103 */
2104 slang_ir_node *n;
2105 n = _slang_gen_function_call_name(A,
2106 (const char *) oper->children[1].a_id,
2107 &oper->children[1], &oper->children[0]);
2108 return n;
2109 }
2110 else {
2111 slang_ir_node *n, *lhs, *rhs;
2112 lhs = _slang_gen_operation(A, &oper->children[0]);
2113 rhs = _slang_gen_operation(A, &oper->children[1]);
2114 if (lhs && rhs) {
2115 /* convert lhs swizzle into writemask */
2116 GLuint writemask, newSwizzle;
2117 if (!swizzle_to_writemask(lhs->Store->Swizzle,
2118 &writemask, &newSwizzle)) {
2119 /* Non-simple writemask, need to swizzle right hand side in
2120 * order to put components into the right place.
2121 */
2122 rhs = _slang_gen_swizzle(rhs, newSwizzle);
2123 }
2124 n = new_node2(IR_MOVE, lhs, rhs);
2125 n->Writemask = writemask;
2126 return n;
2127 }
2128 else {
2129 return NULL;
2130 }
2131 }
2132 }
2133
2134
2135 /**
2136 * Generate IR tree for referencing a field in a struct (or basic vector type)
2137 */
2138 static slang_ir_node *
2139 _slang_gen_field(slang_assemble_ctx * A, slang_operation *oper)
2140 {
2141 slang_typeinfo ti;
2142
2143 slang_typeinfo_construct(&ti);
2144 _slang_typeof_operation(A, &oper->children[0], &ti);
2145
2146 if (_slang_type_is_vector(ti.spec.type)) {
2147 /* the field should be a swizzle */
2148 const GLuint rows = _slang_type_dim(ti.spec.type);
2149 slang_swizzle swz;
2150 slang_ir_node *n;
2151 GLuint swizzle;
2152 if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) {
2153 RETURN_ERROR("Bad swizzle", 0);
2154 }
2155 swizzle = MAKE_SWIZZLE4(swz.swizzle[0],
2156 swz.swizzle[1],
2157 swz.swizzle[2],
2158 swz.swizzle[3]);
2159
2160 n = _slang_gen_operation(A, &oper->children[0]);
2161 /* create new parent node with swizzle */
2162 n = _slang_gen_swizzle(n, swizzle);
2163 return n;
2164 }
2165 else if (ti.spec.type == SLANG_SPEC_FLOAT) {
2166 const GLuint rows = 1;
2167 slang_swizzle swz;
2168 slang_ir_node *n;
2169 GLuint swizzle;
2170 if (!_slang_is_swizzle((char *) oper->a_id, rows, &swz)) {
2171 RETURN_ERROR("Bad swizzle", 0);
2172 }
2173 swizzle = MAKE_SWIZZLE4(swz.swizzle[0],
2174 swz.swizzle[1],
2175 swz.swizzle[2],
2176 swz.swizzle[3]);
2177 n = _slang_gen_operation(A, &oper->children[0]);
2178 /* create new parent node with swizzle */
2179 n = _slang_gen_swizzle(n, swizzle);
2180 return n;
2181 }
2182 else {
2183 /* the field is a structure member (base.field) */
2184 /* oper->children[0] is the base */
2185 /* oper->a_id is the field name */
2186 slang_ir_node *base, *n;
2187
2188 base = _slang_gen_operation(A, &oper->children[0]);
2189
2190 n = new_node1(IR_FIELD, base);
2191 if (n) {
2192 n->Target = (char *) oper->a_id;
2193 }
2194 return n;
2195
2196 #if 0
2197 _mesa_problem(NULL, "glsl structs/fields not supported yet");
2198 return NULL;
2199 #endif
2200 }
2201 }
2202
2203
2204 /**
2205 * Gen code for array indexing.
2206 */
2207 static slang_ir_node *
2208 _slang_gen_subscript(slang_assemble_ctx * A, slang_operation *oper)
2209 {
2210 slang_typeinfo array_ti;
2211
2212 /* get array's type info */
2213 slang_typeinfo_construct(&array_ti);
2214 _slang_typeof_operation(A, &oper->children[0], &array_ti);
2215
2216 if (_slang_type_is_vector(array_ti.spec.type)) {
2217 /* indexing a simple vector type: "vec4 v; v[0]=p;" */
2218 /* translate the index into a swizzle/writemask: "v.x=p" */
2219 const GLuint max = _slang_type_dim(array_ti.spec.type);
2220 GLint index;
2221 slang_ir_node *n;
2222
2223 index = (GLint) oper->children[1].literal[0];
2224 if (oper->children[1].type != SLANG_OPER_LITERAL_INT ||
2225 index >= max) {
2226 RETURN_ERROR("Invalid array index for vector type", 0);
2227 }
2228
2229 n = _slang_gen_operation(A, &oper->children[0]);
2230 if (n) {
2231 /* use swizzle to access the element */
2232 GLuint swizzle = MAKE_SWIZZLE4(SWIZZLE_X + index,
2233 SWIZZLE_NIL,
2234 SWIZZLE_NIL,
2235 SWIZZLE_NIL);
2236 n = _slang_gen_swizzle(n, swizzle);
2237 /*n->Store = _slang_clone_ir_storage_swz(n->Store, */
2238 n->Writemask = WRITEMASK_X << index;
2239 }
2240 return n;
2241 }
2242 else {
2243 /* conventional array */
2244 slang_typeinfo elem_ti;
2245 slang_ir_node *elem, *array, *index;
2246 GLint elemSize;
2247
2248 /* size of array element */
2249 slang_typeinfo_construct(&elem_ti);
2250 _slang_typeof_operation(A, oper, &elem_ti);
2251 elemSize = _slang_sizeof_type_specifier(&elem_ti.spec);
2252 assert(elemSize >= 1);
2253
2254 array = _slang_gen_operation(A, &oper->children[0]);
2255 index = _slang_gen_operation(A, &oper->children[1]);
2256 if (array && index) {
2257 elem = new_node2(IR_ELEMENT, array, index);
2258 elem->Store = _slang_new_ir_storage(array->Store->File,
2259 array->Store->Index,
2260 elemSize);
2261 return elem;
2262 }
2263 else {
2264 return NULL;
2265 }
2266 }
2267 }
2268
2269
2270
2271 /**
2272 * Generate IR tree for a slang_operation (AST node)
2273 */
2274 static slang_ir_node *
2275 _slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper)
2276 {
2277 switch (oper->type) {
2278 case SLANG_OPER_BLOCK_NEW_SCOPE:
2279 {
2280 slang_ir_node *n;
2281
2282 _slang_push_var_table(A->vartable);
2283
2284 oper->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE; /* temp change */
2285 n = _slang_gen_operation(A, oper);
2286 oper->type = SLANG_OPER_BLOCK_NEW_SCOPE; /* restore */
2287
2288 _slang_pop_var_table(A->vartable);
2289
2290 if (n)
2291 n = new_node1(IR_SCOPE, n);
2292 return n;
2293 }
2294 break;
2295
2296 case SLANG_OPER_BLOCK_NO_NEW_SCOPE:
2297 /* list of operations */
2298 if (oper->num_children > 0)
2299 {
2300 slang_ir_node *n, *tree = NULL;
2301 GLuint i;
2302
2303 for (i = 0; i < oper->num_children; i++) {
2304 n = _slang_gen_operation(A, &oper->children[i]);
2305 if (!n) {
2306 _slang_free_ir_tree(tree);
2307 return NULL; /* error must have occured */
2308 }
2309 tree = tree ? new_seq(tree, n) : n;
2310 }
2311
2312 #if 00
2313 if (oper->locals->num_variables > 0) {
2314 int i;
2315 /*
2316 printf("\n****** Deallocate vars in scope!\n");
2317 */
2318 for (i = 0; i < oper->locals->num_variables; i++) {
2319 slang_variable *v = oper->locals->variables + i;
2320 if (v->aux) {
2321 slang_ir_storage *store = (slang_ir_storage *) v->aux;
2322 /*
2323 printf(" Deallocate var %s\n", (char*) v->a_name);
2324 */
2325 assert(store->File == PROGRAM_TEMPORARY);
2326 assert(store->Index >= 0);
2327 _slang_free_temp(A->vartable, store->Index, store->Size);
2328 }
2329 }
2330 }
2331 #endif
2332 return tree;
2333 }
2334 break;
2335 case SLANG_OPER_EXPRESSION:
2336 return _slang_gen_operation(A, &oper->children[0]);
2337
2338 case SLANG_OPER_FOR:
2339 return _slang_gen_for(A, oper);
2340 case SLANG_OPER_DO:
2341 return _slang_gen_do(A, oper);
2342 case SLANG_OPER_WHILE:
2343 return _slang_gen_while(A, oper);
2344 case SLANG_OPER_BREAK:
2345 if (!A->CurLoop) {
2346 RETURN_ERROR("'break' not in loop", 0);
2347 }
2348 return new_break(A->CurLoop);
2349 case SLANG_OPER_CONTINUE:
2350 if (!A->CurLoop) {
2351 RETURN_ERROR("'continue' not in loop", 0);
2352 }
2353 return new_cont(A->CurLoop);
2354 case SLANG_OPER_DISCARD:
2355 return new_node0(IR_KILL);
2356
2357 case SLANG_OPER_EQUAL:
2358 return new_node2(IR_SEQUAL,
2359 _slang_gen_operation(A, &oper->children[0]),
2360 _slang_gen_operation(A, &oper->children[1]));
2361 case SLANG_OPER_NOTEQUAL:
2362 return new_node2(IR_SNEQUAL,
2363 _slang_gen_operation(A, &oper->children[0]),
2364 _slang_gen_operation(A, &oper->children[1]));
2365 case SLANG_OPER_GREATER:
2366 return new_node2(IR_SGT,
2367 _slang_gen_operation(A, &oper->children[0]),
2368 _slang_gen_operation(A, &oper->children[1]));
2369 case SLANG_OPER_LESS:
2370 /* child[0] < child[1] ----> child[1] > child[0] */
2371 return new_node2(IR_SGT,
2372 _slang_gen_operation(A, &oper->children[1]),
2373 _slang_gen_operation(A, &oper->children[0]));
2374 case SLANG_OPER_GREATERequal:
2375 return new_node2(IR_SGE,
2376 _slang_gen_operation(A, &oper->children[0]),
2377 _slang_gen_operation(A, &oper->children[1]));
2378 case SLANG_OPER_LESSequal:
2379 /* child[0] <= child[1] ----> child[1] >= child[0] */
2380 return new_node2(IR_SGE,
2381 _slang_gen_operation(A, &oper->children[1]),
2382 _slang_gen_operation(A, &oper->children[0]));
2383 case SLANG_OPER_ADD:
2384 {
2385 slang_ir_node *n;
2386 assert(oper->num_children == 2);
2387 n = _slang_gen_function_call_name(A, "+", oper, NULL);
2388 return n;
2389 }
2390 case SLANG_OPER_SUBTRACT:
2391 {
2392 slang_ir_node *n;
2393 assert(oper->num_children == 2);
2394 n = _slang_gen_function_call_name(A, "-", oper, NULL);
2395 return n;
2396 }
2397 case SLANG_OPER_MULTIPLY:
2398 {
2399 slang_ir_node *n;
2400 assert(oper->num_children == 2);
2401 n = _slang_gen_function_call_name(A, "*", oper, NULL);
2402 return n;
2403 }
2404 case SLANG_OPER_DIVIDE:
2405 {
2406 slang_ir_node *n;
2407 assert(oper->num_children == 2);
2408 n = _slang_gen_function_call_name(A, "/", oper, NULL);
2409 return n;
2410 }
2411 case SLANG_OPER_MINUS:
2412 {
2413 slang_ir_node *n;
2414 assert(oper->num_children == 1);
2415 n = _slang_gen_function_call_name(A, "-", oper, NULL);
2416 return n;
2417 }
2418 case SLANG_OPER_PLUS:
2419 /* +expr --> do nothing */
2420 return _slang_gen_operation(A, &oper->children[0]);
2421 case SLANG_OPER_VARIABLE_DECL:
2422 return _slang_gen_declaration(A, oper);
2423 case SLANG_OPER_ASSIGN:
2424 return _slang_gen_assignment(A, oper);
2425 case SLANG_OPER_ADDASSIGN:
2426 {
2427 slang_ir_node *n;
2428 assert(oper->num_children == 2);
2429 n = _slang_gen_function_call_name(A, "+=", oper, &oper->children[0]);
2430 return n;
2431 }
2432 case SLANG_OPER_SUBASSIGN:
2433 {
2434 slang_ir_node *n;
2435 assert(oper->num_children == 2);
2436 n = _slang_gen_function_call_name(A, "-=", oper, &oper->children[0]);
2437 return n;
2438 }
2439 break;
2440 case SLANG_OPER_MULASSIGN:
2441 {
2442 slang_ir_node *n;
2443 assert(oper->num_children == 2);
2444 n = _slang_gen_function_call_name(A, "*=", oper, &oper->children[0]);
2445 return n;
2446 }
2447 case SLANG_OPER_DIVASSIGN:
2448 {
2449 slang_ir_node *n;
2450 assert(oper->num_children == 2);
2451 n = _slang_gen_function_call_name(A, "/=", oper, &oper->children[0]);
2452 return n;
2453 }
2454 case SLANG_OPER_LOGICALAND:
2455 {
2456 slang_ir_node *n;
2457 assert(oper->num_children == 2);
2458 n = _slang_gen_logical_and(A, oper);
2459 return n;
2460 }
2461 case SLANG_OPER_LOGICALOR:
2462 {
2463 slang_ir_node *n;
2464 assert(oper->num_children == 2);
2465 n = _slang_gen_logical_or(A, oper);
2466 return n;
2467 }
2468 case SLANG_OPER_LOGICALXOR:
2469 {
2470 slang_ir_node *n;
2471 assert(oper->num_children == 2);
2472 n = _slang_gen_function_call_name(A, "__logicalXor", oper, NULL);
2473 return n;
2474 }
2475 case SLANG_OPER_NOT:
2476 {
2477 slang_ir_node *n;
2478 assert(oper->num_children == 1);
2479 n = _slang_gen_function_call_name(A, "__logicalNot", oper, NULL);
2480 return n;
2481 }
2482
2483 case SLANG_OPER_SELECT: /* b ? x : y */
2484 {
2485 slang_ir_node *n;
2486 assert(oper->num_children == 3);
2487 n = _slang_gen_select(A, oper);
2488 return n;
2489 }
2490
2491 case SLANG_OPER_ASM:
2492 return _slang_gen_asm(A, oper, NULL);
2493 case SLANG_OPER_CALL:
2494 return _slang_gen_function_call_name(A, (const char *) oper->a_id,
2495 oper, NULL);
2496 case SLANG_OPER_RETURN:
2497 return _slang_gen_return(A, oper);
2498 case SLANG_OPER_GOTO:
2499 return new_jump((char*) oper->a_id);
2500 case SLANG_OPER_LABEL:
2501 return new_label((char*) oper->a_id);
2502 case SLANG_OPER_IDENTIFIER:
2503 return _slang_gen_variable(A, oper);
2504 case SLANG_OPER_IF:
2505 if (A->program->Target == GL_FRAGMENT_PROGRAM_ARB) {
2506 return _slang_gen_hl_if(A, oper);
2507 }
2508 else {
2509 /* XXX update tnl executor */
2510 return _slang_gen_if(A, oper);
2511 }
2512 case SLANG_OPER_FIELD:
2513 return _slang_gen_field(A, oper);
2514 case SLANG_OPER_SUBSCRIPT:
2515 return _slang_gen_subscript(A, oper);
2516 case SLANG_OPER_LITERAL_FLOAT:
2517 /* fall-through */
2518 case SLANG_OPER_LITERAL_INT:
2519 /* fall-through */
2520 case SLANG_OPER_LITERAL_BOOL:
2521 return new_float_literal(oper->literal);
2522
2523 case SLANG_OPER_POSTINCREMENT: /* var++ */
2524 {
2525 slang_ir_node *n;
2526 assert(oper->num_children == 1);
2527 n = _slang_gen_function_call_name(A, "__postIncr", oper, NULL);
2528 return n;
2529 }
2530 case SLANG_OPER_POSTDECREMENT: /* var-- */
2531 {
2532 slang_ir_node *n;
2533 assert(oper->num_children == 1);
2534 n = _slang_gen_function_call_name(A, "__postDecr", oper, NULL);
2535 return n;
2536 }
2537 case SLANG_OPER_PREINCREMENT: /* ++var */
2538 {
2539 slang_ir_node *n;
2540 assert(oper->num_children == 1);
2541 n = _slang_gen_function_call_name(A, "++", oper, NULL);
2542 return n;
2543 }
2544 case SLANG_OPER_PREDECREMENT: /* --var */
2545 {
2546 slang_ir_node *n;
2547 assert(oper->num_children == 1);
2548 n = _slang_gen_function_call_name(A, "--", oper, NULL);
2549 return n;
2550 }
2551
2552 case SLANG_OPER_SEQUENCE:
2553 {
2554 slang_ir_node *tree = NULL;
2555 GLuint i;
2556 for (i = 0; i < oper->num_children; i++) {
2557 slang_ir_node *n = _slang_gen_operation(A, &oper->children[i]);
2558 tree = tree ? new_seq(tree, n) : n;
2559 }
2560 return tree;
2561 }
2562
2563 case SLANG_OPER_NONE:
2564 return NULL;
2565 case SLANG_OPER_VOID:
2566 return NULL;
2567
2568 default:
2569 printf("Unhandled node type %d\n", oper->type);
2570 abort();
2571 return new_node0(IR_NOP);
2572 }
2573 abort();
2574 return NULL;
2575 }
2576
2577
2578
2579 /**
2580 * Called by compiler when a global variable has been parsed/compiled.
2581 * Here we examine the variable's type to determine what kind of register
2582 * storage will be used.
2583 *
2584 * A uniform such as "gl_Position" will become the register specification
2585 * (PROGRAM_OUTPUT, VERT_RESULT_HPOS). Or, uniform "gl_FogFragCoord"
2586 * will be (PROGRAM_INPUT, FRAG_ATTRIB_FOGC).
2587 *
2588 * Samplers are interesting. For "uniform sampler2D tex;" we'll specify
2589 * (PROGRAM_SAMPLER, index) where index is resolved at link-time to an
2590 * actual texture unit (as specified by the user calling glUniform1i()).
2591 */
2592 GLboolean
2593 _slang_codegen_global_variable(slang_assemble_ctx *A, slang_variable *var,
2594 slang_unit_type type)
2595 {
2596 struct gl_program *prog = A->program;
2597 const char *varName = (char *) var->a_name;
2598 GLboolean success = GL_TRUE;
2599 GLint texIndex;
2600 slang_ir_storage *store = NULL;
2601 int dbg = 1;
2602
2603 texIndex = sampler_to_texture_index(var->type.specifier.type);
2604
2605 if (texIndex != -1) {
2606 /* Texture sampler:
2607 * store->File = PROGRAM_SAMPLER
2608 * store->Index = sampler uniform location
2609 * store->Size = texture type index (1D, 2D, 3D, cube, etc)
2610 */
2611 GLint samplerUniform = _mesa_add_sampler(prog->Parameters, varName);
2612 store = _slang_new_ir_storage(PROGRAM_SAMPLER, samplerUniform, texIndex);
2613 if (dbg) printf("SAMPLER ");
2614 }
2615 else if (var->type.qualifier == SLANG_QUAL_UNIFORM) {
2616 /* Uniform variable */
2617 const GLint size = _slang_sizeof_type_specifier(&var->type.specifier)
2618 * MAX2(var->array_len, 1);
2619 if (prog) {
2620 /* user-defined uniform */
2621 GLint uniformLoc = _mesa_add_uniform(prog->Parameters, varName, size);
2622 store = _slang_new_ir_storage(PROGRAM_UNIFORM, uniformLoc, size);
2623 }
2624 else {
2625 /* pre-defined uniform, like gl_ModelviewMatrix */
2626 /* We know it's a uniform, but don't allocate storage unless
2627 * it's really used.
2628 */
2629 store = _slang_new_ir_storage(PROGRAM_STATE_VAR, -1, size);
2630 }
2631 if (dbg) printf("UNIFORM (sz %d) ", size);
2632 }
2633 else if (var->type.qualifier == SLANG_QUAL_VARYING) {
2634 const GLint size = 4; /* XXX fix */
2635 if (prog) {
2636 /* user-defined varying */
2637 GLint varyingLoc = _mesa_add_varying(prog->Varying, varName, size);
2638 store = _slang_new_ir_storage(PROGRAM_VARYING, varyingLoc, size);
2639 }
2640 else {
2641 /* pre-defined varying, like gl_Color or gl_TexCoord */
2642 if (type == SLANG_UNIT_FRAGMENT_BUILTIN) {
2643 GLint index = _slang_input_index(varName, GL_FRAGMENT_PROGRAM_ARB);
2644 assert(index >= 0);
2645 store = _slang_new_ir_storage(PROGRAM_INPUT, index, size);
2646 assert(index < FRAG_ATTRIB_MAX);
2647 }
2648 else {
2649 GLint index = _slang_output_index(varName, GL_VERTEX_PROGRAM_ARB);
2650 assert(index >= 0);
2651 assert(type == SLANG_UNIT_VERTEX_BUILTIN);
2652 store = _slang_new_ir_storage(PROGRAM_OUTPUT, index, size);
2653 assert(index < VERT_RESULT_MAX);
2654 }
2655 if (dbg) printf("V/F ");
2656 }
2657 if (dbg) printf("VARYING ");
2658 }
2659 else if (var->type.qualifier == SLANG_QUAL_ATTRIBUTE) {
2660 if (prog) {
2661 /* user-defined vertex attribute */
2662 const GLint size = _slang_sizeof_type_specifier(&var->type.specifier);
2663 const GLint attr = -1; /* unknown */
2664 GLint index = _mesa_add_attribute(prog->Attributes, varName,
2665 size, attr);
2666 assert(index >= 0);
2667 store = _slang_new_ir_storage(PROGRAM_INPUT,
2668 VERT_ATTRIB_GENERIC0 + index, size);
2669 }
2670 else {
2671 /* pre-defined vertex attrib */
2672 GLint index = _slang_input_index(varName, GL_VERTEX_PROGRAM_ARB);
2673 GLint size = 4; /* XXX? */
2674 assert(index >= 0);
2675 store = _slang_new_ir_storage(PROGRAM_INPUT, index, size);
2676 }
2677 if (dbg) printf("ATTRIB ");
2678 }
2679 else if (var->type.qualifier == SLANG_QUAL_FIXEDINPUT) {
2680 GLint index = _slang_input_index(varName, GL_FRAGMENT_PROGRAM_ARB);
2681 GLint size = 4; /* XXX? */
2682 store = _slang_new_ir_storage(PROGRAM_INPUT, index, size);
2683 if (dbg) printf("INPUT ");
2684 }
2685 else if (var->type.qualifier == SLANG_QUAL_FIXEDOUTPUT) {
2686 if (type == SLANG_UNIT_VERTEX_BUILTIN) {
2687 GLint index = _slang_output_index(varName, GL_VERTEX_PROGRAM_ARB);
2688 GLint size = 4; /* XXX? */
2689 store = _slang_new_ir_storage(PROGRAM_OUTPUT, index, size);
2690 }
2691 else {
2692 assert(type == SLANG_UNIT_FRAGMENT_BUILTIN);
2693 GLint index = _slang_output_index(varName, GL_FRAGMENT_PROGRAM_ARB);
2694 GLint size = 4; /* XXX? */
2695 store = _slang_new_ir_storage(PROGRAM_OUTPUT, index, size);
2696 }
2697 if (dbg) printf("OUTPUT ");
2698 }
2699 else if (var->type.qualifier == SLANG_QUAL_CONST && !prog) {
2700 /* pre-defined global constant, like gl_MaxLights */
2701 const GLint size = _slang_sizeof_type_specifier(&var->type.specifier);
2702 store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, size);
2703 if (dbg) printf("CONST ");
2704 }
2705 else {
2706 /* ordinary variable (may be const) */
2707 slang_ir_node *n;
2708
2709 /* IR node to declare the variable */
2710 n = _slang_gen_var_decl(A, var);
2711
2712 /* IR code for the var's initializer, if present */
2713 if (var->initializer) {
2714 slang_ir_node *lhs, *rhs, *init;
2715
2716 /* Generate IR_MOVE instruction to initialize the variable */
2717 lhs = new_node0(IR_VAR);
2718 lhs->Var = var;
2719 lhs->Store = n->Store;
2720
2721 /* constant folding, etc */
2722 _slang_simplify(var->initializer, &A->space, A->atoms);
2723
2724 rhs = _slang_gen_operation(A, var->initializer);
2725 assert(rhs);
2726 init = new_node2(IR_MOVE, lhs, rhs);
2727 n = new_seq(n, init);
2728 }
2729
2730 success = _slang_emit_code(n, A->vartable, A->program, GL_FALSE);
2731
2732 _slang_free_ir_tree(n);
2733 }
2734
2735 if (dbg) printf("GLOBAL VAR %s idx %d\n", (char*) var->a_name,
2736 store ? store->Index : -2);
2737
2738 if (store)
2739 var->aux = store; /* save var's storage info */
2740
2741 return success;
2742 }
2743
2744
2745 /**
2746 * Produce an IR tree from a function AST (fun->body).
2747 * Then call the code emitter to convert the IR tree into gl_program
2748 * instructions.
2749 */
2750 GLboolean
2751 _slang_codegen_function(slang_assemble_ctx * A, slang_function * fun)
2752 {
2753 slang_ir_node *n, *endLabel;
2754 GLboolean success = GL_TRUE;
2755
2756 if (_mesa_strcmp((char *) fun->header.a_name, "main") != 0) {
2757 /* we only really generate code for main, all other functions get
2758 * inlined.
2759 */
2760 return GL_TRUE; /* not an error */
2761 }
2762
2763 #if 1
2764 printf("\n*********** codegen_function %s\n", (char *) fun->header.a_name);
2765 #endif
2766 #if 0
2767 slang_print_function(fun, 1);
2768 #endif
2769
2770 /* should have been allocated earlier: */
2771 assert(A->program->Parameters );
2772 assert(A->program->Varying);
2773 assert(A->vartable);
2774
2775 /* fold constant expressions, etc. */
2776 _slang_simplify(fun->body, &A->space, A->atoms);
2777
2778 A->CurFunction = fun;
2779
2780 /* Create an end-of-function label */
2781 if (!A->CurFunction->end_label)
2782 A->CurFunction->end_label = slang_atom_pool_gen(A->atoms, "__endOfFunc_main_");
2783
2784 /* push new vartable scope */
2785 _slang_push_var_table(A->vartable);
2786
2787 /* Generate IR tree for the function body code */
2788 n = _slang_gen_operation(A, fun->body);
2789 if (n)
2790 n = new_node1(IR_SCOPE, n);
2791
2792 /* pop vartable, restore previous */
2793 _slang_pop_var_table(A->vartable);
2794
2795 if (!n) {
2796 /* XXX record error */
2797 return GL_FALSE;
2798 }
2799
2800 /* append an end-of-function-label to IR tree */
2801 endLabel = new_label(fun->end_label);
2802 n = new_seq(n, endLabel);
2803
2804 A->CurFunction = NULL;
2805
2806 #if 0
2807 printf("************* New AST for %s *****\n", (char*)fun->header.a_name);
2808 slang_print_function(fun, 1);
2809 #endif
2810 #if 0
2811 printf("************* IR for %s *******\n", (char*)fun->header.a_name);
2812 slang_print_ir(n, 0);
2813 #endif
2814 #if 1
2815 printf("************* End codegen function ************\n\n");
2816 #endif
2817
2818 /* Emit program instructions */
2819 success = _slang_emit_code(n, A->vartable, A->program, GL_TRUE);
2820 _slang_free_ir_tree(n);
2821
2822 /* free codegen context */
2823 /*
2824 _mesa_free(A->codegen);
2825 */
2826
2827 return success;
2828 }
2829