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