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