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