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