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