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