New asm instruction and IR_CLAMP node type to allow clamping to [0,1] with instructio...
[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_VAR:
301 printf("VAR %s%s at %s store %p\n",
302 (n->Var ? (char *) n->Var->a_name : "TEMP"),
303 swizzle_string(n->Store->Swizzle),
304 storage_string(n->Store), (void*) n->Store);
305 break;
306 case IR_VAR_DECL:
307 printf("VAR_DECL %s (%p) at %s store %p\n",
308 (n->Var ? (char *) n->Var->a_name : "TEMP"),
309 (void*) n->Var, storage_string(n->Store),
310 (void*) n->Store);
311 break;
312 case IR_FIELD:
313 printf("FIELD %s of\n", n->Target);
314 slang_print_ir(n->Children[0], indent+3);
315 break;
316 case IR_CALL:
317 printf("ASMCALL %s(%d args)\n", n->Target, 0/*XXX*/);
318 break;
319 case IR_FLOAT:
320 printf("FLOAT %f %f %f %f\n",
321 n->Value[0], n->Value[1], n->Value[2], n->Value[3]);
322 break;
323 case IR_I_TO_F:
324 printf("INT_TO_FLOAT %d\n", (int) n->Value[0]);
325 break;
326 case IR_SWIZZLE:
327 printf("SWIZZLE %s of (store %p) \n",
328 swizzle_string(n->Store->Swizzle), (void*) n->Store);
329 slang_print_ir(n->Children[0], indent + 3);
330 break;
331 default:
332 printf("%s (%p, %p) (store %p)\n", slang_ir_name(n->Opcode),
333 (void*) n->Children[0], (void*) n->Children[1], (void*) n->Store);
334 slang_print_ir(n->Children[0], indent+3);
335 slang_print_ir(n->Children[1], indent+3);
336 }
337 }
338
339
340 /**
341 * Allocate temporary storage for an intermediate result (such as for
342 * a multiply or add, etc.
343 */
344 static GLboolean
345 alloc_temp_storage(slang_var_table *vt, slang_ir_node *n, GLint size)
346 {
347 assert(!n->Var);
348 assert(!n->Store);
349 assert(size > 0);
350 n->Store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, size);
351 if (!_slang_alloc_temp(vt, n->Store)) {
352 RETURN_ERROR("Ran out of registers, too many temporaries", 0);
353 }
354 return GL_TRUE;
355 }
356
357
358 /**
359 * Free temporary storage, if n->Store is, in fact, temp storage.
360 * Otherwise, no-op.
361 */
362 static void
363 free_temp_storage(slang_var_table *vt, slang_ir_node *n)
364 {
365 if (n->Store->File == PROGRAM_TEMPORARY && n->Store->Index >= 0) {
366 if (_slang_is_temp(vt, n->Store)) {
367 _slang_free_temp(vt, n->Store);
368 n->Store->Index = -1;
369 n->Store->Size = -1;
370 }
371 }
372 }
373
374
375 /**
376 * Convert IR storage to an instruction dst register.
377 */
378 static void
379 storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st,
380 GLuint writemask)
381 {
382 static const GLuint defaultWritemask[4] = {
383 WRITEMASK_X,
384 WRITEMASK_X | WRITEMASK_Y,
385 WRITEMASK_X | WRITEMASK_Y | WRITEMASK_Z,
386 WRITEMASK_X | WRITEMASK_Y | WRITEMASK_Z | WRITEMASK_W
387 };
388 assert(st->Index >= 0 && st->Index <= 16);
389 dst->File = st->File;
390 dst->Index = st->Index;
391 assert(st->File != PROGRAM_UNDEFINED);
392 assert(st->Size >= 1);
393 assert(st->Size <= 4);
394 if (st->Size == 1) {
395 GLuint comp = GET_SWZ(st->Swizzle, 0);
396 assert(comp < 4);
397 assert(writemask & WRITEMASK_X);
398 dst->WriteMask = WRITEMASK_X << comp;
399 }
400 else {
401 dst->WriteMask = defaultWritemask[st->Size - 1] & writemask;
402 }
403 }
404
405
406 /**
407 * Convert IR storage to an instruction src register.
408 */
409 static void
410 storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st)
411 {
412 static const GLuint defaultSwizzle[4] = {
413 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_X, SWIZZLE_X, SWIZZLE_X),
414 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
415 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W),
416 MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W)
417 };
418 assert(st->File >= 0 && st->File <= 16);
419 src->File = st->File;
420 src->Index = st->Index;
421 assert(st->File != PROGRAM_UNDEFINED);
422 assert(st->Size >= 1);
423 assert(st->Size <= 4);
424 if (st->Swizzle != SWIZZLE_NOOP)
425 src->Swizzle = st->Swizzle;
426 else
427 src->Swizzle = defaultSwizzle[st->Size - 1];
428 }
429
430
431
432 /**
433 * Add new instruction at end of given program.
434 * \param prog the program to append instruction onto
435 * \param opcode opcode for the new instruction
436 * \return pointer to the new instruction
437 */
438 static struct prog_instruction *
439 new_instruction(struct gl_program *prog, gl_inst_opcode opcode)
440 {
441 struct prog_instruction *inst;
442 prog->Instructions = _mesa_realloc_instructions(prog->Instructions,
443 prog->NumInstructions,
444 prog->NumInstructions + 1);
445 inst = prog->Instructions + prog->NumInstructions;
446 prog->NumInstructions++;
447 _mesa_init_instructions(inst, 1);
448 inst->Opcode = opcode;
449 return inst;
450 }
451
452
453 /**
454 * Return pointer to last instruction in program.
455 */
456 static struct prog_instruction *
457 prev_instruction(struct gl_program *prog)
458 {
459 if (prog->NumInstructions == 0)
460 return NULL;
461 else
462 return prog->Instructions + prog->NumInstructions - 1;
463 }
464
465
466 static struct prog_instruction *
467 emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog);
468
469
470 /**
471 * Return an annotation string for given node's storage.
472 */
473 static char *
474 storage_annotation(const slang_ir_node *n, const struct gl_program *prog)
475 {
476 #if ANNOTATE
477 const slang_ir_storage *st = n->Store;
478 static char s[100] = "";
479
480 if (!st)
481 return _mesa_strdup("");
482
483 switch (st->File) {
484 case PROGRAM_CONSTANT:
485 if (st->Index >= 0) {
486 const GLfloat *val = prog->Parameters->ParameterValues[st->Index];
487 if (st->Swizzle == SWIZZLE_NOOP)
488 sprintf(s, "{%f, %f, %f, %f}", val[0], val[1], val[2], val[3]);
489 else {
490 sprintf(s, "%f", val[GET_SWZ(st->Swizzle, 0)]);
491 }
492 }
493 break;
494 case PROGRAM_TEMPORARY:
495 if (n->Var)
496 sprintf(s, "%s", (char *) n->Var->a_name);
497 else
498 sprintf(s, "t[%d]", st->Index);
499 break;
500 case PROGRAM_STATE_VAR:
501 case PROGRAM_UNIFORM:
502 sprintf(s, "%s", prog->Parameters->Parameters[st->Index].Name);
503 break;
504 case PROGRAM_VARYING:
505 sprintf(s, "%s", prog->Varying->Parameters[st->Index].Name);
506 break;
507 case PROGRAM_INPUT:
508 sprintf(s, "input[%d]", st->Index);
509 break;
510 case PROGRAM_OUTPUT:
511 sprintf(s, "output[%d]", st->Index);
512 break;
513 default:
514 s[0] = 0;
515 }
516 return _mesa_strdup(s);
517 #else
518 return NULL;
519 #endif
520 }
521
522
523 /**
524 * Return an annotation string for an instruction.
525 */
526 static char *
527 instruction_annotation(gl_inst_opcode opcode, char *dstAnnot,
528 char *srcAnnot0, char *srcAnnot1, char *srcAnnot2)
529 {
530 #if ANNOTATE
531 const char *operator;
532 char *s;
533 int len = 50;
534
535 if (dstAnnot)
536 len += strlen(dstAnnot);
537 else
538 dstAnnot = _mesa_strdup("");
539
540 if (srcAnnot0)
541 len += strlen(srcAnnot0);
542 else
543 srcAnnot0 = _mesa_strdup("");
544
545 if (srcAnnot1)
546 len += strlen(srcAnnot1);
547 else
548 srcAnnot1 = _mesa_strdup("");
549
550 if (srcAnnot2)
551 len += strlen(srcAnnot2);
552 else
553 srcAnnot2 = _mesa_strdup("");
554
555 switch (opcode) {
556 case OPCODE_ADD:
557 operator = "+";
558 break;
559 case OPCODE_SUB:
560 operator = "-";
561 break;
562 case OPCODE_MUL:
563 operator = "*";
564 break;
565 case OPCODE_DP3:
566 operator = "DP3";
567 break;
568 case OPCODE_DP4:
569 operator = "DP4";
570 break;
571 case OPCODE_XPD:
572 operator = "XPD";
573 break;
574 case OPCODE_RSQ:
575 operator = "RSQ";
576 break;
577 case OPCODE_SGT:
578 operator = ">";
579 break;
580 default:
581 operator = ",";
582 }
583
584 s = (char *) malloc(len);
585 sprintf(s, "%s = %s %s %s %s", dstAnnot,
586 srcAnnot0, operator, srcAnnot1, srcAnnot2);
587 assert(_mesa_strlen(s) < len);
588
589 free(dstAnnot);
590 free(srcAnnot0);
591 free(srcAnnot1);
592 free(srcAnnot2);
593
594 return s;
595 #else
596 return NULL;
597 #endif
598 }
599
600
601
602 /**
603 * Generate code for a simple arithmetic instruction.
604 * Either 1, 2 or 3 operands.
605 */
606 static struct prog_instruction *
607 emit_arith(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
608 {
609 struct prog_instruction *inst;
610 const slang_ir_info *info = slang_find_ir_info(n->Opcode);
611 char *srcAnnot[3], *dstAnnot;
612 GLuint i;
613
614 assert(info);
615 assert(info->InstOpcode != OPCODE_NOP);
616
617 srcAnnot[0] = srcAnnot[1] = srcAnnot[2] = dstAnnot = NULL;
618
619 #if PEEPHOLE_OPTIMIZATIONS
620 /* Look for MAD opportunity */
621 if (info->NumParams == 2 &&
622 n->Opcode == IR_ADD && n->Children[0]->Opcode == IR_MUL) {
623 /* found pattern IR_ADD(IR_MUL(A, B), C) */
624 emit(vt, n->Children[0]->Children[0], prog); /* A */
625 emit(vt, n->Children[0]->Children[1], prog); /* B */
626 emit(vt, n->Children[1], prog); /* C */
627 /* generate MAD instruction */
628 inst = new_instruction(prog, OPCODE_MAD);
629 /* operands: A, B, C: */
630 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Children[0]->Store);
631 storage_to_src_reg(&inst->SrcReg[1], n->Children[0]->Children[1]->Store);
632 storage_to_src_reg(&inst->SrcReg[2], n->Children[1]->Store);
633 free_temp_storage(vt, n->Children[0]->Children[0]);
634 free_temp_storage(vt, n->Children[0]->Children[1]);
635 free_temp_storage(vt, n->Children[1]);
636 }
637 else if (info->NumParams == 2 &&
638 n->Opcode == IR_ADD && n->Children[1]->Opcode == IR_MUL) {
639 /* found pattern IR_ADD(A, IR_MUL(B, C)) */
640 emit(vt, n->Children[0], prog); /* A */
641 emit(vt, n->Children[1]->Children[0], prog); /* B */
642 emit(vt, n->Children[1]->Children[1], prog); /* C */
643 /* generate MAD instruction */
644 inst = new_instruction(prog, OPCODE_MAD);
645 /* operands: B, C, A */
646 storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Children[0]->Store);
647 storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Children[1]->Store);
648 storage_to_src_reg(&inst->SrcReg[2], n->Children[0]->Store);
649 free_temp_storage(vt, n->Children[1]->Children[0]);
650 free_temp_storage(vt, n->Children[1]->Children[1]);
651 free_temp_storage(vt, n->Children[0]);
652 }
653 else
654 #endif
655 {
656 /* normal case */
657
658 /* gen code for children */
659 for (i = 0; i < info->NumParams; i++)
660 emit(vt, n->Children[i], prog);
661
662 /* gen this instruction and src registers */
663 inst = new_instruction(prog, info->InstOpcode);
664 for (i = 0; i < info->NumParams; i++)
665 storage_to_src_reg(&inst->SrcReg[i], n->Children[i]->Store);
666
667 /* annotation */
668 for (i = 0; i < info->NumParams; i++)
669 srcAnnot[i] = storage_annotation(n->Children[i], prog);
670
671 /* free temps */
672 for (i = 0; i < info->NumParams; i++)
673 free_temp_storage(vt, n->Children[i]);
674 }
675
676 /* result storage */
677 if (!n->Store) {
678 if (!alloc_temp_storage(vt, n, info->ResultSize))
679 return NULL;
680 }
681 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
682
683 dstAnnot = storage_annotation(n, prog);
684
685 inst->Comment = instruction_annotation(inst->Opcode, dstAnnot, srcAnnot[0],
686 srcAnnot[1], srcAnnot[2]);
687
688 /*_mesa_print_instruction(inst);*/
689 return inst;
690 }
691
692
693 /**
694 * Generate code for an IR_CLAMP instruction.
695 */
696 static struct prog_instruction *
697 emit_clamp(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
698 {
699 struct prog_instruction *inst;
700
701 assert(n->Opcode == IR_CLAMP);
702 /* ch[0] = value
703 * ch[1] = min limit
704 * ch[2] = max limit
705 */
706
707 inst = emit(vt, n->Children[0], prog);
708
709 /* If lower limit == 0.0 and upper limit == 1.0,
710 * set prev instruction's SaturateMode field to SATURATE_ZERO_ONE.
711 * Else,
712 * emit OPCODE_MIN, OPCODE_MAX sequence.
713 */
714 #if 0
715 /* XXX this isn't quite finished yet */
716 if (n->Children[1]->Opcode == IR_FLOAT &&
717 n->Children[1]->Value[0] == 0.0 &&
718 n->Children[1]->Value[1] == 0.0 &&
719 n->Children[1]->Value[2] == 0.0 &&
720 n->Children[1]->Value[3] == 0.0 &&
721 n->Children[2]->Opcode == IR_FLOAT &&
722 n->Children[2]->Value[0] == 1.0 &&
723 n->Children[2]->Value[1] == 1.0 &&
724 n->Children[2]->Value[2] == 1.0 &&
725 n->Children[2]->Value[3] == 1.0) {
726 if (!inst) {
727 inst = prev_instruction(prog);
728 }
729 if (inst && inst->Opcode != OPCODE_NOP) {
730 /* and prev instruction's DstReg matches n->Children[0]->Store */
731 inst->SaturateMode = SATURATE_ZERO_ONE;
732 n->Store = n->Children[0]->Store;
733 return inst;
734 }
735 }
736 #endif
737
738 if (!n->Store)
739 if (!alloc_temp_storage(vt, n, n->Children[0]->Store->Size))
740 return NULL;
741
742 emit(vt, n->Children[1], prog);
743 emit(vt, n->Children[2], prog);
744
745 /* tmp = max(ch[0], ch[1]) */
746 inst = new_instruction(prog, OPCODE_MAX);
747 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
748 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
749 storage_to_src_reg(&inst->SrcReg[1], n->Children[1]->Store);
750
751 /* tmp = min(tmp, ch[2]) */
752 inst = new_instruction(prog, OPCODE_MIN);
753 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
754 storage_to_src_reg(&inst->SrcReg[0], n->Store);
755 storage_to_src_reg(&inst->SrcReg[1], n->Children[2]->Store);
756
757 return inst;
758 }
759
760
761 static struct prog_instruction *
762 emit_negation(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
763 {
764 /* Implement as MOV dst, -src; */
765 /* XXX we could look at the previous instruction and in some circumstances
766 * modify it to accomplish the negation.
767 */
768 struct prog_instruction *inst;
769
770 emit(vt, n->Children[0], prog);
771
772 if (!n->Store)
773 if (!alloc_temp_storage(vt, n, n->Children[0]->Store->Size))
774 return NULL;
775
776 inst = new_instruction(prog, OPCODE_MOV);
777 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
778 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
779 inst->SrcReg[0].NegateBase = NEGATE_XYZW;
780 inst->Comment = n->Comment;
781 return inst;
782 }
783
784
785 static struct prog_instruction *
786 emit_label(const char *target, struct gl_program *prog)
787 {
788 struct prog_instruction *inst;
789 inst = new_instruction(prog, OPCODE_NOP);
790 inst->Comment = _mesa_strdup(target);
791 return inst;
792 }
793
794
795 static struct prog_instruction *
796 emit_cjump(const char *target, struct gl_program *prog, GLuint zeroOrOne)
797 {
798 struct prog_instruction *inst;
799 inst = new_instruction(prog, OPCODE_BRA);
800 if (zeroOrOne)
801 inst->DstReg.CondMask = COND_NE; /* branch if non-zero */
802 else
803 inst->DstReg.CondMask = COND_EQ; /* branch if equal to zero */
804 inst->DstReg.CondSwizzle = SWIZZLE_X;
805 inst->Comment = _mesa_strdup(target);
806 return inst;
807 }
808
809
810 static struct prog_instruction *
811 emit_jump(const char *target, struct gl_program *prog)
812 {
813 struct prog_instruction *inst;
814 inst = new_instruction(prog, OPCODE_BRA);
815 inst->DstReg.CondMask = COND_TR; /* always branch */
816 /*inst->DstReg.CondSwizzle = SWIZZLE_X;*/
817 inst->Comment = _mesa_strdup(target);
818 return inst;
819 }
820
821
822 static struct prog_instruction *
823 emit_kill(struct gl_program *prog)
824 {
825 struct prog_instruction *inst;
826 /* NV-KILL - discard fragment depending on condition code.
827 * Note that ARB-KILL depends on sign of vector operand.
828 */
829 inst = new_instruction(prog, OPCODE_KIL_NV);
830 inst->DstReg.CondMask = COND_TR; /* always branch */
831 return inst;
832 }
833
834
835 static struct prog_instruction *
836 emit_tex(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
837 {
838 struct prog_instruction *inst;
839 if (n->Opcode == IR_TEX) {
840 inst = new_instruction(prog, OPCODE_TEX);
841 }
842 else if (n->Opcode == IR_TEXB) {
843 inst = new_instruction(prog, OPCODE_TXB);
844 }
845 else {
846 assert(n->Opcode == IR_TEXP);
847 inst = new_instruction(prog, OPCODE_TXP);
848 }
849
850 if (!n->Store)
851 if (!alloc_temp_storage(vt, n, 4))
852 return NULL;
853
854 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
855
856 /* Child[1] is the coord */
857 storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store);
858
859 /* Child[0] is the sampler (a uniform which'll indicate the texture unit) */
860 assert(n->Children[0]->Store);
861 assert(n->Children[0]->Store->Size >= TEXTURE_1D_INDEX);
862
863 inst->Sampler = n->Children[0]->Store->Index; /* i.e. uniform's index */
864 inst->TexSrcTarget = n->Children[0]->Store->Size;
865 inst->TexSrcUnit = 27; /* Dummy value; the TexSrcUnit will be computed at
866 * link time, using the sampler uniform's value.
867 */
868 return inst;
869 }
870
871
872 static struct prog_instruction *
873 emit_move(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
874 {
875 struct prog_instruction *inst;
876
877 /* rhs */
878 assert(n->Children[1]);
879 inst = emit(vt, n->Children[1], prog);
880
881 assert(n->Children[1]->Store->Index >= 0);
882
883 /* lhs */
884 emit(vt, n->Children[0], prog);
885
886 assert(!n->Store);
887 n->Store = n->Children[0]->Store;
888
889 #if PEEPHOLE_OPTIMIZATIONS
890 if (inst && _slang_is_temp(vt, n->Children[1]->Store)) {
891 /* Peephole optimization:
892 * Just modify the RHS to put its result into the dest of this
893 * MOVE operation. Then, this MOVE is a no-op.
894 */
895 _slang_free_temp(vt, n->Children[1]->Store);
896 *n->Children[1]->Store = *n->Children[0]->Store;
897 /* fixup the prev (RHS) instruction */
898 assert(n->Children[0]->Store->Index >= 0);
899 assert(n->Children[0]->Store->Index < 16);
900 storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask);
901 return inst;
902 }
903 else
904 #endif
905 {
906 if (n->Children[0]->Store->Size > 4) {
907 /* move matrix/struct etc (block of registers) */
908 slang_ir_storage dstStore = *n->Children[0]->Store;
909 slang_ir_storage srcStore = *n->Children[1]->Store;
910 GLint size = srcStore.Size;
911 ASSERT(n->Children[0]->Writemask == WRITEMASK_XYZW);
912 ASSERT(n->Children[1]->Store->Swizzle == SWIZZLE_NOOP);
913 dstStore.Size = 4;
914 srcStore.Size = 4;
915 while (size >= 4) {
916 inst = new_instruction(prog, OPCODE_MOV);
917 inst->Comment = _mesa_strdup("IR_MOVE block");
918 storage_to_dst_reg(&inst->DstReg, &dstStore, n->Writemask);
919 storage_to_src_reg(&inst->SrcReg[0], &srcStore);
920 srcStore.Index++;
921 dstStore.Index++;
922 size -= 4;
923 }
924 }
925 else {
926 /* single register move */
927 char *srcAnnot, *dstAnnot;
928 inst = new_instruction(prog, OPCODE_MOV);
929 assert(n->Children[0]->Store->Index >= 0);
930 assert(n->Children[0]->Store->Index < 16);
931 storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask);
932 storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store);
933 dstAnnot = storage_annotation(n->Children[0], prog);
934 srcAnnot = storage_annotation(n->Children[1], prog);
935 inst->Comment = instruction_annotation(inst->Opcode, dstAnnot,
936 srcAnnot, NULL, NULL);
937 }
938 free_temp_storage(vt, n->Children[1]);
939 return inst;
940 }
941 }
942
943
944 static struct prog_instruction *
945 emit_cond(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
946 {
947 /* Conditional expression (in if/while/for stmts).
948 * Need to update condition code register.
949 * Next instruction is typically an IR_CJUMP0/1.
950 */
951 /* last child expr instruction: */
952 struct prog_instruction *inst = emit(vt, n->Children[0], prog);
953 if (inst) {
954 /* set inst's CondUpdate flag */
955 inst->CondUpdate = GL_TRUE;
956 return inst; /* XXX or null? */
957 }
958 else {
959 /* This'll happen for things like "if (i) ..." where no code
960 * is normally generated for the expression "i".
961 * Generate a move instruction just to set condition codes.
962 * Note: must use full 4-component vector since all four
963 * condition codes must be set identically.
964 */
965 if (!alloc_temp_storage(vt, n, 4))
966 return NULL;
967 inst = new_instruction(prog, OPCODE_MOV);
968 inst->CondUpdate = GL_TRUE;
969 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
970 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
971 _slang_free_temp(vt, n->Store);
972 inst->Comment = _mesa_strdup("COND expr");
973 return inst; /* XXX or null? */
974 }
975 }
976
977
978 static struct prog_instruction *
979 emit(slang_var_table *vt, slang_ir_node *n, struct gl_program *prog)
980 {
981 struct prog_instruction *inst;
982 if (!n)
983 return NULL;
984
985 switch (n->Opcode) {
986 case IR_SEQ:
987 /* sequence of two sub-trees */
988 assert(n->Children[0]);
989 assert(n->Children[1]);
990 emit(vt, n->Children[0], prog);
991 inst = emit(vt, n->Children[1], prog);
992 assert(!n->Store);
993 n->Store = n->Children[1]->Store;
994 return inst;
995
996 case IR_SCOPE:
997 /* new variable scope */
998 _slang_push_var_table(vt);
999 inst = emit(vt, n->Children[0], prog);
1000 _slang_pop_var_table(vt);
1001 return inst;
1002
1003 case IR_VAR_DECL:
1004 /* Variable declaration - allocate a register for it */
1005 assert(n->Store);
1006 assert(n->Store->File != PROGRAM_UNDEFINED);
1007 assert(n->Store->Size > 0);
1008 assert(n->Store->Index < 0);
1009 if (!n->Var || n->Var->isTemp) {
1010 /* a nameless/temporary variable, will be freed after first use */
1011 if (!_slang_alloc_temp(vt, n->Store))
1012 RETURN_ERROR("Ran out of registers, too many temporaries", 0);
1013 }
1014 else {
1015 /* a regular variable */
1016 _slang_add_variable(vt, n->Var);
1017 if (!_slang_alloc_var(vt, n->Store))
1018 RETURN_ERROR("Ran out of registers, too many variables", 0);
1019 /*
1020 printf("IR_VAR_DECL %s %d store %p\n",
1021 (char*) n->Var->a_name, n->Store->Index, (void*) n->Store);
1022 */
1023 assert(n->Var->aux == n->Store);
1024 }
1025 break;
1026
1027 case IR_VAR:
1028 /* Reference to a variable
1029 * Storage should have already been resolved/allocated.
1030 */
1031 assert(n->Store);
1032 assert(n->Store->File != PROGRAM_UNDEFINED);
1033 if (n->Store->Index < 0) {
1034 printf("#### VAR %s not allocated!\n", (char*)n->Var->a_name);
1035 }
1036 assert(n->Store->Index >= 0);
1037 assert(n->Store->Size > 0);
1038 break;
1039
1040 case IR_ELEMENT:
1041 /* Dereference array element. Just resolve storage for the array
1042 * element represented by this node.
1043 */
1044 assert(n->Store);
1045 assert(n->Store->File != PROGRAM_UNDEFINED);
1046 assert(n->Store->Size > 0);
1047 if (n->Children[1]->Opcode == IR_FLOAT) {
1048 /* OK, constant index */
1049 const GLint arrayAddr = n->Children[0]->Store->Index;
1050 const GLint index = (GLint) n->Children[1]->Value[0];
1051 n->Store->Index = arrayAddr + index;
1052 }
1053 else {
1054 /* Problem: variable index */
1055 const GLint arrayAddr = n->Children[0]->Store->Index;
1056 const GLint index = 0;
1057 _mesa_problem(NULL, "variable array indexes not supported yet!");
1058 n->Store->Index = arrayAddr + index;
1059 }
1060 return NULL; /* no instruction */
1061
1062 case IR_SWIZZLE:
1063 /* swizzled storage access */
1064 (void) emit(vt, n->Children[0], prog);
1065 /* "pull-up" the child's storage info, applying our swizzle info */
1066 n->Store->File = n->Children[0]->Store->File;
1067 n->Store->Index = n->Children[0]->Store->Index;
1068 n->Store->Size = n->Children[0]->Store->Size;
1069 assert(n->Store->Index >= 0);
1070 n->Store->Swizzle = swizzle_swizzle(n->Children[0]->Store->Swizzle,
1071 n->Store->Swizzle);
1072 return NULL;
1073
1074 /* Simple arithmetic */
1075 /* unary */
1076 case IR_RSQ:
1077 case IR_RCP:
1078 case IR_FLOOR:
1079 case IR_FRAC:
1080 case IR_F_TO_I:
1081 case IR_ABS:
1082 case IR_SIN:
1083 case IR_COS:
1084 case IR_DDX:
1085 case IR_DDY:
1086 case IR_NOISE1:
1087 case IR_NOISE2:
1088 case IR_NOISE3:
1089 case IR_NOISE4:
1090 /* binary */
1091 case IR_ADD:
1092 case IR_SUB:
1093 case IR_MUL:
1094 case IR_DOT4:
1095 case IR_DOT3:
1096 case IR_CROSS:
1097 case IR_MIN:
1098 case IR_MAX:
1099 case IR_SEQUAL:
1100 case IR_SNEQUAL:
1101 case IR_SGE:
1102 case IR_SGT:
1103 case IR_POW:
1104 case IR_EXP:
1105 case IR_EXP2:
1106 /* trinary operators */
1107 case IR_LRP:
1108 return emit_arith(vt, n, prog);
1109 case IR_CLAMP:
1110 return emit_clamp(vt, n, prog);
1111 case IR_TEX:
1112 case IR_TEXB:
1113 case IR_TEXP:
1114 return emit_tex(vt, n, prog);
1115 case IR_NEG:
1116 return emit_negation(vt, n, prog);
1117 case IR_FLOAT:
1118 /* find storage location for this float constant */
1119 n->Store->Index = _mesa_add_unnamed_constant(prog->Parameters, n->Value,
1120 n->Store->Size,
1121 &n->Store->Swizzle);
1122 if (n->Store->Index < 0) {
1123 RETURN_ERROR("Ran out of space for constants.", 0);
1124 }
1125 return NULL;
1126
1127 case IR_MOVE:
1128 return emit_move(vt, n, prog);
1129
1130 case IR_COND:
1131 return emit_cond(vt, n, prog);
1132
1133 case IR_LABEL:
1134 return emit_label(n->Target, prog);
1135 case IR_JUMP:
1136 return emit_jump(n->Target, prog);
1137 case IR_CJUMP0:
1138 return emit_cjump(n->Target, prog, 0);
1139 case IR_CJUMP1:
1140 return emit_cjump(n->Target, prog, 1);
1141 case IR_KILL:
1142 return emit_kill(prog);
1143
1144 case IR_IF:
1145 {
1146 struct prog_instruction *inst;
1147 emit(vt, n->Children[0], prog); /* the condition */
1148 inst = new_instruction(prog, OPCODE_IF);
1149 inst->DstReg.CondMask = COND_NE; /* if cond is non-zero */
1150 inst->DstReg.CondSwizzle = SWIZZLE_X;
1151 return inst;
1152 }
1153 case IR_ELSE:
1154 {
1155 struct prog_instruction *inst;
1156 inst = new_instruction(prog, OPCODE_ELSE);
1157 return inst;
1158 }
1159 case IR_ENDIF:
1160 {
1161 struct prog_instruction *inst;
1162 inst = new_instruction(prog, OPCODE_ENDIF);
1163 return inst;
1164 }
1165
1166 default:
1167 _mesa_problem(NULL, "Unexpected IR opcode in emit()\n");
1168 abort();
1169 }
1170 return NULL;
1171 }
1172
1173
1174 GLboolean
1175 _slang_emit_code(slang_ir_node *n, slang_var_table *vt,
1176 struct gl_program *prog, GLboolean withEnd)
1177 {
1178 GLboolean success;
1179
1180 if (emit(vt, n, prog)) {
1181 /* finish up by adding the END opcode to program */
1182 if (withEnd) {
1183 struct prog_instruction *inst;
1184 inst = new_instruction(prog, OPCODE_END);
1185 }
1186 success = GL_TRUE;
1187 }
1188 else {
1189 /* record an error? */
1190 success = GL_FALSE;
1191 }
1192
1193 printf("*********** End generate code (%u inst):\n", prog->NumInstructions);
1194 #if 0
1195 _mesa_print_program(prog);
1196 _mesa_print_program_parameters(ctx,prog);
1197 #endif
1198
1199 return success;
1200 }