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