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