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