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