code movement
[mesa.git] / src / mesa / shader / slang / slang_emit.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_emit.c
27 * Emit program instructions (PI code) from IR trees.
28 * \author Brian Paul
29 */
30
31 #include "imports.h"
32 #include "context.h"
33 #include "get.h"
34 #include "macros.h"
35 #include "program.h"
36 #include "prog_instruction.h"
37 #include "prog_parameter.h"
38 #include "prog_statevars.h"
39 #include "slang_emit.h"
40
41
42 /**
43 * Assembly and IR info
44 */
45 typedef struct
46 {
47 slang_ir_opcode IrOpcode;
48 const char *IrName;
49 gl_inst_opcode InstOpcode;
50 GLuint ResultSize, NumParams;
51 } slang_ir_info;
52
53
54
55 static slang_ir_info IrInfo[] = {
56 /* binary ops */
57 { IR_ADD, "IR_ADD", OPCODE_ADD, 4, 2 },
58 { IR_SUB, "IR_SUB", OPCODE_SUB, 4, 2 },
59 { IR_MUL, "IR_MUL", OPCODE_MUL, 4, 2 },
60 { IR_DIV, "IR_DIV", OPCODE_NOP, 0, 2 }, /* XXX broke */
61 { IR_DOT4, "IR_DOT_4", OPCODE_DP4, 1, 2 },
62 { IR_DOT3, "IR_DOT_3", OPCODE_DP3, 1, 2 },
63 { IR_CROSS, "IR_CROSS", OPCODE_XPD, 3, 2 },
64 { IR_MIN, "IR_MIN", OPCODE_MIN, 4, 2 },
65 { IR_MAX, "IR_MAX", OPCODE_MAX, 4, 2 },
66 { IR_SEQUAL, "IR_SEQUAL", OPCODE_SEQ, 4, 2 },
67 { IR_SNEQUAL, "IR_SNEQUAL", OPCODE_SNE, 4, 2 },
68 { IR_SGE, "IR_SGE", OPCODE_SGE, 4, 2 },
69 { IR_SGT, "IR_SGT", OPCODE_SGT, 4, 2 },
70 { IR_POW, "IR_POW", OPCODE_POW, 1, 2 },
71 /* unary ops */
72 { IR_I_TO_F, "IR_I_TO_F", OPCODE_NOP, 1, 1 },
73 { IR_EXP, "IR_EXP", OPCODE_EXP, 1, 1 },
74 { IR_EXP2, "IR_EXP2", OPCODE_EX2, 1, 1 },
75 { IR_LOG2, "IR_LOG2", OPCODE_LG2, 1, 1 },
76 { IR_RSQ, "IR_RSQ", OPCODE_RSQ, 1, 1 },
77 { IR_RCP, "IR_RCP", OPCODE_RCP, 1, 1 },
78 { IR_FLOOR, "IR_FLOOR", OPCODE_FLR, 4, 1 },
79 { IR_FRAC, "IR_FRAC", OPCODE_FRC, 4, 1 },
80 { IR_ABS, "IR_ABS", OPCODE_ABS, 4, 1 },
81 { IR_SIN, "IR_SIN", OPCODE_SIN, 1, 1 },
82 { IR_COS, "IR_COS", OPCODE_COS, 1, 1 },
83 /* other */
84 { IR_SEQ, "IR_SEQ", 0, 0, 0 },
85 { IR_LABEL, "IR_LABEL", 0, 0, 0 },
86 { IR_JUMP, "IR_JUMP", 0, 0, 0 },
87 { IR_CJUMP, "IR_CJUMP", 0, 0, 0 },
88 { IR_CALL, "IR_CALL", 0, 0, 0 },
89 { IR_MOVE, "IR_MOVE", 0, 0, 1 },
90 { IR_LESS, "IR_LESS", 0, 1, 2 },
91 { IR_NOT, "IR_NOT", 0, 1, 1 },
92 { IR_VAR, "IR_VAR", 0, 0, 0 },
93 { IR_VAR_DECL, "IR_VAR_DECL", 0, 0, 0 },
94 { IR_FLOAT, "IR_FLOAT", 0, 0, 0 },
95 { IR_FIELD, "IR_FIELD", 0, 0, 0 },
96 { IR_NOP, NULL, OPCODE_NOP, 0, 0 }
97 };
98
99
100 static slang_ir_info *
101 slang_find_ir_info(slang_ir_opcode opcode)
102 {
103 GLuint i;
104 for (i = 0; IrInfo[i].IrName; i++) {
105 if (IrInfo[i].IrOpcode == opcode) {
106 return IrInfo + i;
107 }
108 }
109 return NULL;
110 }
111
112 static const char *
113 slang_ir_name(slang_ir_opcode opcode)
114 {
115 return slang_find_ir_info(opcode)->IrName;
116 }
117
118
119 slang_ir_storage *
120 _slang_new_ir_storage(enum register_file file, GLint index, GLint size)
121 {
122 slang_ir_storage *st;
123 st = (slang_ir_storage *) _mesa_calloc(sizeof(slang_ir_storage));
124 if (st) {
125 st->File = file;
126 st->Index = index;
127 st->Size = size;
128 }
129 return st;
130 }
131
132
133 slang_ir_storage *
134 _slang_clone_ir_storage(slang_ir_storage *store)
135 {
136 slang_ir_storage *clone
137 = _slang_new_ir_storage(store->File, store->Index, store->Size);
138 return clone;
139 }
140
141
142 static const char *
143 swizzle_string(GLuint swizzle)
144 {
145 static char s[6];
146 GLuint i;
147 s[0] = '.';
148 for (i = 1; i < 5; i++) {
149 s[i] = "xyzw"[GET_SWZ(swizzle, i-1)];
150 }
151 s[i] = 0;
152 return s;
153 }
154
155 static const char *
156 writemask_string(GLuint writemask)
157 {
158 static char s[6];
159 GLuint i, j = 0;
160 s[j++] = '.';
161 for (i = 0; i < 4; i++) {
162 if (writemask & (1 << i))
163 s[j++] = "xyzw"[i];
164 }
165 s[j] = 0;
166 return s;
167 }
168
169 static const char *
170 storage_string(const slang_ir_storage *st)
171 {
172 static const char *files[] = {
173 "TEMP",
174 "LOCAL_PARAM",
175 "ENV_PARAM",
176 "STATE",
177 "INPUT",
178 "OUTPUT",
179 "NAMED_PARAM",
180 "CONSTANT",
181 "UNIFORM",
182 "WRITE_ONLY",
183 "ADDRESS",
184 "UNDEFINED"
185 };
186 static char s[100];
187 #if 0
188 if (st->Size == 1)
189 sprintf(s, "%s[%d]", files[st->File], st->Index);
190 else
191 sprintf(s, "%s[%d..%d]", files[st->File], st->Index,
192 st->Index + st->Size - 1);
193 #endif
194 sprintf(s, "%s", files[st->File]);
195 return s;
196 }
197
198
199 static GLuint
200 sizeof_struct(const slang_struct *s)
201 {
202 return 0;
203 }
204
205
206 GLuint
207 _slang_sizeof_type_specifier(const slang_type_specifier *spec)
208 {
209 switch (spec->type) {
210 case slang_spec_void:
211 abort();
212 return 0;
213 case slang_spec_bool:
214 return 1;
215 case slang_spec_bvec2:
216 return 2;
217 case slang_spec_bvec3:
218 return 3;
219 case slang_spec_bvec4:
220 return 4;
221 case slang_spec_int:
222 return 1;
223 case slang_spec_ivec2:
224 return 2;
225 case slang_spec_ivec3:
226 return 3;
227 case slang_spec_ivec4:
228 return 4;
229 case slang_spec_float:
230 return 1;
231 case slang_spec_vec2:
232 return 2;
233 case slang_spec_vec3:
234 return 3;
235 case slang_spec_vec4:
236 return 4;
237 case slang_spec_mat2:
238 return 2 * 2;
239 case slang_spec_mat3:
240 return 3 * 3;
241 case slang_spec_mat4:
242 return 4 * 4;
243 case slang_spec_sampler1D:
244 case slang_spec_sampler2D:
245 case slang_spec_sampler3D:
246 case slang_spec_samplerCube:
247 case slang_spec_sampler1DShadow:
248 case slang_spec_sampler2DShadow:
249 abort();
250 return 0;
251 case slang_spec_struct:
252 return sizeof_struct(spec->_struct);
253 case slang_spec_array:
254 return 1; /* XXX */
255 default:
256 abort();
257 return 0;
258 }
259 return 0;
260 }
261
262
263
264 static GLuint
265 sizeof_type(const slang_fully_specified_type *t)
266 {
267 return _slang_sizeof_type_specifier(&t->specifier);
268 }
269
270
271 #define IND 0
272 void
273 slang_print_ir(const slang_ir_node *n, int indent)
274 {
275 int i;
276 if (!n)
277 return;
278 #if !IND
279 if (n->Opcode != IR_SEQ)
280 #else
281 printf("%3d:", indent);
282 #endif
283 for (i = 0; i < indent; i++)
284 printf(" ");
285
286 switch (n->Opcode) {
287 case IR_SEQ:
288 #if IND
289 printf("SEQ at %p\n", (void*) n);
290 #endif
291 assert(n->Children[0]);
292 assert(n->Children[1]);
293 slang_print_ir(n->Children[0], indent + IND);
294 slang_print_ir(n->Children[1], indent + IND);
295 break;
296 case IR_MOVE:
297 printf("MOVE (writemask = %s)\n", writemask_string(n->Writemask));
298 slang_print_ir(n->Children[0], indent+3);
299 slang_print_ir(n->Children[1], indent+3);
300 break;
301 case IR_LABEL:
302 printf("LABEL: %s\n", n->Target);
303 break;
304 case IR_JUMP:
305 printf("JUMP %s\n", n->Target);
306 break;
307 case IR_CJUMP:
308 printf("CJUMP %s\n", n->Target);
309 slang_print_ir(n->Children[0], indent+3);
310 break;
311 case IR_VAR:
312 printf("VAR %s%s at %s store %p\n",
313 (char *) n->Var->a_name, swizzle_string(n->Swizzle),
314 storage_string(n->Store), (void*) n->Store);
315 break;
316 case IR_VAR_DECL:
317 printf("VAR_DECL %s (%p) at %s store %p\n",
318 (char *) n->Var->a_name, (void*) n->Var, storage_string(n->Store),
319 (void*) n->Store);
320 break;
321 case IR_FIELD:
322 printf("FIELD %s of\n", n->Target);
323 slang_print_ir(n->Children[0], indent+3);
324 break;
325 case IR_CALL:
326 printf("ASMCALL %s(%d args)\n", n->Target, n->Swizzle);
327 break;
328 case IR_FLOAT:
329 printf("FLOAT %f %f %f %f\n",
330 n->Value[0], n->Value[1], n->Value[2], n->Value[3]);
331 break;
332 case IR_I_TO_F:
333 printf("INT_TO_FLOAT %d\n", (int) n->Value[0]);
334 break;
335 default:
336 printf("%s (%p, %p)\n", slang_ir_name(n->Opcode),
337 (void*) n->Children[0], (void*) n->Children[1]);
338 slang_print_ir(n->Children[0], indent+3);
339 slang_print_ir(n->Children[1], indent+3);
340 }
341 }
342
343
344 static GLint
345 alloc_temporary(slang_gen_context *gc, GLint size)
346 {
347 const GLuint sz4 = (size + 3) / 4;
348 GLuint i, j;
349 ASSERT(size > 0); /* number of floats */
350 for (i = 0; i < MAX_PROGRAM_TEMPS; i++) {
351 GLuint found = 0;
352 for (j = 0; j < sz4; j++) {
353 if (!gc->TempUsed[i + j]) {
354 found++;
355 }
356 }
357 if (found == sz4) {
358 /* found block of size/4 free regs */
359 for (j = 0; j < sz4; j++)
360 gc->TempUsed[i + j] = GL_TRUE;
361 return i;
362 }
363 }
364 return -1;
365 }
366
367
368 static GLboolean
369 is_temporary(const slang_gen_context *gc, const slang_ir_storage *st)
370 {
371 if (st->File == PROGRAM_TEMPORARY && gc->TempUsed[st->Index])
372 return gc->TempUsed[st->Index];
373 else
374 return GL_FALSE;
375 }
376
377
378 static void
379 free_temporary(slang_gen_context *gc, GLuint r, GLint size)
380 {
381 const GLuint sz4 = (size + 3) / 4;
382 GLuint i;
383 for (i = 0; i < sz4; i++) {
384 if (gc->TempUsed[r + i])
385 gc->TempUsed[r + i] = GL_FALSE;
386 }
387 }
388
389
390
391 static GLint
392 slang_find_input(GLenum target, const char *name, GLint index)
393 {
394 struct input_info {
395 const char *Name;
396 GLuint Attrib;
397 };
398 static const struct input_info vertInputs[] = {
399 { "gl_Vertex", VERT_ATTRIB_POS },
400 { "gl_Normal", VERT_ATTRIB_NORMAL },
401 { "gl_Color", VERT_ATTRIB_COLOR0 },
402 { "gl_SecondaryColor", VERT_ATTRIB_COLOR1 },
403 { NULL, 0 }
404 };
405 static const struct input_info fragInputs[] = {
406 { NULL, 0 }
407 };
408 const struct input_info *inputs;
409 GLuint i;
410
411 if (target == GL_VERTEX_PROGRAM_ARB) {
412 inputs = vertInputs;
413 }
414 else {
415 assert(target == GL_FRAGMENT_PROGRAM_ARB);
416 inputs = fragInputs;
417 }
418
419 for (i = 0; inputs[i].Name; i++) {
420 if (strcmp(inputs[i].Name, name) == 0) {
421 /* found */
422 return inputs[i].Attrib;
423 }
424 }
425 return -1;
426 }
427
428
429 static GLint
430 slang_find_output(GLenum target, const char *name, GLint index)
431 {
432 struct output_info {
433 const char *Name;
434 GLuint Attrib;
435 };
436 static const struct output_info vertOutputs[] = {
437 { "gl_Position", VERT_RESULT_HPOS },
438 { "gl_FrontColor", VERT_RESULT_COL0 },
439 { "gl_BackColor", VERT_RESULT_BFC0 },
440 { "gl_FrontSecondaryColor", VERT_RESULT_COL1 },
441 { "gl_BackSecondaryColor", VERT_RESULT_BFC1 },
442 { "gl_TexCoord", VERT_RESULT_TEX0 }, /* XXX indexed */
443 { "gl_FogFragCoord", VERT_RESULT_FOGC },
444 { NULL, 0 }
445 };
446 static const struct output_info fragOutputs[] = {
447 { "gl_FragColor", FRAG_RESULT_COLR },
448 { NULL, 0 }
449 };
450 const struct output_info *outputs;
451 GLuint i;
452
453 if (target == GL_VERTEX_PROGRAM_ARB) {
454 outputs = vertOutputs;
455 }
456 else {
457 assert(target == GL_FRAGMENT_PROGRAM_ARB);
458 outputs = fragOutputs;
459 }
460
461 for (i = 0; outputs[i].Name; i++) {
462 if (strcmp(outputs[i].Name, name) == 0) {
463 /* found */
464 return outputs[i].Attrib;
465 }
466 }
467 return -1;
468 }
469
470
471 /**
472 * Lookup a named constant and allocate storage for the parameter in
473 * the given parameter list.
474 * \return position of the constant in the paramList.
475 */
476 static GLint
477 slang_lookup_constant(const char *name, GLint index,
478 struct gl_program_parameter_list *paramList)
479 {
480 struct constant_info {
481 const char *Name;
482 const GLenum Token;
483 };
484 static const struct constant_info info[] = {
485 { "gl_MaxLights", GL_MAX_LIGHTS },
486 { "gl_MaxClipPlanes", GL_MAX_CLIP_PLANES },
487 { "gl_MaxTextureUnits", GL_MAX_TEXTURE_UNITS },
488 { "gl_MaxTextureCoords", GL_MAX_TEXTURE_COORDS },
489 { "gl_MaxVertexAttribs", GL_MAX_VERTEX_ATTRIBS },
490 { "gl_MaxVertexUniformComponents", GL_MAX_VERTEX_UNIFORM_COMPONENTS },
491 { "gl_MaxVaryingFloats", GL_MAX_VARYING_FLOATS },
492 { "gl_MaxVertexTextureImageUnits", GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS },
493 { "gl_MaxTextureImageUnits", GL_MAX_TEXTURE_IMAGE_UNITS },
494 { "gl_MaxFragmentUniformComponents", GL_MAX_FRAGMENT_UNIFORM_COMPONENTS },
495 { "gl_MaxCombinedTextureImageUnits", GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS },
496 { NULL, 0 }
497 };
498 GLuint i;
499 GLuint swizzle; /* XXX use this */
500
501 for (i = 0; info[i].Name; i++) {
502 if (strcmp(info[i].Name, name) == 0) {
503 /* found */
504 GLfloat value = -1.0;
505 GLint pos;
506 _mesa_GetFloatv(info[i].Token, &value);
507 ASSERT(value >= 0.0); /* sanity check that glGetFloatv worked */
508 pos = _mesa_add_unnamed_constant(paramList, &value, 1, &swizzle);
509 return pos;
510 }
511 }
512 return -1;
513 }
514
515
516 /**
517 * Determine if 'name' is a state variable. If so, create a new program
518 * parameter for it, and return the param's index. Else, return -1.
519 */
520 static GLint
521 slang_lookup_statevar(const char *name, GLint index,
522 struct gl_program_parameter_list *paramList)
523 {
524 struct state_info {
525 const char *Name;
526 const GLuint NumRows; /** for matrices */
527 const GLuint Swizzle;
528 const GLint Indexes[6];
529 };
530 static const struct state_info state[] = {
531 { "gl_ModelViewMatrix", 4, SWIZZLE_NOOP,
532 { STATE_MATRIX, STATE_MODELVIEW, 0, 0, 0, STATE_MATRIX_TRANSPOSE } },
533 { "gl_NormalMatrix", 3, SWIZZLE_NOOP,
534 { STATE_MATRIX, STATE_MODELVIEW, 0, 0, 0, STATE_MATRIX_INVTRANS } },
535 { "gl_ProjectionMatrix", 4, SWIZZLE_NOOP,
536 { STATE_MATRIX, STATE_PROJECTION, 0, 0, 0, STATE_MATRIX_TRANSPOSE } },
537 { "gl_ModelViewProjectionMatrix", 4, SWIZZLE_NOOP,
538 { STATE_MATRIX, STATE_MVP, 0, 0, 0, STATE_MATRIX_TRANSPOSE } },
539 { "gl_TextureMatrix", 4, SWIZZLE_NOOP,
540 { STATE_MATRIX, STATE_TEXTURE, 0, 0, 0, STATE_MATRIX_TRANSPOSE } },
541 { NULL, 0, 0, {0, 0, 0, 0, 0, 0} }
542 };
543 GLuint i;
544
545 for (i = 0; state[i].Name; i++) {
546 if (strcmp(state[i].Name, name) == 0) {
547 /* found */
548 if (paramList) {
549 if (state[i].NumRows > 1) {
550 /* a matrix */
551 GLuint j;
552 GLint pos[4], indexesCopy[6];
553 /* make copy of state tokens */
554 for (j = 0; j < 6; j++)
555 indexesCopy[j] = state[i].Indexes[j];
556 /* load rows */
557 for (j = 0; j < state[i].NumRows; j++) {
558 indexesCopy[3] = indexesCopy[4] = j; /* jth row of matrix */
559 pos[j] = _mesa_add_state_reference(paramList, indexesCopy);
560 assert(pos[j] >= 0);
561 }
562 return pos[0];
563 }
564 else {
565 /* non-matrix state */
566 GLint pos
567 = _mesa_add_state_reference(paramList, state[i].Indexes);
568 assert(pos >= 0);
569 return pos;
570 }
571 }
572 }
573 }
574 return -1;
575 }
576
577
578 static GLint
579 slang_alloc_uniform(struct gl_program *prog, const char *name)
580 {
581 GLint i = _mesa_add_uniform(prog->Parameters, name, 4);
582 return i;
583 }
584
585
586 static GLint
587 slang_alloc_varying(struct gl_program *prog, const char *name)
588 {
589 GLint i = _mesa_add_varying(prog->Varying, name, 4); /* XXX fix size */
590 #if 0
591 if (prog->Target == GL_VERTEX_PROGRAM_ARB) {
592 #ifdef OLD_LINK
593 i += VERT_RESULT_VAR0;
594 prog->OutputsWritten |= (1 << i);
595 #else
596 prog->OutputsWritten |= (1 << (i + VERT_RESULT_VAR0));
597 #endif
598 }
599 else {
600 #ifdef OLD_LINK
601 i += FRAG_ATTRIB_VAR0;
602 prog->InputsRead |= (1 << i);
603 #else
604 prog->InputsRead |= (1 << (i + FRAG_ATTRIB_VAR0));
605 #endif
606 }
607 #endif
608 return i;
609 }
610
611
612 /**
613 * Allocate temporary storage for an intermediate result (such as for
614 * a multiply or add, etc.
615 */
616 static void
617 slang_alloc_temp_storage(slang_gen_context *gc, slang_ir_node *n, GLint size)
618 {
619 GLint indx;
620 assert(!n->Var);
621 assert(!n->Store);
622 assert(size > 0);
623 indx = alloc_temporary(gc, size);
624 n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, indx, size);
625 }
626
627
628 /**
629 * Allocate storage info for an IR node (n->Store).
630 * We may do any of the following:
631 * 1. Compute Store->File/Index for program inputs/outputs/uniforms/etc.
632 * 2. Allocate storage for user-declared variables.
633 * 3. Allocate intermediate/unnamed storage for complex expressions.
634 * 4. other?
635 *
636 * If gc or prog is NULL, we may only be able to determine the Store->File
637 * but not an Index (register).
638 */
639 void
640 slang_resolve_storage(slang_gen_context *gc, slang_ir_node *n,
641 struct gl_program *prog)
642 {
643 assert(gc);
644 assert(n);
645 assert(prog);
646
647 if (!n->Store) {
648 /* allocate storage info for this node */
649 if (n->Var && n->Var->aux) {
650 /* node storage info = var storage info */
651 n->Store = (slang_ir_storage *) n->Var->aux;
652 }
653 else {
654 /* alloc new storage info */
655 n->Store = _slang_new_ir_storage(PROGRAM_UNDEFINED, -1, -5);
656 if (n->Var)
657 n->Var->aux = n->Store;
658 }
659 }
660
661 if (n->Opcode == IR_VAR_DECL) {
662 /* storage declaration */
663 assert(n->Var);
664 if (n->Store->Index < 0) { /* XXX assert this? */
665 assert(gc);
666 n->Store->File = PROGRAM_TEMPORARY;
667 n->Store->Size = sizeof_type(&n->Var->type);
668 n->Store->Index = alloc_temporary(gc, n->Store->Size);
669 printf("alloc var %s storage at %d (size %d)\n",
670 (char *) n->Var->a_name,
671 n->Store->Index,
672 n->Store->Size);
673 assert(n->Store->Size > 0);
674 n->Var->declared = GL_TRUE;
675 }
676 assert(n->Store->Size > 0);
677 return;
678 }
679
680 if (n->Opcode == IR_VAR && n->Store->File == PROGRAM_UNDEFINED) {
681 /* try to determine the storage for this variable */
682 GLint i;
683
684 assert(n->Var);
685
686 if (n->Store->Size < 0) {
687 /* determine var/storage size now */
688 n->Store->Size = sizeof_type(&n->Var->type);
689 assert(n->Store->Size > 0);
690 }
691
692 #if 0
693 assert(n->Var->declared ||
694 n->Var->type.qualifier == slang_qual_uniform ||
695 n->Var->type.qualifier == slang_qual_varying ||
696 n->Var->type.qualifier == slang_qual_fixedoutput ||
697 n->Var->type.qualifier == slang_qual_attribute ||
698 n->Var->type.qualifier == slang_qual_out ||
699 n->Var->type.qualifier == slang_qual_const);
700 #endif
701
702 i = slang_find_input(prog->Target, (char *) n->Var->a_name, 0);
703 if (i >= 0) {
704 n->Store->File = PROGRAM_INPUT;
705 n->Store->Index = i;
706 assert(n->Store->Size > 0);
707 prog->InputsRead |= (1 << i);
708 return;
709 }
710
711 i = slang_find_output(prog->Target, (char *) n->Var->a_name, 0);
712 if (i >= 0) {
713 n->Store->File = PROGRAM_OUTPUT;
714 n->Store->Index = i;
715 prog->OutputsWritten |= (1 << i);
716 return;
717 }
718
719 i = slang_lookup_statevar((char *) n->Var->a_name, 0, prog->Parameters);
720 if (i >= 0) {
721 n->Store->File = PROGRAM_STATE_VAR;
722 n->Store->Index = i;
723 return;
724 }
725
726 i = slang_lookup_constant((char *) n->Var->a_name, 0, prog->Parameters);
727 if (i >= 0) {
728 n->Store->File = PROGRAM_CONSTANT;
729 n->Store->Index = i;
730 return;
731 }
732
733 /* probably a uniform or varying */
734 if (n->Var->type.qualifier == slang_qual_uniform) {
735 i = slang_alloc_uniform(prog, (char *) n->Var->a_name);
736 if (i >= 0) {
737 n->Store->File = PROGRAM_UNIFORM;
738 n->Store->Index = i;
739 return;
740 }
741 }
742 else if (n->Var->type.qualifier == slang_qual_varying) {
743 i = slang_alloc_varying(prog, (char *) n->Var->a_name);
744 if (i >= 0) {
745 #ifdef OLD_LINK
746 if (prog->Target == GL_VERTEX_PROGRAM_ARB)
747 n->Store->File = PROGRAM_OUTPUT;
748 else
749 n->Store->File = PROGRAM_INPUT;
750 #else
751 n->Store->File = PROGRAM_VARYING;
752 #endif
753 n->Store->Index = i;
754 return;
755 }
756 }
757
758 if (n->Store->File == PROGRAM_UNDEFINED && n->Store->Index < 0) {
759 /* ordinary local var */
760 assert(n->Store->Size > 0);
761 n->Store->File = PROGRAM_TEMPORARY;
762 n->Store->Index = alloc_temporary(gc, n->Store->Size);
763 }
764 }
765 }
766
767
768 static slang_ir_storage *
769 alloc_constant(const GLfloat v[], GLuint size, struct gl_program *prog)
770 {
771 GLuint swizzle;
772 GLint ind = _mesa_add_unnamed_constant(prog->Parameters, v, size, &swizzle);
773 slang_ir_storage *st = _slang_new_ir_storage(PROGRAM_CONSTANT, ind, size);
774 return st;
775 }
776
777
778 /**
779 * Swizzle a swizzle.
780 */
781 #if 0
782 static GLuint
783 swizzle_compose(GLuint swz1, GLuint swz2)
784 {
785 GLuint i, swz, s[4];
786 for (i = 0; i < 4; i++) {
787 GLuint c = GET_SWZ(swz1, i);
788 s[i] = GET_SWZ(swz2, c);
789 }
790 swz = MAKE_SWIZZLE4(s[0], s[1], s[2], s[3]);
791 return swz;
792 }
793 #endif
794
795
796 /**
797 * Convert IR storage to an instruction dst register.
798 */
799 static void
800 storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st,
801 GLuint writemask)
802 {
803 static const GLuint defaultWritemask[4] = {
804 WRITEMASK_X,
805 WRITEMASK_X | WRITEMASK_Y,
806 WRITEMASK_X | WRITEMASK_Y | WRITEMASK_Z,
807 WRITEMASK_X | WRITEMASK_Y | WRITEMASK_Z | WRITEMASK_W
808 };
809 dst->File = st->File;
810 dst->Index = st->Index;
811 assert(st->File != PROGRAM_UNDEFINED);
812 assert(st->Size >= 1);
813 assert(st->Size <= 4);
814 dst->WriteMask = defaultWritemask[st->Size - 1] & writemask;
815 }
816
817
818 /**
819 * Convert IR storage to an instruction src register.
820 */
821 static void
822 storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st,
823 GLuint swizzle)
824 {
825 static const GLuint defaultSwizzle[4] = {
826 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X),
827 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
828 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
829 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W)
830 };
831
832 src->File = st->File;
833 src->Index = st->Index;
834 assert(st->File != PROGRAM_UNDEFINED);
835 assert(st->Size >= 1);
836 assert(st->Size <= 4);
837 /* XXX swizzling logic here may need some work */
838 /*src->Swizzle = swizzle_compose(swizzle, defaultSwizzle[st->Size - 1]);*/
839 if (swizzle != SWIZZLE_NOOP)
840 src->Swizzle = swizzle;
841 else
842 src->Swizzle = defaultSwizzle[st->Size - 1];
843 }
844
845
846
847 /**
848 * Add new instruction at end of given program.
849 * \param prog the program to append instruction onto
850 * \param opcode opcode for the new instruction
851 * \return pointer to the new instruction
852 */
853 static struct prog_instruction *
854 new_instruction(struct gl_program *prog, gl_inst_opcode opcode)
855 {
856 struct prog_instruction *inst;
857 prog->Instructions = _mesa_realloc_instructions(prog->Instructions,
858 prog->NumInstructions,
859 prog->NumInstructions + 1);
860 inst = prog->Instructions + prog->NumInstructions;
861 prog->NumInstructions++;
862 _mesa_init_instructions(inst, 1);
863 inst->Opcode = opcode;
864 return inst;
865 }
866
867
868 static struct prog_instruction *
869 gen(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog);
870
871
872 /**
873 * Generate code for a simple binary-op instruction.
874 */
875 static struct prog_instruction *
876 gen_binop(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog)
877 {
878 struct prog_instruction *inst;
879 const slang_ir_info *info = slang_find_ir_info(n->Opcode);
880 assert(info);
881
882 gen(gc, n->Children[0], prog);
883 gen(gc, n->Children[1], prog);
884 inst = new_instruction(prog, info->InstOpcode);
885 /* alloc temp storage for the result: */
886 if (!n->Store || n->Store->File == PROGRAM_UNDEFINED) {
887 #if 1
888 slang_alloc_temp_storage(gc, n, info->ResultSize);
889 #else
890 slang_resolve_storage(gc, n, prog);
891 #endif
892 }
893 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
894 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store,
895 n->Children[0]->Swizzle);
896 storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Store,
897 n->Children[1]->Swizzle);
898 inst->Comment = n->Comment;
899 return inst;
900 }
901
902
903 static struct prog_instruction *
904 gen_unop(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog)
905 {
906 struct prog_instruction *inst;
907 const slang_ir_info *info = slang_find_ir_info(n->Opcode);
908 assert(info);
909
910 assert(info->NumParams == 1);
911
912 gen(gc, n->Children[0], prog);
913
914 inst = new_instruction(prog, info->InstOpcode);
915 /*slang_resolve_storage(gc, n, prog);*/
916
917 if (!n->Store)
918 slang_alloc_temp_storage(gc, n, info->ResultSize);
919
920 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
921
922 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store,
923 n->Children[0]->Swizzle);
924
925 inst->Comment = n->Comment;
926
927 return inst;
928 }
929
930
931 static struct prog_instruction *
932 gen(slang_gen_context *gc, slang_ir_node *n, struct gl_program *prog)
933 {
934 struct prog_instruction *inst;
935 if (!n)
936 return NULL;
937
938 switch (n->Opcode) {
939 case IR_SEQ:
940 assert(n->Children[0]);
941 assert(n->Children[1]);
942 gen(gc, n->Children[0], prog);
943 inst = gen(gc, n->Children[1], prog);
944 n->Store = n->Children[1]->Store;
945 return inst;
946 break;
947 case IR_VAR_DECL:
948 slang_resolve_storage(gc, n, prog);
949 assert(n->Store->Index >= 0);
950 assert(n->Store->Size > 0);
951 break;
952 case IR_VAR:
953 /*printf("Gen: var ref\n");*/
954 {
955 int b = !n->Store || n->Store->Index < 0;
956 if (b)
957 slang_resolve_storage(gc, n, prog);
958 /*assert(n->Store->Index >= 0);*/
959 assert(n->Store->Size > 0);
960 }
961 break;
962 case IR_MOVE:
963 /* rhs */
964 assert(n->Children[1]);
965 inst = gen(gc, n->Children[1], prog);
966 /* lhs */
967 gen(gc, n->Children[0], prog);
968
969 #if 1
970 if (inst && is_temporary(gc, n->Children[1]->Store)) {
971 /* Peephole optimization:
972 * Just modify the RHS to put its result into the dest of this
973 * MOVE operation. Then, this MOVE is a no-op.
974 */
975 free_temporary(gc, n->Children[1]->Store->Index,
976 n->Children[1]->Store->Size);
977 *n->Children[1]->Store = *n->Children[0]->Store;
978 /* fixup the prev (RHS) instruction */
979 storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask);
980 return inst;
981 }
982 else
983 #endif
984 {
985 if (n->Children[0]->Store->Size > 4) {
986 /* move matrix/struct etc */
987 slang_ir_storage dstStore = *n->Children[0]->Store;
988 slang_ir_storage srcStore = *n->Children[1]->Store;
989 GLint size = srcStore.Size;
990 ASSERT(n->Children[0]->Writemask == WRITEMASK_XYZW);
991 ASSERT(n->Children[1]->Swizzle == SWIZZLE_NOOP);
992 dstStore.Size = 4;
993 srcStore.Size = 4;
994 while (size >= 4) {
995 inst = new_instruction(prog, OPCODE_MOV);
996 inst->Comment = _mesa_strdup("IR_MOVE block");
997 storage_to_dst_reg(&inst->DstReg, &dstStore, n->Writemask);
998 storage_to_src_reg(&inst->SrcReg[0], &srcStore,
999 n->Children[1]->Swizzle);
1000 srcStore.Index++;
1001 dstStore.Index++;
1002 size -= 4;
1003 }
1004 }
1005 else {
1006 inst = new_instruction(prog, OPCODE_MOV);
1007 storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask);
1008 storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store,
1009 n->Children[1]->Swizzle);
1010 }
1011 if (n->Children[1]->Store->File == PROGRAM_TEMPORARY) {
1012 free_temporary(gc, n->Children[1]->Store->Index,
1013 n->Children[1]->Store->Size);
1014 }
1015 /*inst->Comment = _mesa_strdup("IR_MOVE");*/
1016 n->Store = n->Children[0]->Store; /*XXX new */
1017 return inst;
1018 }
1019 break;
1020 case IR_ADD:
1021 case IR_SUB:
1022 case IR_MUL:
1023 case IR_DOT4:
1024 case IR_DOT3:
1025 case IR_CROSS:
1026 case IR_MIN:
1027 case IR_MAX:
1028 case IR_SEQUAL:
1029 case IR_SNEQUAL:
1030 case IR_SGE:
1031 case IR_SGT:
1032 case IR_POW:
1033 case IR_EXP:
1034 case IR_EXP2:
1035 return gen_binop(gc, n, prog);
1036 break;
1037 case IR_RSQ:
1038 case IR_RCP:
1039 case IR_FLOOR:
1040 case IR_FRAC:
1041 case IR_ABS:
1042 case IR_SIN:
1043 case IR_COS:
1044 return gen_unop(gc, n, prog);
1045 break;
1046 case IR_LABEL:
1047 /*printf("LAB: %s\n", n->Target);*/
1048 break;
1049 case IR_JUMP:
1050 #if 0
1051 inst = new_instruction(prog, OPCODE_BRA);
1052 inst->Comment = _mesa_strdup(n->Target);
1053 #endif
1054 break;
1055 case IR_FLOAT:
1056 n->Store = alloc_constant(n->Value, 4, prog); /*XXX fix size */
1057 break;
1058 default:
1059 printf("gen: ?\n");
1060 abort();
1061 }
1062 return NULL;
1063 }
1064
1065
1066 slang_gen_context *
1067 _slang_new_codegen_context(void)
1068 {
1069 slang_gen_context *gc = (slang_gen_context *) _mesa_calloc(sizeof(*gc));
1070 return gc;
1071 }
1072
1073
1074
1075 GLboolean
1076 _slang_emit_code(slang_ir_node *n, slang_gen_context *gc,
1077 struct gl_program *prog)
1078 {
1079 /*GET_CURRENT_CONTEXT(ctx);*/
1080
1081 /*
1082 gc = _slang_new_codegen_context();
1083 */
1084
1085 printf("************ Begin generate code\n");
1086
1087 gen(gc, n, prog);
1088
1089 {
1090 struct prog_instruction *inst;
1091 inst = new_instruction(prog, OPCODE_END);
1092 }
1093
1094 printf("************ End generate code (%u inst):\n", prog->NumInstructions);
1095
1096 #if 0
1097 _mesa_print_program(prog);
1098 _mesa_print_program_parameters(ctx,prog);
1099 #endif
1100
1101 _mesa_free(gc);
1102
1103 return GL_FALSE;
1104 }