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