minor 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 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_MIN, "IR_MIN", OPCODE_MIN, 4, 2 },
69 { IR_MAX, "IR_MAX", OPCODE_MAX, 4, 2 },
70 { IR_SEQUAL, "IR_SEQUAL", OPCODE_SEQ, 4, 2 },
71 { IR_SNEQUAL, "IR_SNEQUAL", OPCODE_SNE, 4, 2 },
72 { IR_SGE, "IR_SGE", OPCODE_SGE, 4, 2 },
73 { IR_SGT, "IR_SGT", OPCODE_SGT, 4, 2 },
74 { IR_POW, "IR_POW", OPCODE_POW, 1, 2 },
75 /* unary ops */
76 { IR_I_TO_F, "IR_I_TO_F", OPCODE_NOP, 1, 1 },
77 { IR_F_TO_I, "IR_F_TO_I", OPCODE_INT, 4, 1 }, /* 4 floats to 4 ints */
78 { IR_EXP, "IR_EXP", OPCODE_EXP, 1, 1 },
79 { IR_EXP2, "IR_EXP2", OPCODE_EX2, 1, 1 },
80 { IR_LOG2, "IR_LOG2", OPCODE_LG2, 1, 1 },
81 { IR_RSQ, "IR_RSQ", OPCODE_RSQ, 1, 1 },
82 { IR_RCP, "IR_RCP", OPCODE_RCP, 1, 1 },
83 { IR_FLOOR, "IR_FLOOR", OPCODE_FLR, 4, 1 },
84 { IR_FRAC, "IR_FRAC", OPCODE_FRC, 4, 1 },
85 { IR_ABS, "IR_ABS", OPCODE_ABS, 4, 1 },
86 { IR_NEG, "IR_NEG", OPCODE_NOP/*spec case*/, 4, 1 },
87 { IR_DDX, "IR_DDX", OPCODE_DDX, 4, 1 },
88 { IR_DDX, "IR_DDY", OPCODE_DDX, 4, 1 },
89 { IR_SIN, "IR_SIN", OPCODE_SIN, 1, 1 },
90 { IR_COS, "IR_COS", OPCODE_COS, 1, 1 },
91 /* other */
92 { IR_SEQ, "IR_SEQ", OPCODE_NOP, 0, 0 },
93 { IR_SCOPE, "IR_SCOPE", OPCODE_NOP, 0, 0 },
94 { IR_LABEL, "IR_LABEL", OPCODE_NOP, 0, 0 },
95 { IR_JUMP, "IR_JUMP", OPCODE_NOP, 0, 0 },
96 { IR_CJUMP0, "IR_CJUMP0", OPCODE_NOP, 0, 0 },
97 { IR_CJUMP1, "IR_CJUMP1", OPCODE_NOP, 0, 0 },
98 { IR_IF, "IR_IF", OPCODE_NOP, 0, 0 },
99 { IR_ELSE, "IR_ELSE", OPCODE_NOP, 0, 0 },
100 { IR_ENDIF, "IR_ENDIF", OPCODE_NOP, 0, 0 },
101 { IR_KILL, "IR_KILL", OPCODE_NOP, 0, 0 },
102 { IR_COND, "IR_COND", OPCODE_NOP, 0, 0 },
103 { IR_CALL, "IR_CALL", OPCODE_NOP, 0, 0 },
104 { IR_MOVE, "IR_MOVE", OPCODE_NOP, 0, 1 },
105 { IR_NOT, "IR_NOT", OPCODE_NOP, 1, 1 },
106 { IR_VAR, "IR_VAR", OPCODE_NOP, 0, 0 },
107 { IR_VAR_DECL, "IR_VAR_DECL", OPCODE_NOP, 0, 0 },
108 { IR_TEX, "IR_TEX", OPCODE_TEX, 4, 1 },
109 { IR_TEXB, "IR_TEXB", OPCODE_TXB, 4, 1 },
110 { IR_TEXP, "IR_TEXP", OPCODE_TXP, 4, 1 },
111 { IR_FLOAT, "IR_FLOAT", OPCODE_NOP, 0, 0 },
112 { IR_FIELD, "IR_FIELD", OPCODE_NOP, 0, 0 },
113 { IR_ELEMENT, "IR_ELEMENT", OPCODE_NOP, 0, 0 },
114 { IR_SWIZZLE, "IR_SWIZZLE", OPCODE_NOP, 0, 0 },
115 { IR_NOP, NULL, OPCODE_NOP, 0, 0 }
116 };
117
118
119 static slang_ir_info *
120 slang_find_ir_info(slang_ir_opcode opcode)
121 {
122 GLuint i;
123 for (i = 0; IrInfo[i].IrName; i++) {
124 if (IrInfo[i].IrOpcode == opcode) {
125 return IrInfo + i;
126 }
127 }
128 return NULL;
129 }
130
131 static const char *
132 slang_ir_name(slang_ir_opcode opcode)
133 {
134 return slang_find_ir_info(opcode)->IrName;
135 }
136
137
138 /**
139 * Swizzle a swizzle. That is, return swz2(swz1)
140 */
141 static GLuint
142 swizzle_swizzle(GLuint swz1, GLuint swz2)
143 {
144 GLuint i, swz, s[4];
145 for (i = 0; i < 4; i++) {
146 GLuint c = GET_SWZ(swz2, i);
147 s[i] = GET_SWZ(swz1, c);
148 }
149 swz = MAKE_SWIZZLE4(s[0], s[1], s[2], s[3]);
150 return swz;
151 }
152
153
154 slang_ir_storage *
155 _slang_new_ir_storage(enum register_file file, GLint index, GLint size)
156 {
157 slang_ir_storage *st;
158 st = (slang_ir_storage *) _mesa_calloc(sizeof(slang_ir_storage));
159 if (st) {
160 st->File = file;
161 st->Index = index;
162 st->Size = size;
163 st->Swizzle = SWIZZLE_NOOP;
164 }
165 return st;
166 }
167
168
169 static const char *
170 swizzle_string(GLuint swizzle)
171 {
172 static char s[6];
173 GLuint i;
174 s[0] = '.';
175 for (i = 1; i < 5; i++) {
176 s[i] = "xyzw"[GET_SWZ(swizzle, i-1)];
177 }
178 s[i] = 0;
179 return s;
180 }
181
182 static const char *
183 writemask_string(GLuint writemask)
184 {
185 static char s[6];
186 GLuint i, j = 0;
187 s[j++] = '.';
188 for (i = 0; i < 4; i++) {
189 if (writemask & (1 << i))
190 s[j++] = "xyzw"[i];
191 }
192 s[j] = 0;
193 return s;
194 }
195
196 static const char *
197 storage_string(const slang_ir_storage *st)
198 {
199 static const char *files[] = {
200 "TEMP",
201 "LOCAL_PARAM",
202 "ENV_PARAM",
203 "STATE",
204 "INPUT",
205 "OUTPUT",
206 "NAMED_PARAM",
207 "CONSTANT",
208 "UNIFORM",
209 "WRITE_ONLY",
210 "ADDRESS",
211 "SAMPLER",
212 "UNDEFINED"
213 };
214 static char s[100];
215 #if 0
216 if (st->Size == 1)
217 sprintf(s, "%s[%d]", files[st->File], st->Index);
218 else
219 sprintf(s, "%s[%d..%d]", files[st->File], st->Index,
220 st->Index + st->Size - 1);
221 #endif
222 assert(st->File < (GLint) (sizeof(files) / sizeof(files[0])));
223 sprintf(s, "%s[%d]", files[st->File], st->Index);
224 return s;
225 }
226
227
228 #define IND 0
229 void
230 slang_print_ir(const slang_ir_node *n, int indent)
231 {
232 int i;
233 if (!n)
234 return;
235 #if !IND
236 if (n->Opcode != IR_SEQ)
237 #else
238 printf("%3d:", indent);
239 #endif
240 for (i = 0; i < indent; i++)
241 printf(" ");
242
243 switch (n->Opcode) {
244 case IR_SEQ:
245 #if IND
246 printf("SEQ at %p\n", (void*) n);
247 #endif
248 assert(n->Children[0]);
249 assert(n->Children[1]);
250 slang_print_ir(n->Children[0], indent + IND);
251 slang_print_ir(n->Children[1], indent + IND);
252 break;
253 case IR_SCOPE:
254 printf("NEW SCOPE\n");
255 assert(!n->Children[1]);
256 slang_print_ir(n->Children[0], indent + 3);
257 break;
258 case IR_MOVE:
259 printf("MOVE (writemask = %s)\n", writemask_string(n->Writemask));
260 slang_print_ir(n->Children[0], indent+3);
261 slang_print_ir(n->Children[1], indent+3);
262 break;
263 case IR_LABEL:
264 printf("LABEL: %s\n", n->Target);
265 break;
266 case IR_COND:
267 printf("COND\n");
268 slang_print_ir(n->Children[0], indent + 3);
269 break;
270 case IR_JUMP:
271 printf("JUMP %s\n", n->Target);
272 break;
273 case IR_CJUMP0:
274 printf("CJUMP0 %s\n", n->Target);
275 slang_print_ir(n->Children[0], indent+3);
276 break;
277 case IR_CJUMP1:
278 printf("CJUMP1 %s\n", n->Target);
279 slang_print_ir(n->Children[0], indent+3);
280 break;
281
282 case IR_IF:
283 printf("IF \n");
284 slang_print_ir(n->Children[0], indent+3);
285 break;
286 case IR_ELSE:
287 printf("ELSE\n");
288 break;
289 case IR_ENDIF:
290 printf("ENDIF\n");
291 break;
292
293 case IR_VAR:
294 printf("VAR %s%s at %s store %p\n",
295 (char *) n->Var->a_name, swizzle_string(n->Store->Swizzle),
296 storage_string(n->Store), (void*) n->Store);
297 break;
298 case IR_VAR_DECL:
299 printf("VAR_DECL %s (%p) at %s store %p\n",
300 (char *) n->Var->a_name, (void*) n->Var, storage_string(n->Store),
301 (void*) n->Store);
302 break;
303 case IR_FIELD:
304 printf("FIELD %s of\n", n->Target);
305 slang_print_ir(n->Children[0], indent+3);
306 break;
307 case IR_CALL:
308 printf("ASMCALL %s(%d args)\n", n->Target, 0/*XXX*/);
309 break;
310 case IR_FLOAT:
311 printf("FLOAT %f %f %f %f\n",
312 n->Value[0], n->Value[1], n->Value[2], n->Value[3]);
313 break;
314 case IR_I_TO_F:
315 printf("INT_TO_FLOAT %d\n", (int) n->Value[0]);
316 break;
317 case IR_SWIZZLE:
318 printf("SWIZZLE %s of (store %p) \n",
319 swizzle_string(n->Store->Swizzle), (void*) n->Store);
320 slang_print_ir(n->Children[0], indent + 3);
321 break;
322 default:
323 printf("%s (%p, %p) (store %p)\n", slang_ir_name(n->Opcode),
324 (void*) n->Children[0], (void*) n->Children[1], (void*) n->Store);
325 slang_print_ir(n->Children[0], indent+3);
326 slang_print_ir(n->Children[1], indent+3);
327 }
328 }
329
330
331 /**
332 * Allocate temporary storage for an intermediate result (such as for
333 * a multiply or add, etc.
334 */
335 static void
336 alloc_temp_storage(slang_var_table *vt, slang_ir_node *n, GLint size)
337 {
338 assert(!n->Var);
339 assert(!n->Store);
340 assert(size > 0);
341 n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, size);
342 (void) _slang_alloc_temp(vt, n->Store);
343 }
344
345
346 /**
347 * Free temporary storage, if n->Store is, in fact, temp storage.
348 * Otherwise, no-op.
349 */
350 static void
351 free_temp_storage(slang_var_table *vt, slang_ir_node *n)
352 {
353 if (n->Store->File == PROGRAM_TEMPORARY && n->Store->Index >= 0) {
354 if (_slang_is_temp(vt, n->Store)) {
355 _slang_free_temp(vt, n->Store);
356 n->Store->Index = -1;
357 n->Store->Size = -1;
358 }
359 }
360 }
361
362
363 /**
364 * Convert IR storage to an instruction dst register.
365 */
366 static void
367 storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st,
368 GLuint writemask)
369 {
370 static const GLuint defaultWritemask[4] = {
371 WRITEMASK_X,
372 WRITEMASK_X | WRITEMASK_Y,
373 WRITEMASK_X | WRITEMASK_Y | WRITEMASK_Z,
374 WRITEMASK_X | WRITEMASK_Y | WRITEMASK_Z | WRITEMASK_W
375 };
376 assert(st->Index >= 0 && st->Index <= 16);
377 dst->File = st->File;
378 dst->Index = st->Index;
379 assert(st->File != PROGRAM_UNDEFINED);
380 assert(st->Size >= 1);
381 assert(st->Size <= 4);
382 if (st->Size == 1) {
383 GLuint comp = GET_SWZ(st->Swizzle, 0);
384 assert(comp < 4);
385 assert(writemask & WRITEMASK_X);
386 dst->WriteMask = WRITEMASK_X << comp;
387 }
388 else {
389 dst->WriteMask = defaultWritemask[st->Size - 1] & writemask;
390 }
391 }
392
393
394 /**
395 * Convert IR storage to an instruction src register.
396 */
397 static void
398 storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st)
399 {
400 static const GLuint defaultSwizzle[4] = {
401 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X),
402 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
403 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
404 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W)
405 };
406 assert(st->File >= 0 && st->File <= 16);
407 src->File = st->File;
408 src->Index = st->Index;
409 assert(st->File != PROGRAM_UNDEFINED);
410 assert(st->Size >= 1);
411 assert(st->Size <= 4);
412 if (st->Swizzle != SWIZZLE_NOOP)
413 src->Swizzle = st->Swizzle;
414 else
415 src->Swizzle = defaultSwizzle[st->Size - 1];
416 }
417
418
419
420 /**
421 * Add new instruction at end of given program.
422 * \param prog the program to append instruction onto
423 * \param opcode opcode for the new instruction
424 * \return pointer to the new instruction
425 */
426 static struct prog_instruction *
427 new_instruction(struct gl_program *prog, gl_inst_opcode opcode)
428 {
429 struct prog_instruction *inst;
430 prog->Instructions = _mesa_realloc_instructions(prog->Instructions,
431 prog->NumInstructions,
432 prog->NumInstructions + 1);
433 inst = prog->Instructions + prog->NumInstructions;
434 prog->NumInstructions++;
435 _mesa_init_instructions(inst, 1);
436 inst->Opcode = opcode;
437 return inst;
438 }
439
440
441 static struct prog_instruction *
442 emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog);
443
444
445 /**
446 * Return an annotation string for given node's storage.
447 */
448 static char *
449 storage_annotation(const slang_ir_node *n, const struct gl_program *prog)
450 {
451 #if ANNOTATE
452 const slang_ir_storage *st = n->Store;
453 static char s[100] = "";
454
455 if (!st)
456 return _mesa_strdup("");
457
458 switch (st->File) {
459 case PROGRAM_CONSTANT:
460 if (st->Index >= 0) {
461 const GLfloat *val = prog->Parameters->ParameterValues[st->Index];
462 if (st->Swizzle == SWIZZLE_NOOP)
463 sprintf(s, "{%f, %f, %f, %f}", val[0], val[1], val[2], val[3]);
464 else {
465 sprintf(s, "%f", val[GET_SWZ(st->Swizzle, 0)]);
466 }
467 }
468 break;
469 case PROGRAM_TEMPORARY:
470 if (n->Var)
471 sprintf(s, "%s", (char *) n->Var->a_name);
472 else
473 sprintf(s, "t[%d]", st->Index);
474 break;
475 case PROGRAM_STATE_VAR:
476 case PROGRAM_UNIFORM:
477 sprintf(s, "%s", prog->Parameters->Parameters[st->Index].Name);
478 break;
479 case PROGRAM_VARYING:
480 sprintf(s, "%s", prog->Varying->Parameters[st->Index].Name);
481 break;
482 case PROGRAM_INPUT:
483 sprintf(s, "input[%d]", st->Index);
484 break;
485 case PROGRAM_OUTPUT:
486 sprintf(s, "output[%d]", st->Index);
487 break;
488 default:
489 s[0] = 0;
490 }
491 return _mesa_strdup(s);
492 #else
493 return NULL;
494 #endif
495 }
496
497
498 /**
499 * Return an annotation string for an instruction.
500 */
501 static char *
502 instruction_annotation(gl_inst_opcode opcode,
503 char *dstAnnot, char *srcAnnot0, char *srcAnnot1)
504 {
505 #if ANNOTATE
506 const char *operator;
507 char *s;
508 int len = 50;
509
510 if (dstAnnot)
511 len += strlen(dstAnnot);
512 else
513 dstAnnot = _mesa_strdup("");
514
515 if (srcAnnot0)
516 len += strlen(srcAnnot0);
517 else
518 srcAnnot0 = _mesa_strdup("");
519
520 if (srcAnnot1)
521 len += strlen(srcAnnot1);
522 else
523 srcAnnot1 = _mesa_strdup("");
524
525 switch (opcode) {
526 case OPCODE_ADD:
527 operator = "+";
528 break;
529 case OPCODE_SUB:
530 operator = "-";
531 break;
532 case OPCODE_MUL:
533 operator = "*";
534 break;
535 case OPCODE_DP3:
536 operator = "DP3";
537 break;
538 case OPCODE_DP4:
539 operator = "DP4";
540 break;
541 case OPCODE_XPD:
542 operator = "XPD";
543 break;
544 case OPCODE_RSQ:
545 operator = "RSQ";
546 break;
547 case OPCODE_SGT:
548 operator = ">";
549 break;
550 default:
551 operator = ",";
552 }
553
554 s = (char *) malloc(len);
555 sprintf(s, "%s = %s %s %s", dstAnnot, srcAnnot0, operator, srcAnnot1);
556 assert(_mesa_strlen(s) < len);
557
558 free(dstAnnot);
559 free(srcAnnot0);
560 free(srcAnnot1);
561
562 return s;
563 #else
564 return NULL;
565 #endif
566 }
567
568
569
570 /**
571 * Generate code for a simple binary-op instruction.
572 */
573 static struct prog_instruction *
574 emit_binop(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
575 {
576 struct prog_instruction *inst;
577 const slang_ir_info *info = slang_find_ir_info(n->Opcode);
578 char *srcAnnot0 = NULL, *srcAnnot1 = NULL, *dstAnnot = NULL;
579
580 assert(info);
581 assert(info->InstOpcode != OPCODE_NOP);
582
583 #if PEEPHOLE_OPTIMIZATIONS
584 /* Look for MAD opportunity */
585 if (n->Opcode == IR_ADD && n->Children[0]->Opcode == IR_MUL) {
586 /* found pattern IR_ADD(IR_MUL(A, B), C) */
587 emit(vt, n->Children[0]->Children[0], prog); /* A */
588 emit(vt, n->Children[0]->Children[1], prog); /* B */
589 emit(vt, n->Children[1], prog); /* C */
590 /* generate MAD instruction */
591 inst = new_instruction(prog, OPCODE_MAD);
592 /* operands: A, B, C: */
593 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Children[0]->Store);
594 storage_to_src_reg(&inst->SrcReg[1], n->Children[0]->Children[1]->Store);
595 storage_to_src_reg(&inst->SrcReg[2], n->Children[1]->Store);
596 free_temp_storage(vt, n->Children[0]->Children[0]);
597 free_temp_storage(vt, n->Children[0]->Children[1]);
598 free_temp_storage(vt, n->Children[1]);
599 }
600 else if (n->Opcode == IR_ADD && n->Children[1]->Opcode == IR_MUL) {
601 /* found pattern IR_ADD(A, IR_MUL(B, C)) */
602 emit(vt, n->Children[0], prog); /* A */
603 emit(vt, n->Children[1]->Children[0], prog); /* B */
604 emit(vt, n->Children[1]->Children[1], prog); /* C */
605 /* generate MAD instruction */
606 inst = new_instruction(prog, OPCODE_MAD);
607 /* operands: B, C, A */
608 storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Children[0]->Store);
609 storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Children[1]->Store);
610 storage_to_src_reg(&inst->SrcReg[2], n->Children[0]->Store);
611 free_temp_storage(vt, n->Children[1]->Children[0]);
612 free_temp_storage(vt, n->Children[1]->Children[1]);
613 free_temp_storage(vt, n->Children[0]);
614 }
615 else
616 #endif
617 {
618 /* normal case */
619
620 /* gen code for children */
621 emit(vt, n->Children[0], prog);
622 emit(vt, n->Children[1], prog);
623
624 /* gen this instruction */
625 inst = new_instruction(prog, info->InstOpcode);
626 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
627 storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Store);
628
629 srcAnnot0 = storage_annotation(n->Children[0], prog);
630 srcAnnot1 = storage_annotation(n->Children[1], prog);
631
632 free_temp_storage(vt, n->Children[0]);
633 free_temp_storage(vt, n->Children[1]);
634 }
635
636 if (!n->Store) {
637 alloc_temp_storage(vt, n, info->ResultSize);
638 }
639 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
640
641 dstAnnot = storage_annotation(n, prog);
642 inst->Comment = instruction_annotation(inst->Opcode, dstAnnot,
643 srcAnnot0, srcAnnot1);
644
645 /*_mesa_print_instruction(inst);*/
646 return inst;
647 }
648
649
650 static struct prog_instruction *
651 emit_unop(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
652 {
653 struct prog_instruction *inst;
654 const slang_ir_info *info = slang_find_ir_info(n->Opcode);
655 char *srcAnnot, *dstAnnot;
656
657 assert(info);
658 assert(info->NumParams == 1);
659
660 /* gen code for child */
661 emit(vt, n->Children[0], prog);
662
663 /* gen this instruction */
664 inst = new_instruction(prog, info->InstOpcode);
665 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
666 srcAnnot = storage_annotation(n->Children[0], prog);
667 free_temp_storage(vt, n->Children[0]);
668
669 if (!n->Store) {
670 alloc_temp_storage(vt, n, info->ResultSize);
671 }
672 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
673
674 dstAnnot = storage_annotation(n, prog);
675 inst->Comment = instruction_annotation(inst->Opcode, dstAnnot,
676 NULL, srcAnnot);
677
678 return inst;
679 }
680
681
682 static struct prog_instruction *
683 emit_negation(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
684 {
685 /* Implement as MOV dst, -src; */
686 /* XXX we could look at the previous instruction and in some circumstances
687 * modify it to accomplish the negation.
688 */
689 struct prog_instruction *inst;
690
691 emit(vt, n->Children[0], prog);
692
693 if (!n->Store)
694 alloc_temp_storage(vt, n, n->Children[0]->Store->Size);
695
696 inst = new_instruction(prog, OPCODE_MOV);
697 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
698 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
699 inst->SrcReg[0].NegateBase = NEGATE_XYZW;
700 inst->Comment = n->Comment;
701 return inst;
702 }
703
704
705 static struct prog_instruction *
706 emit_label(const char *target, struct gl_program *prog)
707 {
708 struct prog_instruction *inst;
709 inst = new_instruction(prog, OPCODE_NOP);
710 inst->Comment = _mesa_strdup(target);
711 return inst;
712 }
713
714
715 static struct prog_instruction *
716 emit_cjump(const char *target, struct gl_program *prog, GLuint zeroOrOne)
717 {
718 struct prog_instruction *inst;
719 inst = new_instruction(prog, OPCODE_BRA);
720 if (zeroOrOne)
721 inst->DstReg.CondMask = COND_NE; /* branch if non-zero */
722 else
723 inst->DstReg.CondMask = COND_EQ; /* branch if equal to zero */
724 inst->DstReg.CondSwizzle = SWIZZLE_X;
725 inst->Comment = _mesa_strdup(target);
726 return inst;
727 }
728
729
730 static struct prog_instruction *
731 emit_jump(const char *target, struct gl_program *prog)
732 {
733 struct prog_instruction *inst;
734 inst = new_instruction(prog, OPCODE_BRA);
735 inst->DstReg.CondMask = COND_TR; /* always branch */
736 /*inst->DstReg.CondSwizzle = SWIZZLE_X;*/
737 inst->Comment = _mesa_strdup(target);
738 return inst;
739 }
740
741
742 static struct prog_instruction *
743 emit_kill(struct gl_program *prog)
744 {
745 struct prog_instruction *inst;
746 /* NV-KILL - discard fragment depending on condition code.
747 * Note that ARB-KILL depends on sign of vector operand.
748 */
749 inst = new_instruction(prog, OPCODE_KIL_NV);
750 inst->DstReg.CondMask = COND_TR; /* always branch */
751 return inst;
752 }
753
754
755 static struct prog_instruction *
756 emit_tex(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
757 {
758 struct prog_instruction *inst;
759 if (n->Opcode == IR_TEX) {
760 inst = new_instruction(prog, OPCODE_TEX);
761 }
762 else if (n->Opcode == IR_TEXB) {
763 inst = new_instruction(prog, OPCODE_TXB);
764 }
765 else {
766 assert(n->Opcode == IR_TEXP);
767 inst = new_instruction(prog, OPCODE_TXP);
768 }
769
770 if (!n->Store)
771 alloc_temp_storage(vt, n, 4);
772
773 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
774
775 /* Child[1] is the coord */
776 storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store);
777
778 /* Child[0] is the sampler (a uniform which'll indicate the texture unit) */
779 assert(n->Children[0]->Store);
780 assert(n->Children[0]->Store->Size >= TEXTURE_1D_INDEX);
781
782 inst->Sampler = n->Children[0]->Store->Index; /* i.e. uniform's index */
783 inst->TexSrcTarget = n->Children[0]->Store->Size;
784 inst->TexSrcUnit = 27; /* Dummy value; the TexSrcUnit will be computed at
785 * link time, using the sampler uniform's value.
786 */
787 return inst;
788 }
789
790
791 static struct prog_instruction *
792 emit_move(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
793 {
794 struct prog_instruction *inst;
795
796 /* rhs */
797 assert(n->Children[1]);
798 inst = emit(vt, n->Children[1], prog);
799
800 assert(n->Children[1]->Store->Index >= 0);
801
802 /* lhs */
803 emit(vt, n->Children[0], prog);
804
805 #if PEEPHOLE_OPTIMIZATIONS
806 if (inst && _slang_is_temp(vt, n->Children[1]->Store)) {
807 /* Peephole optimization:
808 * Just modify the RHS to put its result into the dest of this
809 * MOVE operation. Then, this MOVE is a no-op.
810 */
811 _slang_free_temp(vt, n->Children[1]->Store);
812 *n->Children[1]->Store = *n->Children[0]->Store;
813 /* fixup the prev (RHS) instruction */
814 assert(n->Children[0]->Store->Index >= 0);
815 assert(n->Children[0]->Store->Index < 16);
816 storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask);
817 return inst;
818 }
819 else
820 #endif
821 {
822 if (n->Children[0]->Store->Size > 4) {
823 /* move matrix/struct etc (block of registers) */
824 slang_ir_storage dstStore = *n->Children[0]->Store;
825 slang_ir_storage srcStore = *n->Children[1]->Store;
826 GLint size = srcStore.Size;
827 ASSERT(n->Children[0]->Writemask == WRITEMASK_XYZW);
828 ASSERT(n->Children[1]->Store->Swizzle == SWIZZLE_NOOP);
829 dstStore.Size = 4;
830 srcStore.Size = 4;
831 while (size >= 4) {
832 inst = new_instruction(prog, OPCODE_MOV);
833 inst->Comment = _mesa_strdup("IR_MOVE block");
834 storage_to_dst_reg(&inst->DstReg, &dstStore, n->Writemask);
835 storage_to_src_reg(&inst->SrcReg[0], &srcStore);
836 srcStore.Index++;
837 dstStore.Index++;
838 size -= 4;
839 }
840 }
841 else {
842 /* single register move */
843 char *srcAnnot, *dstAnnot;
844 inst = new_instruction(prog, OPCODE_MOV);
845 assert(n->Children[0]->Store->Index >= 0);
846 assert(n->Children[0]->Store->Index < 16);
847 storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask);
848 storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store);
849 dstAnnot = storage_annotation(n->Children[0], prog);
850 srcAnnot = storage_annotation(n->Children[1], prog);
851 inst->Comment = instruction_annotation(inst->Opcode, dstAnnot,
852 srcAnnot, NULL);
853 }
854 free_temp_storage(vt, n->Children[1]);
855 assert(!n->Store);
856 n->Store = n->Children[0]->Store; /*XXX new */
857 return inst;
858 }
859 }
860
861
862 static struct prog_instruction *
863 emit_cond(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
864 {
865 /* Conditional expression (in if/while/for stmts).
866 * Need to update condition code register.
867 * Next instruction is typically an IR_CJUMP0/1.
868 */
869 /* last child expr instruction: */
870 struct prog_instruction *inst = emit(vt, n->Children[0], prog);
871 if (inst) {
872 /* set inst's CondUpdate flag */
873 inst->CondUpdate = GL_TRUE;
874 return inst; /* XXX or null? */
875 }
876 else {
877 /* This'll happen for things like "if (i) ..." where no code
878 * is normally generated for the expression "i".
879 * Generate a move instruction just to set condition codes.
880 * Note: must use full 4-component vector since all four
881 * condition codes must be set identically.
882 */
883 alloc_temp_storage(vt, n, 4);
884 inst = new_instruction(prog, OPCODE_MOV);
885 inst->CondUpdate = GL_TRUE;
886 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
887 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
888 _slang_free_temp(vt, n->Store);
889 inst->Comment = _mesa_strdup("COND expr");
890 return inst; /* XXX or null? */
891 }
892 }
893
894
895 static struct prog_instruction *
896 emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
897 {
898 struct prog_instruction *inst;
899 if (!n)
900 return NULL;
901
902 switch (n->Opcode) {
903 case IR_SEQ:
904 /* sequence of two sub-trees */
905 assert(n->Children[0]);
906 assert(n->Children[1]);
907 emit(vt, n->Children[0], prog);
908 inst = emit(vt, n->Children[1], prog);
909 assert(!n->Store);
910 n->Store = n->Children[1]->Store;
911 return inst;
912
913 case IR_SCOPE:
914 /* new variable scope */
915 vt = _slang_push_var_table(vt);
916 inst = emit(vt, n->Children[0], prog);
917 vt = _slang_pop_var_table(vt);
918 return inst;
919
920 case IR_VAR_DECL:
921 /* Variable declaration - allocate a register for it */
922 assert(n->Store);
923 assert(n->Store->File != PROGRAM_UNDEFINED);
924 assert(n->Store->Size > 0);
925 assert(n->Store->Index < 0);
926 if (!n->Var || n->Var->isTemp) {
927 /* a nameless/temporary variable, will be freed after first use */
928 (void) _slang_alloc_temp(vt, n->Store);
929 }
930 else {
931 /* a regular variable */
932 _slang_add_variable(vt, n->Var);
933 (void) _slang_alloc_var(vt, n->Store);
934 /*
935 printf("IR_VAR_DECL %s %d store %p\n",
936 (char*) n->Var->a_name, n->Store->Index, (void*) n->Store);
937 */
938 assert(n->Var->aux == n->Store);
939 }
940 assert(n->Store->Index >= 0);
941 break;
942
943 case IR_VAR:
944 /* Reference to a variable
945 * Storage should have already been resolved/allocated.
946 */
947 assert(n->Store);
948 assert(n->Store->File != PROGRAM_UNDEFINED);
949 if (n->Store->Index < 0) {
950 printf("#### VAR %s not allocated!\n", (char*)n->Var->a_name);
951 }
952 assert(n->Store->Index >= 0);
953 assert(n->Store->Size > 0);
954 break;
955
956 case IR_ELEMENT:
957 /* Dereference array element. Just resolve storage for the array
958 * element represented by this node.
959 */
960 assert(n->Store);
961 assert(n->Store->File != PROGRAM_UNDEFINED);
962 assert(n->Store->Size > 0);
963 if (n->Children[1]->Opcode == IR_FLOAT) {
964 /* OK, constant index */
965 const GLint arrayAddr = n->Children[0]->Store->Index;
966 const GLint index = (GLint) n->Children[1]->Value[0];
967 n->Store->Index = arrayAddr + index;
968 }
969 else {
970 /* Problem: variable index */
971 const GLint arrayAddr = n->Children[0]->Store->Index;
972 const GLint index = 0;
973 _mesa_problem(NULL, "variable array indexes not supported yet!");
974 n->Store->Index = arrayAddr + index;
975 }
976 return NULL; /* no instruction */
977
978 case IR_SWIZZLE:
979 /* swizzled storage access */
980 (void) emit(vt, n->Children[0], prog);
981 /* "pull-up" the child's storage info, applying our swizzle info */
982 n->Store->File = n->Children[0]->Store->File;
983 n->Store->Index = n->Children[0]->Store->Index;
984 n->Store->Size = n->Children[0]->Store->Size;
985 assert(n->Store->Index >= 0);
986 n->Store->Swizzle = swizzle_swizzle(n->Children[0]->Store->Swizzle,
987 n->Store->Swizzle);
988 return NULL;
989
990 /* Simple binary operators */
991 case IR_ADD:
992 case IR_SUB:
993 case IR_MUL:
994 case IR_DOT4:
995 case IR_DOT3:
996 case IR_CROSS:
997 case IR_MIN:
998 case IR_MAX:
999 case IR_SEQUAL:
1000 case IR_SNEQUAL:
1001 case IR_SGE:
1002 case IR_SGT:
1003 case IR_POW:
1004 case IR_EXP:
1005 case IR_EXP2:
1006 return emit_binop(vt, n, prog);
1007 /* Simple unary operators */
1008 case IR_RSQ:
1009 case IR_RCP:
1010 case IR_FLOOR:
1011 case IR_FRAC:
1012 case IR_F_TO_I:
1013 case IR_ABS:
1014 case IR_SIN:
1015 case IR_COS:
1016 case IR_DDX:
1017 case IR_DDY:
1018 return emit_unop(vt, n, prog);
1019 case IR_TEX:
1020 case IR_TEXB:
1021 case IR_TEXP:
1022 return emit_tex(vt, n, prog);
1023 case IR_NEG:
1024 return emit_negation(vt, n, prog);
1025 case IR_FLOAT:
1026 /* find storage location for this float constant */
1027 n->Store->Index = _mesa_add_unnamed_constant(prog->Parameters, n->Value,
1028 n->Store->Size,
1029 &n->Store->Swizzle);
1030 if (n->Store->Index < 0) {
1031 RETURN_ERROR("Ran out of space for constants.", 0);
1032 }
1033 return NULL;
1034
1035 case IR_MOVE:
1036 return emit_move(vt, n, prog);
1037
1038 case IR_COND:
1039 return emit_cond(vt, n, prog);
1040
1041 case IR_LABEL:
1042 return emit_label(n->Target, prog);
1043 case IR_JUMP:
1044 return emit_jump(n->Target, prog);
1045 case IR_CJUMP0:
1046 return emit_cjump(n->Target, prog, 0);
1047 case IR_CJUMP1:
1048 return emit_cjump(n->Target, prog, 1);
1049 case IR_KILL:
1050 return emit_kill(prog);
1051
1052 case IR_IF:
1053 {
1054 struct prog_instruction *inst;
1055 emit(vt, n->Children[0], prog); /* the condition */
1056 inst = new_instruction(prog, OPCODE_IF);
1057 inst->DstReg.CondMask = COND_NE; /* if cond is non-zero */
1058 inst->DstReg.CondSwizzle = SWIZZLE_X;
1059 return inst;
1060 }
1061 case IR_ELSE:
1062 {
1063 struct prog_instruction *inst;
1064 inst = new_instruction(prog, OPCODE_ELSE);
1065 return inst;
1066 }
1067 case IR_ENDIF:
1068 {
1069 struct prog_instruction *inst;
1070 inst = new_instruction(prog, OPCODE_ENDIF);
1071 return inst;
1072 }
1073
1074 default:
1075 _mesa_problem(NULL, "Unexpected IR opcode in emit()\n");
1076 abort();
1077 }
1078 return NULL;
1079 }
1080
1081
1082 GLboolean
1083 _slang_emit_code(slang_ir_node *n, slang_var_table *vt,
1084 struct gl_program *prog, GLboolean withEnd)
1085 {
1086 GLboolean success;
1087
1088 if (emit(vt, n, prog)) {
1089 /* finish up by adding the END opcode to program */
1090 if (withEnd) {
1091 struct prog_instruction *inst;
1092 inst = new_instruction(prog, OPCODE_END);
1093 }
1094 success = GL_TRUE;
1095 }
1096 else {
1097 /* record an error? */
1098 success = GL_FALSE;
1099 }
1100
1101 printf("*********** End generate code (%u inst):\n", prog->NumInstructions);
1102 #if 0
1103 _mesa_print_program(prog);
1104 _mesa_print_program_parameters(ctx,prog);
1105 #endif
1106
1107 return success;
1108 }