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