remove debug abort() calls
[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 if (!n->Children[1]->Store) {
797 slang_info_log_error(emitInfo->log, "invalid assignment");
798 return NULL;
799 }
800 assert(n->Children[1]->Store->Index >= 0);
801
802 n->Store = n->Children[0]->Store;
803
804 #if PEEPHOLE_OPTIMIZATIONS
805 if (inst && _slang_is_temp(emitInfo->vt, n->Children[1]->Store)) {
806 /* Peephole optimization:
807 * Just modify the RHS to put its result into the dest of this
808 * MOVE operation. Then, this MOVE is a no-op.
809 */
810 _slang_free_temp(emitInfo->vt, n->Children[1]->Store);
811 *n->Children[1]->Store = *n->Children[0]->Store;
812 /* fixup the prev (RHS) instruction */
813 assert(n->Children[0]->Store->Index >= 0);
814 storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask);
815 return inst;
816 }
817 else
818 #endif
819 {
820 if (n->Children[0]->Store->Size > 4) {
821 /* move matrix/struct etc (block of registers) */
822 slang_ir_storage dstStore = *n->Children[0]->Store;
823 slang_ir_storage srcStore = *n->Children[1]->Store;
824 GLint size = srcStore.Size;
825 ASSERT(n->Children[0]->Writemask == WRITEMASK_XYZW);
826 ASSERT(n->Children[1]->Store->Swizzle == SWIZZLE_NOOP);
827 dstStore.Size = 4;
828 srcStore.Size = 4;
829 while (size >= 4) {
830 inst = new_instruction(emitInfo, OPCODE_MOV);
831 inst->Comment = _mesa_strdup("IR_MOVE block");
832 storage_to_dst_reg(&inst->DstReg, &dstStore, n->Writemask);
833 storage_to_src_reg(&inst->SrcReg[0], &srcStore);
834 srcStore.Index++;
835 dstStore.Index++;
836 size -= 4;
837 }
838 }
839 else {
840 /* single register move */
841 char *srcAnnot, *dstAnnot;
842 inst = new_instruction(emitInfo, OPCODE_MOV);
843 assert(n->Children[0]->Store->Index >= 0);
844 storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store, n->Writemask);
845 storage_to_src_reg(&inst->SrcReg[0], n->Children[1]->Store);
846 dstAnnot = storage_annotation(n->Children[0], emitInfo->prog);
847 srcAnnot = storage_annotation(n->Children[1], emitInfo->prog);
848 inst->Comment = instruction_annotation(inst->Opcode, dstAnnot,
849 srcAnnot, NULL, NULL);
850 }
851 free_temp_storage(emitInfo->vt, n->Children[1]);
852 return inst;
853 }
854 }
855
856
857 static struct prog_instruction *
858 emit_cond(slang_emit_info *emitInfo, slang_ir_node *n)
859 {
860 struct prog_instruction *inst;
861
862 if (!n->Children[0])
863 return NULL;
864
865 inst = emit(emitInfo, n->Children[0]);
866
867 if (emitInfo->EmitCondCodes) {
868 /* Conditional expression (in if/while/for stmts).
869 * Need to update condition code register.
870 * Next instruction is typically an IR_IF.
871 */
872 if (inst) {
873 /* set inst's CondUpdate flag */
874 inst->CondUpdate = GL_TRUE;
875 n->Store = n->Children[0]->Store;
876 return inst; /* XXX or null? */
877 }
878 else {
879 /* This'll happen for things like "if (i) ..." where no code
880 * is normally generated for the expression "i".
881 * Generate a move instruction just to set condition codes.
882 * Note: must use full 4-component vector since all four
883 * condition codes must be set identically.
884 */
885 if (!alloc_temp_storage(emitInfo, n, 4))
886 return NULL;
887 inst = new_instruction(emitInfo, OPCODE_MOV);
888 inst->CondUpdate = GL_TRUE;
889 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
890 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
891 _slang_free_temp(emitInfo->vt, n->Store);
892 inst->Comment = _mesa_strdup("COND expr");
893 return inst; /* XXX or null? */
894 }
895 }
896 else {
897 /* No-op */
898 n->Store = n->Children[0]->Store;
899 return NULL;
900 }
901 }
902
903
904 /**
905 * Logical-NOT
906 */
907 static struct prog_instruction *
908 emit_not(slang_emit_info *emitInfo, slang_ir_node *n)
909 {
910 GLfloat zero = 0.0;
911 slang_ir_storage st;
912 struct prog_instruction *inst;
913
914 /* need zero constant */
915 st.File = PROGRAM_CONSTANT;
916 st.Size = 1;
917 st.Index = _mesa_add_unnamed_constant(emitInfo->prog->Parameters, &zero,
918 1, &st.Swizzle);
919
920 /* child expr */
921 (void) emit(emitInfo, n->Children[0]);
922 /* XXXX if child instr is SGT convert to SLE, if SEQ, SNE, etc */
923
924 if (!n->Store)
925 if (!alloc_temp_storage(emitInfo, n, n->Children[0]->Store->Size))
926 return NULL;
927
928 inst = new_instruction(emitInfo, OPCODE_SEQ);
929 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
930 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
931 storage_to_src_reg(&inst->SrcReg[1], &st);
932
933 free_temp_storage(emitInfo->vt, n->Children[0]);
934
935 inst->Comment = _mesa_strdup("NOT");
936 return inst;
937 }
938
939
940 static struct prog_instruction *
941 emit_if(slang_emit_info *emitInfo, slang_ir_node *n)
942 {
943 struct gl_program *prog = emitInfo->prog;
944 struct prog_instruction *ifInst;
945 GLuint ifInstLoc, elseInstLoc = 0;
946
947 emit(emitInfo, n->Children[0]); /* the condition */
948
949 #if 0
950 assert(n->Children[0]->Store->Size == 1); /* a bool! */
951 #endif
952
953 ifInstLoc = prog->NumInstructions;
954 if (emitInfo->EmitHighLevelInstructions) {
955 ifInst = new_instruction(emitInfo, OPCODE_IF);
956 if (emitInfo->EmitCondCodes) {
957 ifInst->DstReg.CondMask = COND_NE; /* if cond is non-zero */
958 }
959 else {
960 /* test reg.x */
961 storage_to_src_reg(&ifInst->SrcReg[0], n->Children[0]->Store);
962 }
963 }
964 else {
965 /* conditional jump to else, or endif */
966 ifInst = new_instruction(emitInfo, OPCODE_BRA);
967 ifInst->DstReg.CondMask = COND_EQ; /* BRA if cond is zero */
968 ifInst->Comment = _mesa_strdup("if zero");
969 }
970 if (emitInfo->EmitCondCodes) {
971 /* which condition code to use: */
972 ifInst->DstReg.CondSwizzle = n->Children[0]->Store->Swizzle;
973 }
974
975 /* if body */
976 emit(emitInfo, n->Children[1]);
977
978 if (n->Children[2]) {
979 /* have else body */
980 elseInstLoc = prog->NumInstructions;
981 if (emitInfo->EmitHighLevelInstructions) {
982 (void) new_instruction(emitInfo, OPCODE_ELSE);
983 }
984 else {
985 /* jump to endif instruction */
986 struct prog_instruction *inst;
987 inst = new_instruction(emitInfo, OPCODE_BRA);
988 inst->Comment = _mesa_strdup("else");
989 inst->DstReg.CondMask = COND_TR; /* always branch */
990 }
991 ifInst = prog->Instructions + ifInstLoc;
992 ifInst->BranchTarget = prog->NumInstructions;
993
994 emit(emitInfo, n->Children[2]);
995 }
996 else {
997 /* no else body */
998 ifInst = prog->Instructions + ifInstLoc;
999 ifInst->BranchTarget = prog->NumInstructions + 1;
1000 }
1001
1002 if (emitInfo->EmitHighLevelInstructions) {
1003 (void) new_instruction(emitInfo, OPCODE_ENDIF);
1004 }
1005
1006 if (n->Children[2]) {
1007 struct prog_instruction *elseInst;
1008 elseInst = prog->Instructions + elseInstLoc;
1009 elseInst->BranchTarget = prog->NumInstructions;
1010 }
1011 return NULL;
1012 }
1013
1014
1015 static struct prog_instruction *
1016 emit_loop(slang_emit_info *emitInfo, slang_ir_node *n)
1017 {
1018 struct gl_program *prog = emitInfo->prog;
1019 struct prog_instruction *beginInst, *endInst;
1020 GLuint beginInstLoc, tailInstLoc, endInstLoc;
1021 slang_ir_node *ir;
1022
1023 /* emit OPCODE_BGNLOOP */
1024 beginInstLoc = prog->NumInstructions;
1025 if (emitInfo->EmitHighLevelInstructions) {
1026 (void) new_instruction(emitInfo, OPCODE_BGNLOOP);
1027 }
1028
1029 /* body */
1030 emit(emitInfo, n->Children[0]);
1031
1032 /* tail */
1033 tailInstLoc = prog->NumInstructions;
1034 if (n->Children[1]) {
1035 if (emitInfo->EmitComments)
1036 emit_comment(emitInfo, "Loop tail code:");
1037 emit(emitInfo, n->Children[1]);
1038 }
1039
1040 endInstLoc = prog->NumInstructions;
1041 if (emitInfo->EmitHighLevelInstructions) {
1042 /* emit OPCODE_ENDLOOP */
1043 endInst = new_instruction(emitInfo, OPCODE_ENDLOOP);
1044 }
1045 else {
1046 /* emit unconditional BRA-nch */
1047 endInst = new_instruction(emitInfo, OPCODE_BRA);
1048 endInst->DstReg.CondMask = COND_TR; /* always true */
1049 }
1050 /* ENDLOOP's BranchTarget points to the BGNLOOP inst */
1051 endInst->BranchTarget = beginInstLoc;
1052
1053 if (emitInfo->EmitHighLevelInstructions) {
1054 /* BGNLOOP's BranchTarget points to the ENDLOOP inst */
1055 beginInst = prog->Instructions + beginInstLoc;
1056 beginInst->BranchTarget = prog->NumInstructions - 1;
1057 }
1058
1059 /* Done emitting loop code. Now walk over the loop's linked list of
1060 * BREAK and CONT nodes, filling in their BranchTarget fields (which
1061 * will point to the ENDLOOP+1 or BGNLOOP instructions, respectively).
1062 */
1063 for (ir = n->List; ir; ir = ir->List) {
1064 struct prog_instruction *inst = prog->Instructions + ir->InstLocation;
1065 assert(inst->BranchTarget < 0);
1066 if (ir->Opcode == IR_BREAK ||
1067 ir->Opcode == IR_BREAK_IF_FALSE ||
1068 ir->Opcode == IR_BREAK_IF_TRUE) {
1069 assert(inst->Opcode == OPCODE_BRK ||
1070 inst->Opcode == OPCODE_BRK0 ||
1071 inst->Opcode == OPCODE_BRK1 ||
1072 inst->Opcode == OPCODE_BRA);
1073 /* go to instruction after end of loop */
1074 inst->BranchTarget = endInstLoc + 1;
1075 }
1076 else {
1077 assert(ir->Opcode == IR_CONT ||
1078 ir->Opcode == IR_CONT_IF_FALSE ||
1079 ir->Opcode == IR_CONT_IF_TRUE);
1080 assert(inst->Opcode == OPCODE_CONT ||
1081 inst->Opcode == OPCODE_CONT0 ||
1082 inst->Opcode == OPCODE_CONT1 ||
1083 inst->Opcode == OPCODE_BRA);
1084 /* go to instruction at tail of loop */
1085 inst->BranchTarget = endInstLoc;
1086 }
1087 }
1088 return NULL;
1089 }
1090
1091
1092 /**
1093 * Unconditional "continue" or "break" statement.
1094 * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted.
1095 */
1096 static struct prog_instruction *
1097 emit_cont_break(slang_emit_info *emitInfo, slang_ir_node *n)
1098 {
1099 gl_inst_opcode opcode;
1100 struct prog_instruction *inst;
1101
1102 if (n->Opcode == IR_CONT) {
1103 /* we need to execute the loop's tail code before doing CONT */
1104 assert(n->Parent);
1105 assert(n->Parent->Opcode == IR_LOOP);
1106 if (n->Parent->Children[1]) {
1107 /* emit tail code */
1108 if (emitInfo->EmitComments) {
1109 emit_comment(emitInfo, "continue - tail code:");
1110 }
1111 emit(emitInfo, n->Parent->Children[1]);
1112 }
1113 }
1114
1115 /* opcode selection */
1116 if (emitInfo->EmitHighLevelInstructions) {
1117 opcode = (n->Opcode == IR_CONT) ? OPCODE_CONT : OPCODE_BRK;
1118 }
1119 else {
1120 opcode = OPCODE_BRA;
1121 }
1122 n->InstLocation = emitInfo->prog->NumInstructions;
1123 inst = new_instruction(emitInfo, opcode);
1124 inst->DstReg.CondMask = COND_TR; /* always true */
1125 return inst;
1126 }
1127
1128
1129 /**
1130 * Conditional "continue" or "break" statement.
1131 * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted.
1132 */
1133 static struct prog_instruction *
1134 emit_cont_break_if(slang_emit_info *emitInfo, slang_ir_node *n,
1135 GLboolean breakTrue)
1136 {
1137 gl_inst_opcode opcode;
1138 struct prog_instruction *inst;
1139
1140 assert(n->Opcode == IR_CONT_IF_TRUE ||
1141 n->Opcode == IR_CONT_IF_FALSE ||
1142 n->Opcode == IR_BREAK_IF_TRUE ||
1143 n->Opcode == IR_BREAK_IF_FALSE);
1144
1145 /* evaluate condition expr, setting cond codes */
1146 inst = emit(emitInfo, n->Children[0]);
1147 if (emitInfo->EmitCondCodes) {
1148 assert(inst);
1149 inst->CondUpdate = GL_TRUE;
1150 }
1151
1152 n->InstLocation = emitInfo->prog->NumInstructions;
1153
1154 /* opcode selection */
1155 if (emitInfo->EmitHighLevelInstructions) {
1156 if (emitInfo->EmitCondCodes) {
1157 if (n->Opcode == IR_CONT_IF_TRUE ||
1158 n->Opcode == IR_CONT_IF_FALSE)
1159 opcode = OPCODE_CONT;
1160 else
1161 opcode = OPCODE_BRK;
1162 }
1163 else {
1164 if (n->Opcode == IR_CONT_IF_TRUE)
1165 opcode = OPCODE_CONT1;
1166 else if (n->Opcode == IR_CONT_IF_FALSE)
1167 opcode = OPCODE_CONT0;
1168 else if (n->Opcode == IR_BREAK_IF_TRUE)
1169 opcode = OPCODE_BRK1;
1170 else if (n->Opcode == IR_BREAK_IF_FALSE)
1171 opcode = OPCODE_BRK0;
1172 }
1173 }
1174 else {
1175 opcode = OPCODE_BRA;
1176 }
1177
1178 inst = new_instruction(emitInfo, opcode);
1179 if (emitInfo->EmitCondCodes) {
1180 inst->DstReg.CondMask = breakTrue ? COND_NE : COND_EQ;
1181 }
1182 else {
1183 /* BRK0, BRK1, CONT0, CONT1 uses SrcReg[0] as the condition */
1184 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
1185 }
1186 return inst;
1187 }
1188
1189
1190
1191 /**
1192 * Remove any SWIZZLE_NIL terms from given swizzle mask (smear prev term).
1193 * Ex: fix_swizzle("zyNN") -> "zyyy"
1194 */
1195 static GLuint
1196 fix_swizzle(GLuint swizzle)
1197 {
1198 GLuint swz[4], i;
1199 for (i = 0; i < 4; i++) {
1200 swz[i] = GET_SWZ(swizzle, i);
1201 if (swz[i] == SWIZZLE_NIL) {
1202 swz[i] = swz[i - 1];
1203 }
1204 }
1205 return MAKE_SWIZZLE4(swz[0], swz[1], swz[2], swz[3]);
1206 }
1207
1208
1209 /**
1210 * Return the number of components actually named by the swizzle.
1211 * Recall that swizzles may have undefined/don't-care values.
1212 */
1213 static GLuint
1214 swizzle_size(GLuint swizzle)
1215 {
1216 GLuint size = 0, i;
1217 for (i = 0; i < 4; i++) {
1218 GLuint swz = GET_SWZ(swizzle, i);
1219 size += (swz >= 0 && swz <= 3);
1220 }
1221 return size;
1222 }
1223
1224
1225 static struct prog_instruction *
1226 emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n)
1227 {
1228 GLuint swizzle;
1229
1230 (void) emit(emitInfo, n->Children[0]);
1231
1232 #ifdef DEBUG
1233 {
1234 GLuint s = n->Children[0]->Store->Swizzle;
1235 assert(GET_SWZ(s, 0) != SWIZZLE_NIL);
1236 assert(GET_SWZ(s, 1) != SWIZZLE_NIL);
1237 assert(GET_SWZ(s, 2) != SWIZZLE_NIL);
1238 assert(GET_SWZ(s, 3) != SWIZZLE_NIL);
1239 }
1240 #endif
1241 /* For debug: n->Var = n->Children[0]->Var; */
1242
1243 /* "pull-up" the child's storage info, applying our swizzle info */
1244 n->Store->File = n->Children[0]->Store->File;
1245 n->Store->Index = n->Children[0]->Store->Index;
1246 n->Store->Size = swizzle_size(n->Store->Swizzle);
1247 #if 0
1248 printf("Emit Swizzle reg %d chSize %d size %d swz %s\n",
1249 n->Store->Index, n->Children[0]->Store->Size,
1250 n->Store->Size,
1251 _mesa_swizzle_string(n->Store->Swizzle, 0, 0));
1252 #endif
1253
1254 /* apply this swizzle to child's swizzle to get composed swizzle */
1255 swizzle = fix_swizzle(n->Store->Swizzle); /* remove the don't care terms */
1256 n->Store->Swizzle = swizzle_swizzle(n->Children[0]->Store->Swizzle,
1257 swizzle);
1258
1259 return NULL;
1260 }
1261
1262
1263 /**
1264 * Dereference array element. Just resolve storage for the array
1265 * element represented by this node.
1266 */
1267 static struct prog_instruction *
1268 emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n)
1269 {
1270 assert(n->Store);
1271 assert(n->Store->File != PROGRAM_UNDEFINED);
1272 assert(n->Store->Size > 0);
1273
1274 if (n->Store->File == PROGRAM_STATE_VAR) {
1275 n->Store->Index = _slang_alloc_statevar(n, emitInfo->prog->Parameters);
1276 return NULL;
1277 }
1278
1279 if (n->Children[1]->Opcode == IR_FLOAT) {
1280 /* Constant index */
1281 const GLint arrayAddr = n->Children[0]->Store->Index;
1282 const GLint index = (GLint) n->Children[1]->Value[0];
1283 n->Store->Index = arrayAddr + index;
1284 }
1285 else {
1286 /* Variable index - PROBLEM */
1287 const GLint arrayAddr = n->Children[0]->Store->Index;
1288 const GLint index = 0;
1289 _mesa_problem(NULL, "variable array indexes not supported yet!");
1290 n->Store->Index = arrayAddr + index;
1291 }
1292 return NULL; /* no instruction */
1293 }
1294
1295
1296 /**
1297 * Resolve storage for accessing a structure field.
1298 */
1299 static struct prog_instruction *
1300 emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n)
1301 {
1302 if (n->Store->File == PROGRAM_STATE_VAR) {
1303 n->Store->Index = _slang_alloc_statevar(n, emitInfo->prog->Parameters);
1304 }
1305 else {
1306 GLint offset = n->FieldOffset / 4;
1307 assert(n->Children[0]->Store->Index >= 0);
1308 n->Store->Index = n->Children[0]->Store->Index + offset;
1309 if (n->Store->Size == 1) {
1310 GLint swz = n->FieldOffset % 4;
1311 n->Store->Swizzle = MAKE_SWIZZLE4(swz, swz, swz, swz);
1312 }
1313 else {
1314 n->Store->Swizzle = SWIZZLE_XYZW;
1315 }
1316 }
1317 return NULL; /* no instruction */
1318 }
1319
1320
1321 static struct prog_instruction *
1322 emit(slang_emit_info *emitInfo, slang_ir_node *n)
1323 {
1324 struct prog_instruction *inst;
1325 if (!n)
1326 return NULL;
1327
1328 switch (n->Opcode) {
1329 case IR_SEQ:
1330 /* sequence of two sub-trees */
1331 assert(n->Children[0]);
1332 assert(n->Children[1]);
1333 emit(emitInfo, n->Children[0]);
1334 inst = emit(emitInfo, n->Children[1]);
1335 #if 0
1336 assert(!n->Store);
1337 #endif
1338 n->Store = n->Children[1]->Store;
1339 return inst;
1340
1341 case IR_SCOPE:
1342 /* new variable scope */
1343 _slang_push_var_table(emitInfo->vt);
1344 inst = emit(emitInfo, n->Children[0]);
1345 _slang_pop_var_table(emitInfo->vt);
1346 return inst;
1347
1348 case IR_VAR_DECL:
1349 /* Variable declaration - allocate a register for it */
1350 assert(n->Store);
1351 assert(n->Store->File != PROGRAM_UNDEFINED);
1352 assert(n->Store->Size > 0);
1353 /*assert(n->Store->Index < 0);*/
1354 if (!n->Var || n->Var->isTemp) {
1355 /* a nameless/temporary variable, will be freed after first use */
1356 /*NEW*/
1357 if (n->Store->Index < 0 && !_slang_alloc_temp(emitInfo->vt, n->Store)) {
1358 slang_info_log_error(emitInfo->log,
1359 "Ran out of registers, too many temporaries");
1360 return NULL;
1361 }
1362 }
1363 else {
1364 /* a regular variable */
1365 _slang_add_variable(emitInfo->vt, n->Var);
1366 if (!_slang_alloc_var(emitInfo->vt, n->Store)) {
1367 slang_info_log_error(emitInfo->log,
1368 "Ran out of registers, too many variables");
1369 return NULL;
1370 }
1371 /*
1372 printf("IR_VAR_DECL %s %d store %p\n",
1373 (char*) n->Var->a_name, n->Store->Index, (void*) n->Store);
1374 */
1375 assert(n->Var->aux == n->Store);
1376 }
1377 if (emitInfo->EmitComments) {
1378 /* emit NOP with comment describing the variable's storage location */
1379 char s[1000];
1380 sprintf(s, "TEMP[%d]%s = variable %s (size %d)",
1381 n->Store->Index,
1382 _mesa_swizzle_string(n->Store->Swizzle, 0, GL_FALSE),
1383 (n->Var ? (char *) n->Var->a_name : "anonymous"),
1384 n->Store->Size);
1385 inst = emit_comment(emitInfo, s);
1386 return inst;
1387 }
1388 return NULL;
1389
1390 case IR_VAR:
1391 /* Reference to a variable
1392 * Storage should have already been resolved/allocated.
1393 */
1394 assert(n->Store);
1395 assert(n->Store->File != PROGRAM_UNDEFINED);
1396
1397 if (n->Store->File == PROGRAM_STATE_VAR &&
1398 n->Store->Index < 0) {
1399 n->Store->Index = _slang_alloc_statevar(n, emitInfo->prog->Parameters);
1400 }
1401
1402 if (n->Store->Index < 0) {
1403 printf("#### VAR %s not allocated!\n", (char*)n->Var->a_name);
1404 }
1405 assert(n->Store->Index >= 0);
1406 assert(n->Store->Size > 0);
1407 break;
1408
1409 case IR_ELEMENT:
1410 return emit_array_element(emitInfo, n);
1411 case IR_FIELD:
1412 return emit_struct_field(emitInfo, n);
1413 case IR_SWIZZLE:
1414 return emit_swizzle(emitInfo, n);
1415
1416 case IR_I_TO_F:
1417 /* just move */
1418 emit(emitInfo, n->Children[0]);
1419 inst = new_instruction(emitInfo, OPCODE_MOV);
1420 if (!n->Store) {
1421 if (!alloc_temp_storage(emitInfo, n, 1))
1422 return NULL;
1423 }
1424 storage_to_dst_reg(&inst->DstReg, n->Store, n->Writemask);
1425 storage_to_src_reg(&inst->SrcReg[0], n->Children[0]->Store);
1426 if (emitInfo->EmitComments)
1427 inst->Comment = _mesa_strdup("int to float");
1428 return NULL;
1429
1430 /* Simple arithmetic */
1431 /* unary */
1432 case IR_RSQ:
1433 case IR_RCP:
1434 case IR_FLOOR:
1435 case IR_FRAC:
1436 case IR_F_TO_I:
1437 case IR_ABS:
1438 case IR_SIN:
1439 case IR_COS:
1440 case IR_DDX:
1441 case IR_DDY:
1442 case IR_NOISE1:
1443 case IR_NOISE2:
1444 case IR_NOISE3:
1445 case IR_NOISE4:
1446 /* binary */
1447 case IR_ADD:
1448 case IR_SUB:
1449 case IR_MUL:
1450 case IR_DOT4:
1451 case IR_DOT3:
1452 case IR_CROSS:
1453 case IR_MIN:
1454 case IR_MAX:
1455 case IR_SEQUAL:
1456 case IR_SNEQUAL:
1457 case IR_SGE:
1458 case IR_SGT:
1459 case IR_SLE:
1460 case IR_SLT:
1461 case IR_POW:
1462 case IR_EXP:
1463 case IR_EXP2:
1464 /* trinary operators */
1465 case IR_LRP:
1466 return emit_arith(emitInfo, n);
1467
1468 case IR_EQUAL:
1469 case IR_NOTEQUAL:
1470 return emit_compare(emitInfo, n);
1471
1472 case IR_CLAMP:
1473 return emit_clamp(emitInfo, n);
1474 case IR_TEX:
1475 case IR_TEXB:
1476 case IR_TEXP:
1477 return emit_tex(emitInfo, n);
1478 case IR_NEG:
1479 return emit_negation(emitInfo, n);
1480 case IR_FLOAT:
1481 /* find storage location for this float constant */
1482 n->Store->Index = _mesa_add_unnamed_constant(emitInfo->prog->Parameters,
1483 n->Value,
1484 n->Store->Size,
1485 &n->Store->Swizzle);
1486 if (n->Store->Index < 0) {
1487 slang_info_log_error(emitInfo->log, "Ran out of space for constants");
1488 return NULL;
1489 }
1490 return NULL;
1491
1492 case IR_MOVE:
1493 return emit_move(emitInfo, n);
1494
1495 case IR_COND:
1496 return emit_cond(emitInfo, n);
1497
1498 case IR_NOT:
1499 return emit_not(emitInfo, n);
1500
1501 case IR_LABEL:
1502 return emit_label(emitInfo, n);
1503 case IR_JUMP:
1504 assert(n);
1505 assert(n->Label);
1506 return emit_jump(emitInfo, n);
1507 case IR_KILL:
1508 return emit_kill(emitInfo);
1509
1510 case IR_IF:
1511 return emit_if(emitInfo, n);
1512
1513 case IR_LOOP:
1514 return emit_loop(emitInfo, n);
1515 case IR_BREAK_IF_FALSE:
1516 case IR_CONT_IF_FALSE:
1517 return emit_cont_break_if(emitInfo, n, GL_FALSE);
1518 case IR_BREAK_IF_TRUE:
1519 case IR_CONT_IF_TRUE:
1520 return emit_cont_break_if(emitInfo, n, GL_TRUE);
1521 case IR_BREAK:
1522 /* fall-through */
1523 case IR_CONT:
1524 return emit_cont_break(emitInfo, n);
1525
1526 case IR_BEGIN_SUB:
1527 return new_instruction(emitInfo, OPCODE_BGNSUB);
1528 case IR_END_SUB:
1529 return new_instruction(emitInfo, OPCODE_ENDSUB);
1530 case IR_RETURN:
1531 return new_instruction(emitInfo, OPCODE_RET);
1532
1533 case IR_NOP:
1534 return NULL;
1535
1536 default:
1537 _mesa_problem(NULL, "Unexpected IR opcode in emit()\n");
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 }