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