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