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