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