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