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