comments, etc
[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 "macros.h"
34 #include "program.h"
35 #include "prog_instruction.h"
36 #include "prog_parameter.h"
37 #include "prog_print.h"
38 #include "slang_emit.h"
39 #include "slang_error.h"
40
41
42 #define PEEPHOLE_OPTIMIZATIONS 1
43 #define ANNOTATE 0
44
45
46 /* XXX temporarily here */
47 static GLboolean EmitHighLevelInstructions = GL_TRUE;
48
49
50
51 /**
52 * Assembly and IR info
53 */
54 typedef struct
55 {
56 slang_ir_opcode IrOpcode;
57 const char *IrName;
58 gl_inst_opcode InstOpcode;
59 GLuint ResultSize, NumParams;
60 } slang_ir_info;
61
62
63
64 static const slang_ir_info IrInfo[] = {
65 /* binary ops */
66 { IR_ADD, "IR_ADD", OPCODE_ADD, 4, 2 },
67 { IR_SUB, "IR_SUB", OPCODE_SUB, 4, 2 },
68 { IR_MUL, "IR_MUL", OPCODE_MUL, 4, 2 },
69 { IR_DIV, "IR_DIV", OPCODE_NOP, 0, 2 }, /* XXX broke */
70 { IR_DOT4, "IR_DOT_4", OPCODE_DP4, 1, 2 },
71 { IR_DOT3, "IR_DOT_3", OPCODE_DP3, 1, 2 },
72 { IR_CROSS, "IR_CROSS", OPCODE_XPD, 3, 2 },
73 { IR_LRP, "IR_LRP", OPCODE_LRP, 4, 3 },
74 { IR_MIN, "IR_MIN", OPCODE_MIN, 4, 2 },
75 { IR_MAX, "IR_MAX", OPCODE_MAX, 4, 2 },
76 { IR_CLAMP, "IR_CLAMP", OPCODE_NOP, 4, 3 }, /* special case: emit_clamp() */
77 { IR_SEQUAL, "IR_SEQUAL", OPCODE_SEQ, 4, 2 },
78 { IR_SNEQUAL, "IR_SNEQUAL", OPCODE_SNE, 4, 2 },
79 { IR_SGE, "IR_SGE", OPCODE_SGE, 4, 2 },
80 { IR_SGT, "IR_SGT", OPCODE_SGT, 4, 2 },
81 { IR_POW, "IR_POW", OPCODE_POW, 1, 2 },
82 /* unary ops */
83 { IR_I_TO_F, "IR_I_TO_F", OPCODE_NOP, 1, 1 },
84 { IR_F_TO_I, "IR_F_TO_I", OPCODE_INT, 4, 1 }, /* 4 floats to 4 ints */
85 { IR_EXP, "IR_EXP", OPCODE_EXP, 1, 1 },
86 { IR_EXP2, "IR_EXP2", OPCODE_EX2, 1, 1 },
87 { IR_LOG2, "IR_LOG2", OPCODE_LG2, 1, 1 },
88 { IR_RSQ, "IR_RSQ", OPCODE_RSQ, 1, 1 },
89 { IR_RCP, "IR_RCP", OPCODE_RCP, 1, 1 },
90 { IR_FLOOR, "IR_FLOOR", OPCODE_FLR, 4, 1 },
91 { IR_FRAC, "IR_FRAC", OPCODE_FRC, 4, 1 },
92 { IR_ABS, "IR_ABS", OPCODE_ABS, 4, 1 },
93 { IR_NEG, "IR_NEG", OPCODE_NOP, 4, 1 }, /* special case: emit_negation() */
94 { IR_DDX, "IR_DDX", OPCODE_DDX, 4, 1 },
95 { IR_DDX, "IR_DDY", OPCODE_DDX, 4, 1 },
96 { IR_SIN, "IR_SIN", OPCODE_SIN, 1, 1 },
97 { IR_COS, "IR_COS", OPCODE_COS, 1, 1 },
98 { IR_NOISE1, "IR_NOISE1", OPCODE_NOISE1, 1, 1 },
99 { IR_NOISE2, "IR_NOISE2", OPCODE_NOISE2, 1, 1 },
100 { IR_NOISE3, "IR_NOISE3", OPCODE_NOISE3, 1, 1 },
101 { IR_NOISE4, "IR_NOISE4", OPCODE_NOISE4, 1, 1 },
102
103 /* other */
104 { IR_SEQ, "IR_SEQ", OPCODE_NOP, 0, 0 },
105 { IR_SCOPE, "IR_SCOPE", OPCODE_NOP, 0, 0 },
106 { IR_LABEL, "IR_LABEL", OPCODE_NOP, 0, 0 },
107 { IR_JUMP, "IR_JUMP", OPCODE_NOP, 0, 0 },
108 { IR_CJUMP0, "IR_CJUMP0", OPCODE_NOP, 0, 0 },
109 { IR_CJUMP1, "IR_CJUMP1", OPCODE_NOP, 0, 0 },
110 { IR_IF, "IR_IF", OPCODE_NOP, 0, 0 },
111 { IR_KILL, "IR_KILL", OPCODE_NOP, 0, 0 },
112 { IR_COND, "IR_COND", OPCODE_NOP, 0, 0 },
113 { IR_CALL, "IR_CALL", OPCODE_NOP, 0, 0 },
114 { IR_MOVE, "IR_MOVE", OPCODE_NOP, 0, 1 },
115 { IR_NOT, "IR_NOT", OPCODE_NOP, 1, 1 },
116 { IR_VAR, "IR_VAR", OPCODE_NOP, 0, 0 },
117 { IR_VAR_DECL, "IR_VAR_DECL", OPCODE_NOP, 0, 0 },
118 { IR_TEX, "IR_TEX", OPCODE_TEX, 4, 1 },
119 { IR_TEXB, "IR_TEXB", OPCODE_TXB, 4, 1 },
120 { IR_TEXP, "IR_TEXP", OPCODE_TXP, 4, 1 },
121 { IR_FLOAT, "IR_FLOAT", OPCODE_NOP, 0, 0 }, /* float literal */
122 { IR_FIELD, "IR_FIELD", OPCODE_NOP, 0, 0 },
123 { IR_ELEMENT, "IR_ELEMENT", OPCODE_NOP, 0, 0 },
124 { IR_SWIZZLE, "IR_SWIZZLE", OPCODE_NOP, 0, 0 },
125 { IR_NOP, NULL, OPCODE_NOP, 0, 0 }
126 };
127
128
129 static const slang_ir_info *
130 slang_find_ir_info(slang_ir_opcode opcode)
131 {
132 GLuint i;
133 for (i = 0; IrInfo[i].IrName; i++) {
134 if (IrInfo[i].IrOpcode == opcode) {
135 return IrInfo + i;
136 }
137 }
138 return NULL;
139 }
140
141 static const char *
142 slang_ir_name(slang_ir_opcode opcode)
143 {
144 return slang_find_ir_info(opcode)->IrName;
145 }
146
147
148 /**
149 * Swizzle a swizzle. That is, return swz2(swz1)
150 */
151 static GLuint
152 swizzle_swizzle(GLuint swz1, GLuint swz2)
153 {
154 GLuint i, swz, s[4];
155 for (i = 0; i < 4; i++) {
156 GLuint c = GET_SWZ(swz2, i);
157 s[i] = GET_SWZ(swz1, c);
158 }
159 swz = MAKE_SWIZZLE4(s[0], s[1], s[2], s[3]);
160 return swz;
161 }
162
163
164 slang_ir_storage *
165 _slang_new_ir_storage(enum register_file file, GLint index, GLint size)
166 {
167 slang_ir_storage *st;
168 st = (slang_ir_storage *) _mesa_calloc(sizeof(slang_ir_storage));
169 if (st) {
170 st->File = file;
171 st->Index = index;
172 st->Size = size;
173 st->Swizzle = SWIZZLE_NOOP;
174 }
175 return st;
176 }
177
178
179 static const char *
180 swizzle_string(GLuint swizzle)
181 {
182 static char s[6];
183 GLuint i;
184 s[0] = '.';
185 for (i = 1; i < 5; i++) {
186 s[i] = "xyzw"[GET_SWZ(swizzle, i-1)];
187 }
188 s[i] = 0;
189 return s;
190 }
191
192 static const char *
193 writemask_string(GLuint writemask)
194 {
195 static char s[6];
196 GLuint i, j = 0;
197 s[j++] = '.';
198 for (i = 0; i < 4; i++) {
199 if (writemask & (1 << i))
200 s[j++] = "xyzw"[i];
201 }
202 s[j] = 0;
203 return s;
204 }
205
206 static const char *
207 storage_string(const slang_ir_storage *st)
208 {
209 static const char *files[] = {
210 "TEMP",
211 "LOCAL_PARAM",
212 "ENV_PARAM",
213 "STATE",
214 "INPUT",
215 "OUTPUT",
216 "NAMED_PARAM",
217 "CONSTANT",
218 "UNIFORM",
219 "WRITE_ONLY",
220 "ADDRESS",
221 "SAMPLER",
222 "UNDEFINED"
223 };
224 static char s[100];
225 #if 0
226 if (st->Size == 1)
227 sprintf(s, "%s[%d]", files[st->File], st->Index);
228 else
229 sprintf(s, "%s[%d..%d]", files[st->File], st->Index,
230 st->Index + st->Size - 1);
231 #endif
232 assert(st->File < (GLint) (sizeof(files) / sizeof(files[0])));
233 sprintf(s, "%s[%d]", files[st->File], st->Index);
234 return s;
235 }
236
237
238 static void
239 spaces(int n)
240 {
241 while (n-- > 0) {
242 printf(" ");
243 }
244 }
245
246 #define IND 0
247 void
248 slang_print_ir(const slang_ir_node *n, int indent)
249 {
250 if (!n)
251 return;
252 #if !IND
253 if (n->Opcode != IR_SEQ)
254 #else
255 printf("%3d:", indent);
256 #endif
257 spaces(indent);
258
259 switch (n->Opcode) {
260 case IR_SEQ:
261 #if IND
262 printf("SEQ at %p\n", (void*) n);
263 #endif
264 assert(n->Children[0]);
265 assert(n->Children[1]);
266 slang_print_ir(n->Children[0], indent + IND);
267 slang_print_ir(n->Children[1], indent + IND);
268 break;
269 case IR_SCOPE:
270 printf("NEW SCOPE\n");
271 assert(!n->Children[1]);
272 slang_print_ir(n->Children[0], indent + 3);
273 break;
274 case IR_MOVE:
275 printf("MOVE (writemask = %s)\n", writemask_string(n->Writemask));
276 slang_print_ir(n->Children[0], indent+3);
277 slang_print_ir(n->Children[1], indent+3);
278 break;
279 case IR_LABEL:
280 printf("LABEL: %s\n", n->Target);
281 break;
282 case IR_COND:
283 printf("COND\n");
284 slang_print_ir(n->Children[0], indent + 3);
285 break;
286 case IR_JUMP:
287 printf("JUMP %s\n", n->Target);
288 break;
289 case IR_CJUMP0:
290 printf("CJUMP0 %s\n", n->Target);
291 slang_print_ir(n->Children[0], indent+3);
292 break;
293 case IR_CJUMP1:
294 printf("CJUMP1 %s\n", n->Target);
295 slang_print_ir(n->Children[0], indent+3);
296 break;
297
298 case IR_IF:
299 printf("IF \n");
300 slang_print_ir(n->Children[0], indent+3);
301 spaces(indent);
302 printf("THEN\n");
303 slang_print_ir(n->Children[1], indent+3);
304 if (n->Children[2]) {
305 spaces(indent);
306 printf("ELSE\n");
307 slang_print_ir(n->Children[2], indent+3);
308 }
309 printf("ENDIF\n");
310 break;
311
312 case IR_BEGIN_SUB:
313 printf("BEGIN_SUB\n");
314 break;
315 case IR_END_SUB:
316 printf("END_SUB\n");
317 break;
318 case IR_RETURN:
319 printf("RETURN\n");
320 break;
321 case IR_CALL:
322 printf("CALL\n");
323 break;
324
325 case IR_LOOP:
326 printf("LOOP\n");
327 slang_print_ir(n->Children[0], indent+3);
328 spaces(indent);
329 printf("ENDLOOP\n");
330 break;
331 case IR_CONT:
332 printf("CONT\n");
333 break;
334 case IR_BREAK:
335 printf("BREAK\n");
336 break;
337 case IR_BREAK_IF_FALSE:
338 printf("BREAK_IF_FALSE\n");
339 slang_print_ir(n->Children[0], indent+3);
340 break;
341 case IR_BREAK_IF_TRUE:
342 printf("BREAK_IF_TRUE\n");
343 slang_print_ir(n->Children[0], indent+3);
344 break;
345 case IR_CONT_IF_FALSE:
346 printf("CONT_IF_FALSE\n");
347 slang_print_ir(n->Children[0], indent+3);
348 break;
349 case IR_CONT_IF_TRUE:
350 printf("CONT_IF_TRUE\n");
351 slang_print_ir(n->Children[0], indent+3);
352 break;
353
354 case IR_VAR:
355 printf("VAR %s%s at %s store %p\n",
356 (n->Var ? (char *) n->Var->a_name : "TEMP"),
357 swizzle_string(n->Store->Swizzle),
358 storage_string(n->Store), (void*) n->Store);
359 break;
360 case IR_VAR_DECL:
361 printf("VAR_DECL %s (%p) at %s store %p\n",
362 (n->Var ? (char *) n->Var->a_name : "TEMP"),
363 (void*) n->Var, storage_string(n->Store),
364 (void*) n->Store);
365 break;
366 case IR_FIELD:
367 printf("FIELD %s of\n", n->Target);
368 slang_print_ir(n->Children[0], indent+3);
369 break;
370 case IR_FLOAT:
371 printf("FLOAT %g %g %g %g\n",
372 n->Value[0], n->Value[1], n->Value[2], n->Value[3]);
373 break;
374 case IR_I_TO_F:
375 printf("INT_TO_FLOAT\n");
376 slang_print_ir(n->Children[0], indent+3);
377 break;
378 case IR_F_TO_I:
379 printf("FLOAT_TO_INT\n");
380 slang_print_ir(n->Children[0], indent+3);
381 break;
382 case IR_SWIZZLE:
383 printf("SWIZZLE %s of (store %p) \n",
384 swizzle_string(n->Store->Swizzle), (void*) n->Store);
385 slang_print_ir(n->Children[0], indent + 3);
386 break;
387 default:
388 printf("%s (%p, %p) (store %p)\n", slang_ir_name(n->Opcode),
389 (void*) n->Children[0], (void*) n->Children[1], (void*) n->Store);
390 slang_print_ir(n->Children[0], indent+3);
391 slang_print_ir(n->Children[1], indent+3);
392 }
393 }
394
395
396 /**
397 * Allocate temporary storage for an intermediate result (such as for
398 * a multiply or add, etc.
399 */
400 static GLboolean
401 alloc_temp_storage(slang_var_table *vt, slang_ir_node *n, GLint size)
402 {
403 assert(!n->Var);
404 assert(!n->Store);
405 assert(size > 0);
406 n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, size);
407 if (!_slang_alloc_temp(vt, n->Store)) {
408 RETURN_ERROR("Ran out of registers, too many temporaries", 0);
409 }
410 return GL_TRUE;
411 }
412
413
414 /**
415 * Free temporary storage, if n->Store is, in fact, temp storage.
416 * Otherwise, no-op.
417 */
418 static void
419 free_temp_storage(slang_var_table *vt, slang_ir_node *n)
420 {
421 if (n->Store->File == PROGRAM_TEMPORARY && n->Store->Index >= 0) {
422 if (_slang_is_temp(vt, n->Store)) {
423 _slang_free_temp(vt, n->Store);
424 n->Store->Index = -1;
425 n->Store->Size = -1;
426 }
427 }
428 }
429
430
431 /**
432 * Convert IR storage to an instruction dst register.
433 */
434 static void
435 storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st,
436 GLuint writemask)
437 {
438 static const GLuint defaultWritemask[4] = {
439 WRITEMASK_X,
440 WRITEMASK_X | WRITEMASK_Y,
441 WRITEMASK_X | WRITEMASK_Y | WRITEMASK_Z,
442 WRITEMASK_X | WRITEMASK_Y | WRITEMASK_Z | WRITEMASK_W
443 };
444 assert(st->Index >= 0 && st->Index <= 16);
445 dst->File = st->File;
446 dst->Index = st->Index;
447 assert(st->File != PROGRAM_UNDEFINED);
448 assert(st->Size >= 1);
449 assert(st->Size <= 4);
450 if (st->Size == 1) {
451 GLuint comp = GET_SWZ(st->Swizzle, 0);
452 assert(comp < 4);
453 assert(writemask & WRITEMASK_X);
454 dst->WriteMask = WRITEMASK_X << comp;
455 }
456 else {
457 dst->WriteMask = defaultWritemask[st->Size - 1] & writemask;
458 }
459 }
460
461
462 /**
463 * Convert IR storage to an instruction src register.
464 */
465 static void
466 storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st)
467 {
468 static const GLuint defaultSwizzle[4] = {
469 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X),
470 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
471 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
472 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W)
473 };
474 assert(st->File >= 0 && st->File <= 16);
475 src->File = st->File;
476 src->Index = st->Index;
477 assert(st->File != PROGRAM_UNDEFINED);
478 assert(st->Size >= 1);
479 assert(st->Size <= 4);
480 if (st->Swizzle != SWIZZLE_NOOP)
481 src->Swizzle = st->Swizzle;
482 else
483 src->Swizzle = defaultSwizzle[st->Size - 1]; /*XXX really need this?*/
484
485 assert(GET_SWZ(src->Swizzle, 0) != SWIZZLE_NIL);
486 assert(GET_SWZ(src->Swizzle, 1) != SWIZZLE_NIL);
487 assert(GET_SWZ(src->Swizzle, 2) != SWIZZLE_NIL);
488 assert(GET_SWZ(src->Swizzle, 3) != SWIZZLE_NIL);
489 }
490
491
492
493 /**
494 * Add new instruction at end of given program.
495 * \param prog the program to append instruction onto
496 * \param opcode opcode for the new instruction
497 * \return pointer to the new instruction
498 */
499 static struct prog_instruction *
500 new_instruction(struct gl_program *prog, gl_inst_opcode opcode)
501 {
502 struct prog_instruction *inst;
503 prog->Instructions = _mesa_realloc_instructions(prog->Instructions,
504 prog->NumInstructions,
505 prog->NumInstructions + 1);
506 inst = prog->Instructions + prog->NumInstructions;
507 prog->NumInstructions++;
508 _mesa_init_instructions(inst, 1);
509 inst->Opcode = opcode;
510 inst->BranchTarget = -1; /* invalid */
511 return inst;
512 }
513
514
515 /**
516 * Return pointer to last instruction in program.
517 */
518 static struct prog_instruction *
519 prev_instruction(struct gl_program *prog)
520 {
521 if (prog->NumInstructions == 0)
522 return NULL;
523 else
524 return prog->Instructions + prog->NumInstructions - 1;
525 }
526
527
528 static struct prog_instruction *
529 emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog);
530
531
532 /**
533 * Return an annotation string for given node's storage.
534 */
535 static char *
536 storage_annotation(const slang_ir_node *n, const struct gl_program *prog)
537 {
538 #if ANNOTATE
539 const slang_ir_storage *st = n->Store;
540 static char s[100] = "";
541
542 if (!st)
543 return _mesa_strdup("");
544
545 switch (st->File) {
546 case PROGRAM_CONSTANT:
547 if (st->Index >= 0) {
548 const GLfloat *val = prog->Parameters->ParameterValues[st->Index];
549 if (st->Swizzle == SWIZZLE_NOOP)
550 sprintf(s, "{%g, %g, %g, %g}", val[0], val[1], val[2], val[3]);
551 else {
552 sprintf(s, "%g", val[GET_SWZ(st->Swizzle, 0)]);
553 }
554 }
555 break;
556 case PROGRAM_TEMPORARY:
557 if (n->Var)
558 sprintf(s, "%s", (char *) n->Var->a_name);
559 else
560 sprintf(s, "t[%d]", st->Index);
561 break;
562 case PROGRAM_STATE_VAR:
563 case PROGRAM_UNIFORM:
564 sprintf(s, "%s", prog->Parameters->Parameters[st->Index].Name);
565 break;
566 case PROGRAM_VARYING:
567 sprintf(s, "%s", prog->Varying->Parameters[st->Index].Name);
568 break;
569 case PROGRAM_INPUT:
570 sprintf(s, "input[%d]", st->Index);
571 break;
572 case PROGRAM_OUTPUT:
573 sprintf(s, "output[%d]", st->Index);
574 break;
575 default:
576 s[0] = 0;
577 }
578 return _mesa_strdup(s);
579 #else
580 return NULL;
581 #endif
582 }
583
584
585 /**
586 * Return an annotation string for an instruction.
587 */
588 static char *
589 instruction_annotation(gl_inst_opcode opcode, char *dstAnnot,
590 char *srcAnnot0, char *srcAnnot1, char *srcAnnot2)
591 {
592 #if ANNOTATE
593 const char *operator;
594 char *s;
595 int len = 50;
596
597 if (dstAnnot)
598 len += strlen(dstAnnot);
599 else
600 dstAnnot = _mesa_strdup("");
601
602 if (srcAnnot0)
603 len += strlen(srcAnnot0);
604 else
605 srcAnnot0 = _mesa_strdup("");
606
607 if (srcAnnot1)
608 len += strlen(srcAnnot1);
609 else
610 srcAnnot1 = _mesa_strdup("");
611
612 if (srcAnnot2)
613 len += strlen(srcAnnot2);
614 else
615 srcAnnot2 = _mesa_strdup("");
616
617 switch (opcode) {
618 case OPCODE_ADD:
619 operator = "+";
620 break;
621 case OPCODE_SUB:
622 operator = "-";
623 break;
624 case OPCODE_MUL:
625 operator = "*";
626 break;
627 case OPCODE_DP3:
628 operator = "DP3";
629 break;
630 case OPCODE_DP4:
631 operator = "DP4";
632 break;
633 case OPCODE_XPD:
634 operator = "XPD";
635 break;
636 case OPCODE_RSQ:
637 operator = "RSQ";
638 break;
639 case OPCODE_SGT:
640 operator = ">";
641 break;
642 default:
643 operator = ",";
644 }
645
646 s = (char *) malloc(len);
647 sprintf(s, "%s = %s %s %s %s", dstAnnot,
648 srcAnnot0, operator, srcAnnot1, srcAnnot2);
649 assert(_mesa_strlen(s) < len);
650
651 free(dstAnnot);
652 free(srcAnnot0);
653 free(srcAnnot1);
654 free(srcAnnot2);
655
656 return s;
657 #else
658 return NULL;
659 #endif
660 }
661
662
663
664 /**
665 * Generate code for a simple arithmetic instruction.
666 * Either 1, 2 or 3 operands.
667 */
668 static struct prog_instruction *
669 emit_arith(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
670 {
671 struct prog_instruction *inst;
672 const slang_ir_info *info = slang_find_ir_info(n->Opcode);
673 char *srcAnnot[3], *dstAnnot;
674 GLuint i;
675
676 assert(info);
677 assert(info->InstOpcode != OPCODE_NOP);
678
679 srcAnnot[0] = srcAnnot[1] = srcAnnot[2] = dstAnnot = NULL;
680
681 #if PEEPHOLE_OPTIMIZATIONS
682 /* Look for MAD opportunity */
683 if (info->NumParams == 2 &&
684 n->Opcode == IR_ADD && n->Children[0]->Opcode == IR_MUL) {
685 /* found pattern IR_ADD(IR_MUL(A, B), C) */
686 emit(vt, n->Children[0]->Children[0], prog); /* A */
687 emit(vt, n->Children[0]->Children[1], prog); /* B */
688 emit(vt, n->Children[1], prog); /* C */
689 /* generate MAD instruction */
690 inst = new_instruction(prog, OPCODE_MAD);
691 /* operands: A, B, C: */
692 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Children[0]->Store);
693 storage_to_src_reg(&inst->SrcReg[1], n->Children[0]->Children[1]->Store);
694 storage_to_src_reg(&inst->SrcReg[2], n->Children[1]->Store);
695 free_temp_storage(vt, n->Children[0]->Children[0]);
696 free_temp_storage(vt, n->Children[0]->Children[1]);
697 free_temp_storage(vt, n->Children[1]);
698 }
699 else if (info->NumParams == 2 &&
700 n->Opcode == IR_ADD && n->Children[1]->Opcode == IR_MUL) {
701 /* found pattern IR_ADD(A, IR_MUL(B, C)) */
702 emit(vt, n->Children[0], prog); /* A */
703 emit(vt, n->Children[1]->Children[0], prog); /* B */
704 emit(vt, n->Children[1]->Children[1], prog); /* C */
705 /* generate MAD instruction */
706 inst = new_instruction(prog, OPCODE_MAD);
707 /* operands: B, C, A */
708 storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Children[0]->Store);
709 storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Children[1]->Store);
710 storage_to_src_reg(&inst->SrcReg[2], n->Children[0]->Store);
711 free_temp_storage(vt, n->Children[1]->Children[0]);
712 free_temp_storage(vt, n->Children[1]->Children[1]);
713 free_temp_storage(vt, n->Children[0]);
714 }
715 else
716 #endif
717 {
718 /* normal case */
719
720 /* gen code for children */
721 for (i = 0; i < info->NumParams; i++)
722 emit(vt, n->Children[i], prog);
723
724 /* gen this instruction and src registers */
725 inst = new_instruction(prog, info->InstOpcode);
726 for (i = 0; i < info->NumParams; i++)
727 storage_to_src_reg(&inst->SrcReg[i], n->Children[i]->Store);
728
729 /* annotation */
730 for (i = 0; i < info->NumParams; i++)
731 srcAnnot[i] = storage_annotation(n->Children[i], prog);
732
733 /* free temps */
734 for (i = 0; i < info->NumParams; i++)
735 free_temp_storage(vt, n->Children[i]);
736 }
737
738 /* result storage */
739 if (!n->Store) {
740 if (!alloc_temp_storage(vt, n, info->ResultSize))
741 return NULL;
742 }
743 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
744
745 dstAnnot = storage_annotation(n, prog);
746
747 inst->Comment = instruction_annotation(inst->Opcode, dstAnnot, srcAnnot[0],
748 srcAnnot[1], srcAnnot[2]);
749
750 /*_mesa_print_instruction(inst);*/
751 return inst;
752 }
753
754
755 /**
756 * Generate code for an IR_CLAMP instruction.
757 */
758 static struct prog_instruction *
759 emit_clamp(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
760 {
761 struct prog_instruction *inst;
762
763 assert(n->Opcode == IR_CLAMP);
764 /* ch[0] = value
765 * ch[1] = min limit
766 * ch[2] = max limit
767 */
768
769 inst = emit(vt, n->Children[0], prog);
770
771 /* If lower limit == 0.0 and upper limit == 1.0,
772 * set prev instruction's SaturateMode field to SATURATE_ZERO_ONE.
773 * Else,
774 * emit OPCODE_MIN, OPCODE_MAX sequence.
775 */
776 #if 0
777 /* XXX this isn't quite finished yet */
778 if (n->Children[1]->Opcode == IR_FLOAT &&
779 n->Children[1]->Value[0] == 0.0 &&
780 n->Children[1]->Value[1] == 0.0 &&
781 n->Children[1]->Value[2] == 0.0 &&
782 n->Children[1]->Value[3] == 0.0 &&
783 n->Children[2]->Opcode == IR_FLOAT &&
784 n->Children[2]->Value[0] == 1.0 &&
785 n->Children[2]->Value[1] == 1.0 &&
786 n->Children[2]->Value[2] == 1.0 &&
787 n->Children[2]->Value[3] == 1.0) {
788 if (!inst) {
789 inst = prev_instruction(prog);
790 }
791 if (inst && inst->Opcode != OPCODE_NOP) {
792 /* and prev instruction's DstReg matches n->Children[0]->Store */
793 inst->SaturateMode = SATURATE_ZERO_ONE;
794 n->Store = n->Children[0]->Store;
795 return inst;
796 }
797 }
798 #endif
799
800 if (!n->Store)
801 if (!alloc_temp_storage(vt, n, n->Children[0]->Store->Size))
802 return NULL;
803
804 emit(vt, n->Children[1], prog);
805 emit(vt, n->Children[2], prog);
806
807 /* tmp = max(ch[0], ch[1]) */
808 inst = new_instruction(prog, OPCODE_MAX);
809 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
810 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
811 storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Store);
812
813 /* tmp = min(tmp, ch[2]) */
814 inst = new_instruction(prog, OPCODE_MIN);
815 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
816 storage_to_src_reg(&inst->SrcReg[0], n->Store);
817 storage_to_src_reg(&inst->SrcReg[1], n->Children[2]->Store);
818
819 return inst;
820 }
821
822
823 static struct prog_instruction *
824 emit_negation(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
825 {
826 /* Implement as MOV dst, -src; */
827 /* XXX we could look at the previous instruction and in some circumstances
828 * modify it to accomplish the negation.
829 */
830 struct prog_instruction *inst;
831
832 emit(vt, n->Children[0], prog);
833
834 if (!n->Store)
835 if (!alloc_temp_storage(vt, n, n->Children[0]->Store->Size))
836 return NULL;
837
838 inst = new_instruction(prog, OPCODE_MOV);
839 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
840 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
841 inst->SrcReg[0].NegateBase = NEGATE_XYZW;
842 inst->Comment = n->Comment;
843 return inst;
844 }
845
846
847 static struct prog_instruction *
848 emit_label(const char *target, struct gl_program *prog)
849 {
850 struct prog_instruction *inst;
851 inst = new_instruction(prog, OPCODE_NOP);
852 inst->Comment = _mesa_strdup(target);
853 return inst;
854 }
855
856
857 static struct prog_instruction *
858 emit_cjump(const char *target, struct gl_program *prog, GLuint zeroOrOne)
859 {
860 struct prog_instruction *inst;
861 inst = new_instruction(prog, OPCODE_BRA);
862 if (zeroOrOne)
863 inst->DstReg.CondMask = COND_NE; /* branch if non-zero */
864 else
865 inst->DstReg.CondMask = COND_EQ; /* branch if equal to zero */
866 inst->DstReg.CondSwizzle = SWIZZLE_X;
867 inst->Comment = _mesa_strdup(target);
868 return inst;
869 }
870
871
872 static struct prog_instruction *
873 emit_jump(const char *target, struct gl_program *prog)
874 {
875 struct prog_instruction *inst;
876 inst = new_instruction(prog, OPCODE_BRA);
877 inst->DstReg.CondMask = COND_TR; /* always branch */
878 /*inst->DstReg.CondSwizzle = SWIZZLE_X;*/
879 inst->Comment = _mesa_strdup(target);
880 return inst;
881 }
882
883
884 static struct prog_instruction *
885 emit_kill(struct gl_program *prog)
886 {
887 struct prog_instruction *inst;
888 /* NV-KILL - discard fragment depending on condition code.
889 * Note that ARB-KILL depends on sign of vector operand.
890 */
891 inst = new_instruction(prog, OPCODE_KIL_NV);
892 inst->DstReg.CondMask = COND_TR; /* always branch */
893 return inst;
894 }
895
896
897 static struct prog_instruction *
898 emit_tex(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
899 {
900 struct prog_instruction *inst;
901 if (n->Opcode == IR_TEX) {
902 inst = new_instruction(prog, OPCODE_TEX);
903 }
904 else if (n->Opcode == IR_TEXB) {
905 inst = new_instruction(prog, OPCODE_TXB);
906 }
907 else {
908 assert(n->Opcode == IR_TEXP);
909 inst = new_instruction(prog, OPCODE_TXP);
910 }
911
912 if (!n->Store)
913 if (!alloc_temp_storage(vt, n, 4))
914 return NULL;
915
916 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
917
918 (void) emit(vt, n->Children[1], prog);
919
920 /* Child[1] is the coord */
921 storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store);
922
923 /* Child[0] is the sampler (a uniform which'll indicate the texture unit) */
924 assert(n->Children[0]->Store);
925 assert(n->Children[0]->Store->Size >= TEXTURE_1D_INDEX);
926
927 inst->Sampler = n->Children[0]->Store->Index; /* i.e. uniform's index */
928 inst->TexSrcTarget = n->Children[0]->Store->Size;
929 inst->TexSrcUnit = 27; /* Dummy value; the TexSrcUnit will be computed at
930 * link time, using the sampler uniform's value.
931 */
932 return inst;
933 }
934
935
936 static struct prog_instruction *
937 emit_move(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
938 {
939 struct prog_instruction *inst;
940
941 /* rhs */
942 assert(n->Children[1]);
943 inst = emit(vt, n->Children[1], prog);
944
945 assert(n->Children[1]->Store->Index >= 0);
946
947 /* lhs */
948 emit(vt, n->Children[0], prog);
949
950 assert(!n->Store);
951 n->Store = n->Children[0]->Store;
952
953 #if PEEPHOLE_OPTIMIZATIONS
954 if (inst && _slang_is_temp(vt, n->Children[1]->Store)) {
955 /* Peephole optimization:
956 * Just modify the RHS to put its result into the dest of this
957 * MOVE operation. Then, this MOVE is a no-op.
958 */
959 _slang_free_temp(vt, n->Children[1]->Store);
960 *n->Children[1]->Store = *n->Children[0]->Store;
961 /* fixup the prev (RHS) instruction */
962 assert(n->Children[0]->Store->Index >= 0);
963 assert(n->Children[0]->Store->Index < 16);
964 storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask);
965 return inst;
966 }
967 else
968 #endif
969 {
970 if (n->Children[0]->Store->Size > 4) {
971 /* move matrix/struct etc (block of registers) */
972 slang_ir_storage dstStore = *n->Children[0]->Store;
973 slang_ir_storage srcStore = *n->Children[1]->Store;
974 GLint size = srcStore.Size;
975 ASSERT(n->Children[0]->Writemask == WRITEMASK_XYZW);
976 ASSERT(n->Children[1]->Store->Swizzle == SWIZZLE_NOOP);
977 dstStore.Size = 4;
978 srcStore.Size = 4;
979 while (size >= 4) {
980 inst = new_instruction(prog, OPCODE_MOV);
981 inst->Comment = _mesa_strdup("IR_MOVE block");
982 storage_to_dst_reg(&inst->DstReg, &dstStore, n->Writemask);
983 storage_to_src_reg(&inst->SrcReg[0], &srcStore);
984 srcStore.Index++;
985 dstStore.Index++;
986 size -= 4;
987 }
988 }
989 else {
990 /* single register move */
991 char *srcAnnot, *dstAnnot;
992 inst = new_instruction(prog, OPCODE_MOV);
993 assert(n->Children[0]->Store->Index >= 0);
994 assert(n->Children[0]->Store->Index < 16);
995 storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask);
996 storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store);
997 dstAnnot = storage_annotation(n->Children[0], prog);
998 srcAnnot = storage_annotation(n->Children[1], prog);
999 inst->Comment = instruction_annotation(inst->Opcode, dstAnnot,
1000 srcAnnot, NULL, NULL);
1001 }
1002 free_temp_storage(vt, n->Children[1]);
1003 return inst;
1004 }
1005 }
1006
1007
1008 static struct prog_instruction *
1009 emit_cond(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
1010 {
1011 /* Conditional expression (in if/while/for stmts).
1012 * Need to update condition code register.
1013 * Next instruction is typically an IR_CJUMP0/1.
1014 */
1015 /* last child expr instruction: */
1016 struct prog_instruction *inst = emit(vt, n->Children[0], prog);
1017 if (inst) {
1018 /* set inst's CondUpdate flag */
1019 inst->CondUpdate = GL_TRUE;
1020 return inst; /* XXX or null? */
1021 }
1022 else {
1023 /* This'll happen for things like "if (i) ..." where no code
1024 * is normally generated for the expression "i".
1025 * Generate a move instruction just to set condition codes.
1026 * Note: must use full 4-component vector since all four
1027 * condition codes must be set identically.
1028 */
1029 if (!alloc_temp_storage(vt, n, 4))
1030 return NULL;
1031 inst = new_instruction(prog, OPCODE_MOV);
1032 inst->CondUpdate = GL_TRUE;
1033 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
1034 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
1035 _slang_free_temp(vt, n->Store);
1036 inst->Comment = _mesa_strdup("COND expr");
1037 return inst; /* XXX or null? */
1038 }
1039 }
1040
1041
1042 /**
1043 * Logical-NOT
1044 */
1045 static struct prog_instruction *
1046 emit_not(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
1047 {
1048 GLfloat zero = 0.0;
1049 slang_ir_storage st;
1050 struct prog_instruction *inst;
1051
1052 /* need zero constant */
1053 st.File = PROGRAM_CONSTANT;
1054 st.Size = 1;
1055 st.Index = _mesa_add_unnamed_constant(prog->Parameters, &zero,
1056 1, &st.Swizzle);
1057
1058 /* child expr */
1059 (void) emit(vt, n->Children[0], prog);
1060 /* XXXX if child instr is SGT convert to SLE, if SEQ, SNE, etc */
1061
1062 if (!n->Store)
1063 if (!alloc_temp_storage(vt, n, n->Children[0]->Store->Size))
1064 return NULL;
1065
1066 inst = new_instruction(prog, OPCODE_SEQ);
1067 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
1068 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
1069 storage_to_src_reg(&inst->SrcReg[1], &st);
1070
1071 free_temp_storage(vt, n->Children[0]);
1072
1073 inst->Comment = _mesa_strdup("NOT");
1074 return inst;
1075 }
1076
1077
1078 static struct prog_instruction *
1079 emit_if(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
1080 {
1081 struct prog_instruction *ifInst;
1082 GLuint ifInstLoc, elseInstLoc;
1083
1084 emit(vt, n->Children[0], prog); /* the condition */
1085 ifInstLoc = prog->NumInstructions;
1086 if (EmitHighLevelInstructions) {
1087 ifInst = new_instruction(prog, OPCODE_IF);
1088 ifInst->DstReg.CondMask = COND_NE; /* if cond is non-zero */
1089 ifInst->DstReg.CondSwizzle = SWIZZLE_X;
1090 }
1091 else {
1092 /* conditional jump to else, or endif */
1093 ifInst = new_instruction(prog, OPCODE_BRA);
1094 ifInst->DstReg.CondMask = COND_EQ; /* BRA if cond is zero */
1095 ifInst->DstReg.CondSwizzle = SWIZZLE_X;
1096 ifInst->Comment = _mesa_strdup("if zero");
1097 }
1098
1099 /* if body */
1100 emit(vt, n->Children[1], prog);
1101
1102 if (n->Children[2]) {
1103 /* have else body */
1104 elseInstLoc = prog->NumInstructions;
1105 if (EmitHighLevelInstructions) {
1106 (void) new_instruction(prog, OPCODE_ELSE);
1107 }
1108 else {
1109 /* jump to endif instruction */
1110 struct prog_instruction *inst;
1111 inst = new_instruction(prog, OPCODE_BRA);
1112 inst->Comment = _mesa_strdup("else");
1113 inst->DstReg.CondMask = COND_TR; /* always branch */
1114 }
1115 ifInst = prog->Instructions + ifInstLoc;
1116 ifInst->BranchTarget = prog->NumInstructions;
1117
1118 emit(vt, n->Children[2], prog);
1119 }
1120 else {
1121 /* no else body */
1122 ifInst = prog->Instructions + ifInstLoc;
1123 ifInst->BranchTarget = prog->NumInstructions + 1;
1124 }
1125
1126 if (EmitHighLevelInstructions) {
1127 (void) new_instruction(prog, OPCODE_ENDIF);
1128 }
1129
1130 if (n->Children[2]) {
1131 struct prog_instruction *elseInst;
1132 elseInst = prog->Instructions + elseInstLoc;
1133 elseInst->BranchTarget = prog->NumInstructions;
1134 }
1135 return NULL;
1136 }
1137
1138
1139 static struct prog_instruction *
1140 emit_loop(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
1141 {
1142 struct prog_instruction *beginInst, *endInst;
1143 GLuint beginInstLoc, endInstLoc;
1144 slang_ir_node *ir;
1145
1146 /* emit OPCODE_BGNLOOP */
1147 beginInstLoc = prog->NumInstructions;
1148 if (EmitHighLevelInstructions) {
1149 (void) new_instruction(prog, OPCODE_BGNLOOP);
1150 }
1151
1152 /* body */
1153 emit(vt, n->Children[0], prog);
1154
1155 endInstLoc = prog->NumInstructions;
1156 if (EmitHighLevelInstructions) {
1157 /* emit OPCODE_ENDLOOP */
1158 endInst = new_instruction(prog, OPCODE_ENDLOOP);
1159 }
1160 else {
1161 /* emit unconditional BRA-nch */
1162 endInst = new_instruction(prog, OPCODE_BRA);
1163 endInst->DstReg.CondMask = COND_TR; /* always true */
1164 }
1165 /* end instruction's BranchTarget points to top of loop */
1166 endInst->BranchTarget = beginInstLoc;
1167
1168 if (EmitHighLevelInstructions) {
1169 /* BGNLOOP's BranchTarget points to the ENDLOOP inst */
1170 beginInst = prog->Instructions + beginInstLoc;
1171 beginInst->BranchTarget = prog->NumInstructions - 1;
1172 }
1173
1174 /* Done emitting loop code. Now walk over the loop's linked list of
1175 * BREAK and CONT nodes, filling in their BranchTarget fields (which
1176 * will point to the ENDLOOP+1 or BGNLOOP instructions, respectively).
1177 */
1178 for (ir = n->BranchNode; ir; ir = ir->BranchNode) {
1179 struct prog_instruction *inst = prog->Instructions + ir->InstLocation;
1180 assert(inst->BranchTarget < 0);
1181 if (ir->Opcode == IR_BREAK ||
1182 ir->Opcode == IR_BREAK_IF_FALSE ||
1183 ir->Opcode == IR_BREAK_IF_TRUE) {
1184 assert(inst->Opcode == OPCODE_BRK ||
1185 inst->Opcode == OPCODE_BRA);
1186 /* go to instruction after end of loop */
1187 inst->BranchTarget = endInstLoc + 1;
1188 }
1189 else {
1190 assert(ir->Opcode == IR_CONT ||
1191 ir->Opcode == IR_CONT_IF_FALSE ||
1192 ir->Opcode == IR_CONT_IF_TRUE);
1193 assert(inst->Opcode == OPCODE_CONT ||
1194 inst->Opcode == OPCODE_BRA);
1195 /* to go instruction at top of loop */
1196 inst->BranchTarget = beginInstLoc;
1197 }
1198 }
1199 return NULL;
1200 }
1201
1202
1203 /**
1204 * "Continue" or "break" statement.
1205 * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted.
1206 */
1207 static struct prog_instruction *
1208 emit_cont_break(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
1209 {
1210 gl_inst_opcode opcode;
1211 struct prog_instruction *inst;
1212 n->InstLocation = prog->NumInstructions;
1213 if (EmitHighLevelInstructions) {
1214 opcode = (n->Opcode == IR_CONT) ? OPCODE_CONT : OPCODE_BRK;
1215 }
1216 else {
1217 opcode = OPCODE_BRA;
1218 }
1219 inst = new_instruction(prog, opcode);
1220 inst->DstReg.CondMask = COND_TR; /* always true */
1221 return inst;
1222 }
1223
1224
1225 /**
1226 * Conditional "continue" or "break" statement.
1227 * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted.
1228 */
1229 static struct prog_instruction *
1230 emit_cont_break_if(slang_var_table *vt, slang_ir_node *n,
1231 struct gl_program *prog, GLboolean breakTrue)
1232 {
1233 gl_inst_opcode opcode;
1234 struct prog_instruction *inst;
1235
1236 /* evaluate condition expr, setting cond codes */
1237 inst = emit(vt, n->Children[0], prog);
1238 assert(inst);
1239 inst->CondUpdate = GL_TRUE;
1240
1241 n->InstLocation = prog->NumInstructions;
1242 if (EmitHighLevelInstructions) {
1243 if (n->Opcode == IR_CONT_IF_TRUE ||
1244 n->Opcode == IR_CONT_IF_FALSE)
1245 opcode = OPCODE_CONT;
1246 else
1247 opcode = OPCODE_BRK;
1248 }
1249 else {
1250 opcode = OPCODE_BRA;
1251 }
1252 inst = new_instruction(prog, opcode);
1253 inst->DstReg.CondMask = breakTrue ? COND_NE : COND_EQ;
1254 return inst;
1255 }
1256
1257
1258
1259 /**
1260 * Remove any SWIZZLE_NIL terms from given swizzle mask (smear prev term).
1261 * Ex: fix_swizzle("zyNN") -> "zyyy"
1262 */
1263 static GLuint
1264 fix_swizzle(GLuint swizzle)
1265 {
1266 GLuint swz[4], i;
1267 for (i = 0; i < 4; i++) {
1268 swz[i] = GET_SWZ(swizzle, i);
1269 if (swz[i] == SWIZZLE_NIL) {
1270 swz[i] = swz[i - 1];
1271 }
1272 }
1273 return MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
1274 }
1275
1276
1277 static struct prog_instruction *
1278 emit_swizzle(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
1279 {
1280 GLuint swizzle;
1281
1282 /* swizzled storage access */
1283 (void) emit(vt, n->Children[0], prog);
1284
1285 /* "pull-up" the child's storage info, applying our swizzle info */
1286 n->Store->File = n->Children[0]->Store->File;
1287 n->Store->Index = n->Children[0]->Store->Index;
1288 n->Store->Size = n->Children[0]->Store->Size;
1289 /*n->Var = n->Children[0]->Var; XXX for debug */
1290 assert(n->Store->Index >= 0);
1291
1292 swizzle = fix_swizzle(n->Store->Swizzle);
1293 #ifdef DEBUG
1294 {
1295 GLuint s = n->Children[0]->Store->Swizzle;
1296 assert(GET_SWZ(s, 0) != SWIZZLE_NIL);
1297 assert(GET_SWZ(s, 1) != SWIZZLE_NIL);
1298 assert(GET_SWZ(s, 2) != SWIZZLE_NIL);
1299 assert(GET_SWZ(s, 3) != SWIZZLE_NIL);
1300 }
1301 #endif
1302
1303 /* apply this swizzle to child's swizzle to get composed swizzle */
1304 n->Store->Swizzle = swizzle_swizzle(n->Children[0]->Store->Swizzle,
1305 swizzle);
1306 return NULL;
1307 }
1308
1309
1310 static struct prog_instruction *
1311 emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
1312 {
1313 struct prog_instruction *inst;
1314 if (!n)
1315 return NULL;
1316
1317 switch (n->Opcode) {
1318 case IR_SEQ:
1319 /* sequence of two sub-trees */
1320 assert(n->Children[0]);
1321 assert(n->Children[1]);
1322 emit(vt, n->Children[0], prog);
1323 inst = emit(vt, n->Children[1], prog);
1324 assert(!n->Store);
1325 n->Store = n->Children[1]->Store;
1326 return inst;
1327
1328 case IR_SCOPE:
1329 /* new variable scope */
1330 _slang_push_var_table(vt);
1331 inst = emit(vt, n->Children[0], prog);
1332 _slang_pop_var_table(vt);
1333 return inst;
1334
1335 case IR_VAR_DECL:
1336 /* Variable declaration - allocate a register for it */
1337 assert(n->Store);
1338 assert(n->Store->File != PROGRAM_UNDEFINED);
1339 assert(n->Store->Size > 0);
1340 assert(n->Store->Index < 0);
1341 if (!n->Var || n->Var->isTemp) {
1342 /* a nameless/temporary variable, will be freed after first use */
1343 if (!_slang_alloc_temp(vt, n->Store))
1344 RETURN_ERROR("Ran out of registers, too many temporaries", 0);
1345 }
1346 else {
1347 /* a regular variable */
1348 _slang_add_variable(vt, n->Var);
1349 if (!_slang_alloc_var(vt, n->Store))
1350 RETURN_ERROR("Ran out of registers, too many variables", 0);
1351 /*
1352 printf("IR_VAR_DECL %s %d store %p\n",
1353 (char*) n->Var->a_name, n->Store->Index, (void*) n->Store);
1354 */
1355 assert(n->Var->aux == n->Store);
1356 }
1357 break;
1358
1359 case IR_VAR:
1360 /* Reference to a variable
1361 * Storage should have already been resolved/allocated.
1362 */
1363 assert(n->Store);
1364 assert(n->Store->File != PROGRAM_UNDEFINED);
1365 if (n->Store->Index < 0) {
1366 printf("#### VAR %s not allocated!\n", (char*)n->Var->a_name);
1367 }
1368 assert(n->Store->Index >= 0);
1369 assert(n->Store->Size > 0);
1370 break;
1371
1372 case IR_ELEMENT:
1373 /* Dereference array element. Just resolve storage for the array
1374 * element represented by this node.
1375 */
1376 assert(n->Store);
1377 assert(n->Store->File != PROGRAM_UNDEFINED);
1378 assert(n->Store->Size > 0);
1379 if (n->Children[1]->Opcode == IR_FLOAT) {
1380 /* OK, constant index */
1381 const GLint arrayAddr = n->Children[0]->Store->Index;
1382 const GLint index = (GLint) n->Children[1]->Value[0];
1383 n->Store->Index = arrayAddr + index;
1384 }
1385 else {
1386 /* Problem: variable index */
1387 const GLint arrayAddr = n->Children[0]->Store->Index;
1388 const GLint index = 0;
1389 _mesa_problem(NULL, "variable array indexes not supported yet!");
1390 n->Store->Index = arrayAddr + index;
1391 }
1392 return NULL; /* no instruction */
1393
1394 case IR_SWIZZLE:
1395 return emit_swizzle(vt, n, prog);
1396
1397 /* Simple arithmetic */
1398 /* unary */
1399 case IR_RSQ:
1400 case IR_RCP:
1401 case IR_FLOOR:
1402 case IR_FRAC:
1403 case IR_F_TO_I:
1404 case IR_I_TO_F:
1405 case IR_ABS:
1406 case IR_SIN:
1407 case IR_COS:
1408 case IR_DDX:
1409 case IR_DDY:
1410 case IR_NOISE1:
1411 case IR_NOISE2:
1412 case IR_NOISE3:
1413 case IR_NOISE4:
1414 /* binary */
1415 case IR_ADD:
1416 case IR_SUB:
1417 case IR_MUL:
1418 case IR_DOT4:
1419 case IR_DOT3:
1420 case IR_CROSS:
1421 case IR_MIN:
1422 case IR_MAX:
1423 case IR_SEQUAL:
1424 case IR_SNEQUAL:
1425 case IR_SGE:
1426 case IR_SGT:
1427 case IR_POW:
1428 case IR_EXP:
1429 case IR_EXP2:
1430 /* trinary operators */
1431 case IR_LRP:
1432 return emit_arith(vt, n, prog);
1433 case IR_CLAMP:
1434 return emit_clamp(vt, n, prog);
1435 case IR_TEX:
1436 case IR_TEXB:
1437 case IR_TEXP:
1438 return emit_tex(vt, n, prog);
1439 case IR_NEG:
1440 return emit_negation(vt, n, prog);
1441 case IR_FLOAT:
1442 /* find storage location for this float constant */
1443 n->Store->Index = _mesa_add_unnamed_constant(prog->Parameters, n->Value,
1444 n->Store->Size,
1445 &n->Store->Swizzle);
1446 if (n->Store->Index < 0) {
1447 RETURN_ERROR("Ran out of space for constants.", 0);
1448 }
1449 return NULL;
1450
1451 case IR_MOVE:
1452 return emit_move(vt, n, prog);
1453
1454 case IR_COND:
1455 return emit_cond(vt, n, prog);
1456
1457 case IR_NOT:
1458 return emit_not(vt, n, prog);
1459
1460 case IR_LABEL:
1461 return emit_label(n->Target, prog);
1462 case IR_JUMP:
1463 return emit_jump(n->Target, prog);
1464 case IR_CJUMP0:
1465 return emit_cjump(n->Target, prog, 0);
1466 case IR_CJUMP1:
1467 return emit_cjump(n->Target, prog, 1);
1468 case IR_KILL:
1469 return emit_kill(prog);
1470
1471 case IR_IF:
1472 return emit_if(vt, n, prog);
1473
1474 case IR_LOOP:
1475 return emit_loop(vt, n, prog);
1476 case IR_BREAK_IF_FALSE:
1477 case IR_CONT_IF_FALSE:
1478 return emit_cont_break_if(vt, n, prog, GL_FALSE);
1479 case IR_BREAK_IF_TRUE:
1480 case IR_CONT_IF_TRUE:
1481 return emit_cont_break_if(vt, n, prog, GL_TRUE);
1482 case IR_BREAK:
1483 /* fall-through */
1484 case IR_CONT:
1485 return emit_cont_break(vt, n, prog);
1486
1487 case IR_BEGIN_SUB:
1488 return new_instruction(prog, OPCODE_BGNSUB);
1489 case IR_END_SUB:
1490 return new_instruction(prog, OPCODE_ENDSUB);
1491 case IR_RETURN:
1492 return new_instruction(prog, OPCODE_RET);
1493
1494 case IR_NOP:
1495 return NULL;
1496
1497 default:
1498 _mesa_problem(NULL, "Unexpected IR opcode in emit()\n");
1499 abort();
1500 }
1501 return NULL;
1502 }
1503
1504
1505 GLboolean
1506 _slang_emit_code(slang_ir_node *n, slang_var_table *vt,
1507 struct gl_program *prog, GLboolean withEnd)
1508 {
1509 GLboolean success;
1510
1511 if (emit(vt, n, prog)) {
1512 /* finish up by adding the END opcode to program */
1513 if (withEnd) {
1514 struct prog_instruction *inst;
1515 inst = new_instruction(prog, OPCODE_END);
1516 }
1517 success = GL_TRUE;
1518 }
1519 else {
1520 /* record an error? */
1521 success = GL_FALSE;
1522 }
1523
1524 printf("*********** End generate code (%u inst):\n", prog->NumInstructions);
1525 #if 0
1526 _mesa_print_program(prog);
1527 _mesa_print_program_parameters(ctx,prog);
1528 #endif
1529
1530 return success;
1531 }