2 * Mesa 3-D graphics library
5 * Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
27 * Emit program instructions (PI code) from IR trees.
34 *** To emit GPU instructions, we basically just do an in-order traversal
43 #include "prog_instruction.h"
44 #include "prog_parameter.h"
45 #include "prog_print.h"
46 #include "slang_builtin.h"
47 #include "slang_emit.h"
48 #include "slang_mem.h"
51 #define PEEPHOLE_OPTIMIZATIONS 1
59 struct gl_program
*prog
;
60 struct gl_program
**Subroutines
;
61 GLuint NumSubroutines
;
63 /* code-gen options */
64 GLboolean EmitHighLevelInstructions
;
65 GLboolean EmitCondCodes
;
66 GLboolean EmitComments
;
67 GLboolean EmitBeginEndSub
; /* XXX TEMPORARY */
72 static struct gl_program
*
73 new_subroutine(slang_emit_info
*emitInfo
, GLuint
*id
)
75 GET_CURRENT_CONTEXT(ctx
);
76 const GLuint n
= emitInfo
->NumSubroutines
;
78 emitInfo
->Subroutines
= (struct gl_program
**)
79 _mesa_realloc(emitInfo
->Subroutines
,
80 n
* sizeof(struct gl_program
),
81 (n
+ 1) * sizeof(struct gl_program
));
82 emitInfo
->Subroutines
[n
] = _mesa_new_program(ctx
, emitInfo
->prog
->Target
, 0);
83 emitInfo
->Subroutines
[n
]->Parameters
= emitInfo
->prog
->Parameters
;
84 emitInfo
->NumSubroutines
++;
86 return emitInfo
->Subroutines
[n
];
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.
96 writemask_to_swizzle(GLuint writemask
)
98 if (writemask
== WRITEMASK_X
)
100 if (writemask
== WRITEMASK_Y
)
102 if (writemask
== WRITEMASK_Z
)
104 if (writemask
== WRITEMASK_W
)
106 return SWIZZLE_XYZW
; /* shouldn't be hit */
111 * Swizzle a swizzle. That is, return swz2(swz1)
114 swizzle_swizzle(GLuint swz1
, GLuint swz2
)
117 for (i
= 0; i
< 4; i
++) {
118 GLuint c
= GET_SWZ(swz2
, i
);
119 s
[i
] = GET_SWZ(swz1
, c
);
121 swz
= MAKE_SWIZZLE4(s
[0], s
[1], s
[2], s
[3]);
127 _slang_new_ir_storage(enum register_file file
, GLint index
, GLint size
)
129 slang_ir_storage
*st
;
130 st
= (slang_ir_storage
*) _slang_alloc(sizeof(slang_ir_storage
));
135 st
->Swizzle
= SWIZZLE_NOOP
;
142 * Allocate temporary storage for an intermediate result (such as for
143 * a multiply or add, etc.
146 alloc_temp_storage(slang_emit_info
*emitInfo
, slang_ir_node
*n
, GLint size
)
151 n
->Store
= _slang_new_ir_storage(PROGRAM_TEMPORARY
, -1, size
);
152 if (!_slang_alloc_temp(emitInfo
->vt
, n
->Store
)) {
153 slang_info_log_error(emitInfo
->log
,
154 "Ran out of registers, too many temporaries");
155 _slang_free(n
->Store
);
164 * Free temporary storage, if n->Store is, in fact, temp storage.
168 free_temp_storage(slang_var_table
*vt
, slang_ir_node
*n
)
170 if (n
->Store
->File
== PROGRAM_TEMPORARY
&&
171 n
->Store
->Index
>= 0 &&
172 n
->Opcode
!= IR_SWIZZLE
) {
173 if (_slang_is_temp(vt
, n
->Store
)) {
174 _slang_free_temp(vt
, n
->Store
);
175 n
->Store
->Index
= -1;
177 /*_mesa_free(n->Store);*/ /* XXX leak */
185 * Convert IR storage to an instruction dst register.
188 storage_to_dst_reg(struct prog_dst_register
*dst
, const slang_ir_storage
*st
,
191 assert(st
->Index
>= 0);
192 dst
->File
= st
->File
;
193 dst
->Index
= st
->Index
;
194 assert(st
->File
!= PROGRAM_UNDEFINED
);
195 assert(st
->Size
>= 1);
196 assert(st
->Size
<= 4);
198 GLuint comp
= GET_SWZ(st
->Swizzle
, 0);
200 dst
->WriteMask
= WRITEMASK_X
<< comp
;
203 dst
->WriteMask
= writemask
;
209 * Convert IR storage to an instruction src register.
212 storage_to_src_reg(struct prog_src_register
*src
, const slang_ir_storage
*st
)
214 static const GLuint defaultSwizzle
[4] = {
215 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_X
, SWIZZLE_X
, SWIZZLE_X
),
216 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Z
, SWIZZLE_W
),
217 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Z
, SWIZZLE_W
),
218 MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Z
, SWIZZLE_W
)
220 assert(st
->File
>= 0);
221 assert(st
->File
< PROGRAM_UNDEFINED
);
222 assert(st
->Size
>= 1);
223 assert(st
->Size
<= 4);
224 src
->File
= st
->File
;
225 src
->Index
= st
->Index
;
226 if (st
->Swizzle
!= SWIZZLE_NOOP
)
227 src
->Swizzle
= st
->Swizzle
;
229 src
->Swizzle
= defaultSwizzle
[st
->Size
- 1]; /*XXX really need this?*/
231 assert(GET_SWZ(src
->Swizzle
, 0) <= 3);
232 assert(GET_SWZ(src
->Swizzle
, 1) <= 3);
233 assert(GET_SWZ(src
->Swizzle
, 2) <= 3);
234 assert(GET_SWZ(src
->Swizzle
, 3) <= 3);
239 * Setup an instrucion src register to point to a scalar constant.
242 constant_to_src_reg(struct prog_src_register
*src
, GLfloat val
,
243 slang_emit_info
*emitInfo
)
250 zeroReg
= _mesa_add_unnamed_constant(emitInfo
->prog
->Parameters
,
251 value
, 1, &zeroSwizzle
);
252 assert(zeroReg
>= 0);
254 src
->File
= PROGRAM_CONSTANT
;
255 src
->Index
= zeroReg
;
256 src
->Swizzle
= zeroSwizzle
;
261 * Add new instruction at end of given program.
262 * \param prog the program to append instruction onto
263 * \param opcode opcode for the new instruction
264 * \return pointer to the new instruction
266 static struct prog_instruction
*
267 new_instruction(slang_emit_info
*emitInfo
, gl_inst_opcode opcode
)
269 struct gl_program
*prog
= emitInfo
->prog
;
270 struct prog_instruction
*inst
;
273 /* print prev inst */
274 if (prog
->NumInstructions
> 0) {
275 _mesa_print_instruction(prog
->Instructions
+ prog
->NumInstructions
- 1);
278 prog
->Instructions
= _mesa_realloc_instructions(prog
->Instructions
,
279 prog
->NumInstructions
,
280 prog
->NumInstructions
+ 1);
281 inst
= prog
->Instructions
+ prog
->NumInstructions
;
282 prog
->NumInstructions
++;
283 _mesa_init_instructions(inst
, 1);
284 inst
->Opcode
= opcode
;
285 inst
->BranchTarget
= -1; /* invalid */
287 printf("New inst %d: %p %s\n", prog->NumInstructions-1,(void*)inst,
288 _mesa_opcode_string(inst->Opcode));
295 * Return pointer to last instruction in program.
297 static struct prog_instruction
*
298 prev_instruction(slang_emit_info
*emitInfo
)
300 struct gl_program
*prog
= emitInfo
->prog
;
301 if (prog
->NumInstructions
== 0)
304 return prog
->Instructions
+ prog
->NumInstructions
- 1;
308 static struct prog_instruction
*
309 emit(slang_emit_info
*emitInfo
, slang_ir_node
*n
);
313 * Return an annotation string for given node's storage.
316 storage_annotation(const slang_ir_node
*n
, const struct gl_program
*prog
)
319 const slang_ir_storage
*st
= n
->Store
;
320 static char s
[100] = "";
323 return _mesa_strdup("");
326 case PROGRAM_CONSTANT
:
327 if (st
->Index
>= 0) {
328 const GLfloat
*val
= prog
->Parameters
->ParameterValues
[st
->Index
];
329 if (st
->Swizzle
== SWIZZLE_NOOP
)
330 sprintf(s
, "{%g, %g, %g, %g}", val
[0], val
[1], val
[2], val
[3]);
332 sprintf(s
, "%g", val
[GET_SWZ(st
->Swizzle
, 0)]);
336 case PROGRAM_TEMPORARY
:
338 sprintf(s
, "%s", (char *) n
->Var
->a_name
);
340 sprintf(s
, "t[%d]", st
->Index
);
342 case PROGRAM_STATE_VAR
:
343 case PROGRAM_UNIFORM
:
344 sprintf(s
, "%s", prog
->Parameters
->Parameters
[st
->Index
].Name
);
346 case PROGRAM_VARYING
:
347 sprintf(s
, "%s", prog
->Varying
->Parameters
[st
->Index
].Name
);
350 sprintf(s
, "input[%d]", st
->Index
);
353 sprintf(s
, "output[%d]", st
->Index
);
358 return _mesa_strdup(s
);
366 * Return an annotation string for an instruction.
369 instruction_annotation(gl_inst_opcode opcode
, char *dstAnnot
,
370 char *srcAnnot0
, char *srcAnnot1
, char *srcAnnot2
)
373 const char *operator;
378 len
+= strlen(dstAnnot
);
380 dstAnnot
= _mesa_strdup("");
383 len
+= strlen(srcAnnot0
);
385 srcAnnot0
= _mesa_strdup("");
388 len
+= strlen(srcAnnot1
);
390 srcAnnot1
= _mesa_strdup("");
393 len
+= strlen(srcAnnot2
);
395 srcAnnot2
= _mesa_strdup("");
426 s
= (char *) malloc(len
);
427 sprintf(s
, "%s = %s %s %s %s", dstAnnot
,
428 srcAnnot0
, operator, srcAnnot1
, srcAnnot2
);
429 assert(_mesa_strlen(s
) < len
);
444 * Emit an instruction that's just a comment.
446 static struct prog_instruction
*
447 emit_comment(slang_emit_info
*emitInfo
, const char *s
)
449 struct prog_instruction
*inst
= new_instruction(emitInfo
, OPCODE_NOP
);
451 inst
->Comment
= _mesa_strdup(s
);
458 * Generate code for a simple arithmetic instruction.
459 * Either 1, 2 or 3 operands.
461 static struct prog_instruction
*
462 emit_arith(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
464 struct prog_instruction
*inst
;
465 const slang_ir_info
*info
= _slang_ir_info(n
->Opcode
);
466 char *srcAnnot
[3], *dstAnnot
;
470 assert(info
->InstOpcode
!= OPCODE_NOP
);
472 srcAnnot
[0] = srcAnnot
[1] = srcAnnot
[2] = dstAnnot
= NULL
;
474 #if PEEPHOLE_OPTIMIZATIONS
475 /* Look for MAD opportunity */
476 if (info
->NumParams
== 2 &&
477 n
->Opcode
== IR_ADD
&& n
->Children
[0]->Opcode
== IR_MUL
) {
478 /* found pattern IR_ADD(IR_MUL(A, B), C) */
479 emit(emitInfo
, n
->Children
[0]->Children
[0]); /* A */
480 emit(emitInfo
, n
->Children
[0]->Children
[1]); /* B */
481 emit(emitInfo
, n
->Children
[1]); /* C */
482 /* generate MAD instruction */
483 inst
= new_instruction(emitInfo
, OPCODE_MAD
);
484 /* operands: A, B, C: */
485 storage_to_src_reg(&inst
->SrcReg
[0], n
->Children
[0]->Children
[0]->Store
);
486 storage_to_src_reg(&inst
->SrcReg
[1], n
->Children
[0]->Children
[1]->Store
);
487 storage_to_src_reg(&inst
->SrcReg
[2], n
->Children
[1]->Store
);
488 free_temp_storage(emitInfo
->vt
, n
->Children
[0]->Children
[0]);
489 free_temp_storage(emitInfo
->vt
, n
->Children
[0]->Children
[1]);
490 free_temp_storage(emitInfo
->vt
, n
->Children
[1]);
492 else if (info
->NumParams
== 2 &&
493 n
->Opcode
== IR_ADD
&& n
->Children
[1]->Opcode
== IR_MUL
) {
494 /* found pattern IR_ADD(A, IR_MUL(B, C)) */
495 emit(emitInfo
, n
->Children
[0]); /* A */
496 emit(emitInfo
, n
->Children
[1]->Children
[0]); /* B */
497 emit(emitInfo
, n
->Children
[1]->Children
[1]); /* C */
498 /* generate MAD instruction */
499 inst
= new_instruction(emitInfo
, OPCODE_MAD
);
500 /* operands: B, C, A */
501 storage_to_src_reg(&inst
->SrcReg
[0], n
->Children
[1]->Children
[0]->Store
);
502 storage_to_src_reg(&inst
->SrcReg
[1], n
->Children
[1]->Children
[1]->Store
);
503 storage_to_src_reg(&inst
->SrcReg
[2], n
->Children
[0]->Store
);
504 free_temp_storage(emitInfo
->vt
, n
->Children
[1]->Children
[0]);
505 free_temp_storage(emitInfo
->vt
, n
->Children
[1]->Children
[1]);
506 free_temp_storage(emitInfo
->vt
, n
->Children
[0]);
513 /* gen code for children */
514 for (i
= 0; i
< info
->NumParams
; i
++) {
515 emit(emitInfo
, n
->Children
[i
]);
516 if (!n
->Children
[i
] || !n
->Children
[i
]->Store
) {
522 /* gen this instruction and src registers */
523 inst
= new_instruction(emitInfo
, info
->InstOpcode
);
524 for (i
= 0; i
< info
->NumParams
; i
++)
525 storage_to_src_reg(&inst
->SrcReg
[i
], n
->Children
[i
]->Store
);
528 for (i
= 0; i
< info
->NumParams
; i
++)
529 srcAnnot
[i
] = storage_annotation(n
->Children
[i
], emitInfo
->prog
);
532 for (i
= 0; i
< info
->NumParams
; i
++)
533 free_temp_storage(emitInfo
->vt
, n
->Children
[i
]);
538 /* XXX this size isn't correct, it depends on the operands */
539 if (!alloc_temp_storage(emitInfo
, n
, info
->ResultSize
))
542 storage_to_dst_reg(&inst
->DstReg
, n
->Store
, n
->Writemask
);
544 dstAnnot
= storage_annotation(n
, emitInfo
->prog
);
546 inst
->Comment
= instruction_annotation(inst
->Opcode
, dstAnnot
, srcAnnot
[0],
547 srcAnnot
[1], srcAnnot
[2]);
549 /*_mesa_print_instruction(inst);*/
555 * Emit code for == and != operators. These could normally be handled
556 * by emit_arith() except we need to be able to handle structure comparisons.
558 static struct prog_instruction
*
559 emit_compare(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
561 struct prog_instruction
*inst
;
564 assert(n
->Opcode
== IR_EQUAL
|| n
->Opcode
== IR_NOTEQUAL
);
566 /* gen code for children */
567 emit(emitInfo
, n
->Children
[0]);
568 emit(emitInfo
, n
->Children
[1]);
570 assert(n
->Children
[0]->Store
->Size
== n
->Children
[1]->Store
->Size
);
571 size
= n
->Children
[0]->Store
->Size
;
574 gl_inst_opcode opcode
;
577 if (!alloc_temp_storage(emitInfo
, n
, 1)) /* 1 bool */
581 opcode
= n
->Opcode
== IR_EQUAL
? OPCODE_SEQ
: OPCODE_SNE
;
582 inst
= new_instruction(emitInfo
, opcode
);
583 storage_to_src_reg(&inst
->SrcReg
[0], n
->Children
[0]->Store
);
584 storage_to_src_reg(&inst
->SrcReg
[1], n
->Children
[1]->Store
);
585 storage_to_dst_reg(&inst
->DstReg
, n
->Store
, n
->Writemask
);
587 else if (size
<= 4) {
589 gl_inst_opcode dotOp
;
593 if (!alloc_temp_storage(emitInfo
, n
, size
)) /* 'size' bools */
599 swizzle
= SWIZZLE_XYZW
;
601 else if (size
== 3) {
603 swizzle
= SWIZZLE_XYZW
;
608 swizzle
= MAKE_SWIZZLE4(SWIZZLE_X
, SWIZZLE_Y
, SWIZZLE_Y
, SWIZZLE_Y
);
611 /* Compute equality, inequality (tmp1 = (A ?= B)) */
612 inst
= new_instruction(emitInfo
, OPCODE_SNE
);
613 storage_to_src_reg(&inst
->SrcReg
[0], n
->Children
[0]->Store
);
614 storage_to_src_reg(&inst
->SrcReg
[1], n
->Children
[1]->Store
);
615 storage_to_dst_reg(&inst
->DstReg
, n
->Store
, n
->Writemask
);
616 inst
->Comment
= _mesa_strdup("Compare values");
618 /* Compute tmp2 = DOT(tmp1, tmp1) (reduction) */
619 inst
= new_instruction(emitInfo
, dotOp
);
620 storage_to_src_reg(&inst
->SrcReg
[0], n
->Store
);
621 storage_to_src_reg(&inst
->SrcReg
[1], n
->Store
);
622 inst
->SrcReg
[0].Swizzle
= inst
->SrcReg
[1].Swizzle
= swizzle
; /*override*/
623 free_temp_storage(emitInfo
->vt
, n
); /* free tmp1 */
624 if (!alloc_temp_storage(emitInfo
, n
, 1)) /* alloc tmp2 */
626 storage_to_dst_reg(&inst
->DstReg
, n
->Store
, n
->Writemask
);
627 inst
->Comment
= _mesa_strdup("Reduce vec to bool");
629 if (n
->Opcode
== IR_EQUAL
) {
630 /* compute tmp2.x = !tmp2.x via tmp2.x = (tmp2.x == 0) */
631 inst
= new_instruction(emitInfo
, OPCODE_SEQ
);
632 storage_to_src_reg(&inst
->SrcReg
[0], n
->Store
);
633 constant_to_src_reg(&inst
->SrcReg
[1], 0.0, emitInfo
);
634 storage_to_dst_reg(&inst
->DstReg
, n
->Store
, n
->Writemask
);
635 inst
->Comment
= _mesa_strdup("Invert true/false");
639 /* size > 4, struct compare */
641 GLint i
, num
= (n
->Children
[0]->Store
->Size
+ 3) / 4;
642 /*printf("BEGIN COMPARE size %d\n", num);*/
643 for (i
= 0; i
< num
; i
++) {
644 inst
= new_instruction(emitInfo
, opcode
);
645 inst
->SrcReg
[0].File
= n
->Children
[0]->Store
->File
;
646 inst
->SrcReg
[0].Index
= n
->Children
[0]->Store
->Index
+ i
;
647 inst
->SrcReg
[1].File
= n
->Children
[1]->Store
->File
;
648 inst
->SrcReg
[1].Index
= n
->Children
[1]->Store
->Index
+ i
;
649 inst
->DstReg
.File
= n
->Store
->File
;
650 inst
->DstReg
.Index
= n
->Store
->Index
;
652 inst
->CondUpdate
= 1; /* update cond code */
654 inst
->DstReg
.CondMask
= COND_NE
; /* update if !=0 */
656 /*_mesa_print_instruction(inst);*/
658 storage_to_dst_reg(&inst
->DstReg
, n
->Store
, n
->Writemask
);
660 _mesa_problem(NULL
, "struct comparison not implemented yet");
665 free_temp_storage(emitInfo
->vt
, n
->Children
[0]);
666 free_temp_storage(emitInfo
->vt
, n
->Children
[1]);
674 * Generate code for an IR_CLAMP instruction.
676 static struct prog_instruction
*
677 emit_clamp(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
679 struct prog_instruction
*inst
;
681 assert(n
->Opcode
== IR_CLAMP
);
687 inst
= emit(emitInfo
, n
->Children
[0]);
689 /* If lower limit == 0.0 and upper limit == 1.0,
690 * set prev instruction's SaturateMode field to SATURATE_ZERO_ONE.
692 * emit OPCODE_MIN, OPCODE_MAX sequence.
695 /* XXX this isn't quite finished yet */
696 if (n
->Children
[1]->Opcode
== IR_FLOAT
&&
697 n
->Children
[1]->Value
[0] == 0.0 &&
698 n
->Children
[1]->Value
[1] == 0.0 &&
699 n
->Children
[1]->Value
[2] == 0.0 &&
700 n
->Children
[1]->Value
[3] == 0.0 &&
701 n
->Children
[2]->Opcode
== IR_FLOAT
&&
702 n
->Children
[2]->Value
[0] == 1.0 &&
703 n
->Children
[2]->Value
[1] == 1.0 &&
704 n
->Children
[2]->Value
[2] == 1.0 &&
705 n
->Children
[2]->Value
[3] == 1.0) {
707 inst
= prev_instruction(prog
);
709 if (inst
&& inst
->Opcode
!= OPCODE_NOP
) {
710 /* and prev instruction's DstReg matches n->Children[0]->Store */
711 inst
->SaturateMode
= SATURATE_ZERO_ONE
;
712 n
->Store
= n
->Children
[0]->Store
;
719 if (!alloc_temp_storage(emitInfo
, n
, n
->Children
[0]->Store
->Size
))
722 emit(emitInfo
, n
->Children
[1]);
723 emit(emitInfo
, n
->Children
[2]);
725 /* tmp = max(ch[0], ch[1]) */
726 inst
= new_instruction(emitInfo
, OPCODE_MAX
);
727 storage_to_dst_reg(&inst
->DstReg
, n
->Store
, n
->Writemask
);
728 storage_to_src_reg(&inst
->SrcReg
[0], n
->Children
[0]->Store
);
729 storage_to_src_reg(&inst
->SrcReg
[1], n
->Children
[1]->Store
);
731 /* tmp = min(tmp, ch[2]) */
732 inst
= new_instruction(emitInfo
, OPCODE_MIN
);
733 storage_to_dst_reg(&inst
->DstReg
, n
->Store
, n
->Writemask
);
734 storage_to_src_reg(&inst
->SrcReg
[0], n
->Store
);
735 storage_to_src_reg(&inst
->SrcReg
[1], n
->Children
[2]->Store
);
741 static struct prog_instruction
*
742 emit_negation(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
744 /* Implement as MOV dst, -src; */
745 /* XXX we could look at the previous instruction and in some circumstances
746 * modify it to accomplish the negation.
748 struct prog_instruction
*inst
;
750 emit(emitInfo
, n
->Children
[0]);
753 if (!alloc_temp_storage(emitInfo
, n
, n
->Children
[0]->Store
->Size
))
756 inst
= new_instruction(emitInfo
, OPCODE_MOV
);
757 storage_to_dst_reg(&inst
->DstReg
, n
->Store
, n
->Writemask
);
758 storage_to_src_reg(&inst
->SrcReg
[0], n
->Children
[0]->Store
);
759 inst
->SrcReg
[0].NegateBase
= NEGATE_XYZW
;
764 static struct prog_instruction
*
765 emit_label(slang_emit_info
*emitInfo
, const slang_ir_node
*n
)
769 /* XXX this fails in loop tail code - investigate someday */
770 assert(_slang_label_get_location(n
->Label
) < 0);
771 _slang_label_set_location(n
->Label
, emitInfo
->prog
->NumInstructions
,
774 if (_slang_label_get_location(n
->Label
) < 0)
775 _slang_label_set_location(n
->Label
, emitInfo
->prog
->NumInstructions
,
783 * Emit code for an inlined function call (subroutine).
785 static struct prog_instruction
*
786 emit_func(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
788 struct gl_program
*progSave
;
789 struct prog_instruction
*inst
;
792 assert(n
->Opcode
== IR_FUNC
);
795 /* save/push cur program */
796 progSave
= emitInfo
->prog
;
797 emitInfo
->prog
= new_subroutine(emitInfo
, &subroutineId
);
799 _slang_label_set_location(n
->Label
, emitInfo
->prog
->NumInstructions
,
802 if (emitInfo
->EmitBeginEndSub
) {
803 /* BGNSUB isn't a real instruction.
804 * We require a label (i.e. "foobar:") though, if we're going to
805 * print the program in the NV format. The BNGSUB instruction is
806 * really just a NOP to attach the label to.
808 inst
= new_instruction(emitInfo
, OPCODE_BGNSUB
);
809 inst
->Comment
= _mesa_strdup(n
->Label
->Name
);
812 /* body of function: */
813 emit(emitInfo
, n
->Children
[0]);
814 n
->Store
= n
->Children
[0]->Store
;
816 /* add RET instruction now, if needed */
817 inst
= prev_instruction(emitInfo
);
818 if (inst
&& inst
->Opcode
!= OPCODE_RET
) {
819 inst
= new_instruction(emitInfo
, OPCODE_RET
);
822 if (emitInfo
->EmitBeginEndSub
) {
823 inst
= new_instruction(emitInfo
, OPCODE_ENDSUB
);
824 inst
->Comment
= _mesa_strdup(n
->Label
->Name
);
827 /* pop/restore cur program */
828 emitInfo
->prog
= progSave
;
830 /* emit the function call */
831 inst
= new_instruction(emitInfo
, OPCODE_CAL
);
832 /* The branch target is just the subroutine number (changed later) */
833 inst
->BranchTarget
= subroutineId
;
834 inst
->Comment
= _mesa_strdup(n
->Label
->Name
);
835 assert(inst
->BranchTarget
>= 0);
842 * Emit code for a 'return' statement.
844 static struct prog_instruction
*
845 emit_return(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
847 struct prog_instruction
*inst
;
849 assert(n
->Opcode
== IR_RETURN
);
851 inst
= new_instruction(emitInfo
, OPCODE_RET
);
852 inst
->DstReg
.CondMask
= COND_TR
; /* always return */
857 static struct prog_instruction
*
858 emit_kill(slang_emit_info
*emitInfo
)
860 struct prog_instruction
*inst
;
861 /* NV-KILL - discard fragment depending on condition code.
862 * Note that ARB-KILL depends on sign of vector operand.
864 inst
= new_instruction(emitInfo
, OPCODE_KIL_NV
);
865 inst
->DstReg
.CondMask
= COND_TR
; /* always branch */
870 static struct prog_instruction
*
871 emit_tex(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
873 struct prog_instruction
*inst
;
875 (void) emit(emitInfo
, n
->Children
[1]);
877 if (n
->Opcode
== IR_TEX
) {
878 inst
= new_instruction(emitInfo
, OPCODE_TEX
);
880 else if (n
->Opcode
== IR_TEXB
) {
881 inst
= new_instruction(emitInfo
, OPCODE_TXB
);
884 assert(n
->Opcode
== IR_TEXP
);
885 inst
= new_instruction(emitInfo
, OPCODE_TXP
);
889 if (!alloc_temp_storage(emitInfo
, n
, 4))
892 storage_to_dst_reg(&inst
->DstReg
, n
->Store
, n
->Writemask
);
894 /* Child[1] is the coord */
895 assert(n
->Children
[1]->Store
->File
!= PROGRAM_UNDEFINED
);
896 assert(n
->Children
[1]->Store
->Index
>= 0);
897 storage_to_src_reg(&inst
->SrcReg
[0], n
->Children
[1]->Store
);
899 /* Child[0] is the sampler (a uniform which'll indicate the texture unit) */
900 assert(n
->Children
[0]->Store
);
901 /* Store->Index is the sampler index */
902 assert(n
->Children
[0]->Store
->Index
>= 0);
903 /* Store->Size is the texture target */
904 assert(n
->Children
[0]->Store
->Size
>= TEXTURE_1D_INDEX
);
905 assert(n
->Children
[0]->Store
->Size
<= TEXTURE_RECT_INDEX
);
907 inst
->Sampler
= n
->Children
[0]->Store
->Index
; /* i.e. uniform's index */
908 inst
->TexSrcTarget
= n
->Children
[0]->Store
->Size
;
909 inst
->TexSrcUnit
= 27; /* Dummy value; the TexSrcUnit will be computed at
910 * link time, using the sampler uniform's value.
916 static struct prog_instruction
*
917 emit_move(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
919 struct prog_instruction
*inst
;
922 emit(emitInfo
, n
->Children
[0]);
923 if (!n
->Children
[0]->Store
|| n
->Children
[0]->Store
->Index
< 0) {
924 /* an error should have been already recorded */
929 assert(n
->Children
[1]);
930 inst
= emit(emitInfo
, n
->Children
[1]);
932 if (!n
->Children
[1]->Store
|| n
->Children
[1]->Store
->Index
< 0) {
933 if (!emitInfo
->log
->text
) {
934 slang_info_log_error(emitInfo
->log
, "invalid assignment");
939 assert(n
->Children
[1]->Store
->Index
>= 0);
941 /*assert(n->Children[0]->Store->Size == n->Children[1]->Store->Size);*/
943 n
->Store
= n
->Children
[0]->Store
;
945 #if PEEPHOLE_OPTIMIZATIONS
947 _slang_is_temp(emitInfo
->vt
, n
->Children
[1]->Store
) &&
948 (inst
->DstReg
.File
== n
->Children
[1]->Store
->File
) &&
949 (inst
->DstReg
.Index
== n
->Children
[1]->Store
->Index
)) {
950 /* Peephole optimization:
951 * The Right-Hand-Side has its results in a temporary place.
952 * Modify the RHS (and the prev instruction) to store its results
953 * in the destination specified by n->Children[0].
954 * Then, this MOVE is a no-op.
956 if (n
->Children
[1]->Opcode
!= IR_SWIZZLE
)
957 _slang_free_temp(emitInfo
->vt
, n
->Children
[1]->Store
);
958 *n
->Children
[1]->Store
= *n
->Children
[0]->Store
;
959 /* fixup the previous instruction (which stored the RHS result) */
960 assert(n
->Children
[0]->Store
->Index
>= 0);
961 storage_to_dst_reg(&inst
->DstReg
, n
->Children
[0]->Store
, n
->Writemask
);
967 if (n
->Children
[0]->Store
->Size
> 4) {
968 /* move matrix/struct etc (block of registers) */
969 slang_ir_storage dstStore
= *n
->Children
[0]->Store
;
970 slang_ir_storage srcStore
= *n
->Children
[1]->Store
;
971 GLint size
= srcStore
.Size
;
972 ASSERT(n
->Children
[0]->Writemask
== WRITEMASK_XYZW
);
973 ASSERT(n
->Children
[1]->Store
->Swizzle
== SWIZZLE_NOOP
);
977 inst
= new_instruction(emitInfo
, OPCODE_MOV
);
978 inst
->Comment
= _mesa_strdup("IR_MOVE block");
979 storage_to_dst_reg(&inst
->DstReg
, &dstStore
, n
->Writemask
);
980 storage_to_src_reg(&inst
->SrcReg
[0], &srcStore
);
987 /* single register move */
988 char *srcAnnot
, *dstAnnot
;
989 inst
= new_instruction(emitInfo
, OPCODE_MOV
);
990 assert(n
->Children
[0]->Store
->Index
>= 0);
991 storage_to_dst_reg(&inst
->DstReg
, n
->Children
[0]->Store
, n
->Writemask
);
992 storage_to_src_reg(&inst
->SrcReg
[0], n
->Children
[1]->Store
);
993 dstAnnot
= storage_annotation(n
->Children
[0], emitInfo
->prog
);
994 srcAnnot
= storage_annotation(n
->Children
[1], emitInfo
->prog
);
995 inst
->Comment
= instruction_annotation(inst
->Opcode
, dstAnnot
,
996 srcAnnot
, NULL
, NULL
);
998 free_temp_storage(emitInfo
->vt
, n
->Children
[1]);
1005 * An IR_COND node wraps a boolean expression which is used by an
1006 * IF or WHILE test. This is where we'll set condition codes, if needed.
1008 static struct prog_instruction
*
1009 emit_cond(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
1011 struct prog_instruction
*inst
;
1013 assert(n
->Opcode
== IR_COND
);
1015 if (!n
->Children
[0])
1018 /* emit code for the expression */
1019 inst
= emit(emitInfo
, n
->Children
[0]);
1021 if (!n
->Children
[0]->Store
) {
1022 /* error recovery */
1026 assert(n
->Children
[0]->Store
);
1027 /*assert(n->Children[0]->Store->Size == 1);*/
1029 if (emitInfo
->EmitCondCodes
) {
1031 n
->Children
[0]->Store
&&
1032 inst
->DstReg
.File
== n
->Children
[0]->Store
->File
&&
1033 inst
->DstReg
.Index
== n
->Children
[0]->Store
->Index
) {
1034 /* The previous instruction wrote to the register who's value
1035 * we're testing. Just fix that instruction so that the
1036 * condition codes are computed.
1038 inst
->CondUpdate
= GL_TRUE
;
1039 n
->Store
= n
->Children
[0]->Store
;
1043 /* This'll happen for things like "if (i) ..." where no code
1044 * is normally generated for the expression "i".
1045 * Generate a move instruction just to set condition codes.
1047 if (!alloc_temp_storage(emitInfo
, n
, 1))
1049 inst
= new_instruction(emitInfo
, OPCODE_MOV
);
1050 inst
->CondUpdate
= GL_TRUE
;
1051 storage_to_dst_reg(&inst
->DstReg
, n
->Store
, n
->Writemask
);
1052 storage_to_src_reg(&inst
->SrcReg
[0], n
->Children
[0]->Store
);
1053 _slang_free_temp(emitInfo
->vt
, n
->Store
);
1054 inst
->Comment
= _mesa_strdup("COND expr");
1059 /* No-op: the boolean result of the expression is in a regular reg */
1060 n
->Store
= n
->Children
[0]->Store
;
1069 static struct prog_instruction
*
1070 emit_not(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
1072 static const struct {
1073 gl_inst_opcode op
, opNot
;
1075 { OPCODE_SLT
, OPCODE_SGE
},
1076 { OPCODE_SLE
, OPCODE_SGT
},
1077 { OPCODE_SGT
, OPCODE_SLE
},
1078 { OPCODE_SGE
, OPCODE_SLT
},
1079 { OPCODE_SEQ
, OPCODE_SNE
},
1080 { OPCODE_SNE
, OPCODE_SEQ
},
1083 struct prog_instruction
*inst
;
1087 inst
= emit(emitInfo
, n
->Children
[0]);
1089 #if PEEPHOLE_OPTIMIZATIONS
1091 /* if the prev instruction was a comparison instruction, invert it */
1092 for (i
= 0; operators
[i
].op
; i
++) {
1093 if (inst
->Opcode
== operators
[i
].op
) {
1094 inst
->Opcode
= operators
[i
].opNot
;
1095 n
->Store
= n
->Children
[0]->Store
;
1102 /* else, invert using SEQ (v = v == 0) */
1104 if (!alloc_temp_storage(emitInfo
, n
, n
->Children
[0]->Store
->Size
))
1107 inst
= new_instruction(emitInfo
, OPCODE_SEQ
);
1108 storage_to_dst_reg(&inst
->DstReg
, n
->Store
, n
->Writemask
);
1109 storage_to_src_reg(&inst
->SrcReg
[0], n
->Children
[0]->Store
);
1110 constant_to_src_reg(&inst
->SrcReg
[1], 0.0, emitInfo
);
1111 free_temp_storage(emitInfo
->vt
, n
->Children
[0]);
1113 inst
->Comment
= _mesa_strdup("NOT");
1118 static struct prog_instruction
*
1119 emit_if(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
1121 struct gl_program
*prog
= emitInfo
->prog
;
1122 GLuint ifInstLoc
, elseInstLoc
= 0;
1123 GLuint condWritemask
= 0;
1125 /* emit condition expression code */
1127 struct prog_instruction
*inst
;
1128 inst
= emit(emitInfo
, n
->Children
[0]);
1129 if (emitInfo
->EmitCondCodes
) {
1131 /* error recovery */
1134 condWritemask
= inst
->DstReg
.WriteMask
;
1139 assert(n
->Children
[0]->Store
->Size
== 1); /* a bool! */
1142 ifInstLoc
= prog
->NumInstructions
;
1143 if (emitInfo
->EmitHighLevelInstructions
) {
1144 struct prog_instruction
*ifInst
= new_instruction(emitInfo
, OPCODE_IF
);
1145 if (emitInfo
->EmitCondCodes
) {
1146 ifInst
->DstReg
.CondMask
= COND_NE
; /* if cond is non-zero */
1147 /* only test the cond code (1 of 4) that was updated by the
1148 * previous instruction.
1150 ifInst
->DstReg
.CondSwizzle
= writemask_to_swizzle(condWritemask
);
1154 storage_to_src_reg(&ifInst
->SrcReg
[0], n
->Children
[0]->Store
);
1158 /* conditional jump to else, or endif */
1159 struct prog_instruction
*ifInst
= new_instruction(emitInfo
, OPCODE_BRA
);
1160 ifInst
->DstReg
.CondMask
= COND_EQ
; /* BRA if cond is zero */
1161 ifInst
->Comment
= _mesa_strdup("if zero");
1162 ifInst
->DstReg
.CondSwizzle
= writemask_to_swizzle(condWritemask
);
1166 emit(emitInfo
, n
->Children
[1]);
1168 if (n
->Children
[2]) {
1169 /* have else body */
1170 elseInstLoc
= prog
->NumInstructions
;
1171 if (emitInfo
->EmitHighLevelInstructions
) {
1172 (void) new_instruction(emitInfo
, OPCODE_ELSE
);
1175 /* jump to endif instruction */
1176 struct prog_instruction
*inst
;
1177 inst
= new_instruction(emitInfo
, OPCODE_BRA
);
1178 inst
->Comment
= _mesa_strdup("else");
1179 inst
->DstReg
.CondMask
= COND_TR
; /* always branch */
1181 prog
->Instructions
[ifInstLoc
].BranchTarget
= prog
->NumInstructions
;
1182 emit(emitInfo
, n
->Children
[2]);
1186 prog
->Instructions
[ifInstLoc
].BranchTarget
= prog
->NumInstructions
;
1189 if (emitInfo
->EmitHighLevelInstructions
) {
1190 (void) new_instruction(emitInfo
, OPCODE_ENDIF
);
1193 if (n
->Children
[2]) {
1194 prog
->Instructions
[elseInstLoc
].BranchTarget
= prog
->NumInstructions
;
1200 static struct prog_instruction
*
1201 emit_loop(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
1203 struct gl_program
*prog
= emitInfo
->prog
;
1204 struct prog_instruction
*endInst
;
1205 GLuint beginInstLoc
, tailInstLoc
, endInstLoc
;
1208 /* emit OPCODE_BGNLOOP */
1209 beginInstLoc
= prog
->NumInstructions
;
1210 if (emitInfo
->EmitHighLevelInstructions
) {
1211 (void) new_instruction(emitInfo
, OPCODE_BGNLOOP
);
1215 emit(emitInfo
, n
->Children
[0]);
1218 tailInstLoc
= prog
->NumInstructions
;
1219 if (n
->Children
[1]) {
1220 if (emitInfo
->EmitComments
)
1221 emit_comment(emitInfo
, "Loop tail code:");
1222 emit(emitInfo
, n
->Children
[1]);
1225 endInstLoc
= prog
->NumInstructions
;
1226 if (emitInfo
->EmitHighLevelInstructions
) {
1227 /* emit OPCODE_ENDLOOP */
1228 endInst
= new_instruction(emitInfo
, OPCODE_ENDLOOP
);
1231 /* emit unconditional BRA-nch */
1232 endInst
= new_instruction(emitInfo
, OPCODE_BRA
);
1233 endInst
->DstReg
.CondMask
= COND_TR
; /* always true */
1235 /* ENDLOOP's BranchTarget points to the BGNLOOP inst */
1236 endInst
->BranchTarget
= beginInstLoc
;
1238 if (emitInfo
->EmitHighLevelInstructions
) {
1239 /* BGNLOOP's BranchTarget points to the ENDLOOP inst */
1240 prog
->Instructions
[beginInstLoc
].BranchTarget
= prog
->NumInstructions
-1;
1243 /* Done emitting loop code. Now walk over the loop's linked list of
1244 * BREAK and CONT nodes, filling in their BranchTarget fields (which
1245 * will point to the ENDLOOP+1 or BGNLOOP instructions, respectively).
1247 for (ir
= n
->List
; ir
; ir
= ir
->List
) {
1248 struct prog_instruction
*inst
= prog
->Instructions
+ ir
->InstLocation
;
1249 assert(inst
->BranchTarget
< 0);
1250 if (ir
->Opcode
== IR_BREAK
||
1251 ir
->Opcode
== IR_BREAK_IF_TRUE
) {
1252 assert(inst
->Opcode
== OPCODE_BRK
||
1253 inst
->Opcode
== OPCODE_BRA
);
1254 /* go to instruction after end of loop */
1255 inst
->BranchTarget
= endInstLoc
+ 1;
1258 assert(ir
->Opcode
== IR_CONT
||
1259 ir
->Opcode
== IR_CONT_IF_TRUE
);
1260 assert(inst
->Opcode
== OPCODE_CONT
||
1261 inst
->Opcode
== OPCODE_BRA
);
1262 /* go to instruction at tail of loop */
1263 inst
->BranchTarget
= endInstLoc
;
1271 * Unconditional "continue" or "break" statement.
1272 * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted.
1274 static struct prog_instruction
*
1275 emit_cont_break(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
1277 gl_inst_opcode opcode
;
1278 struct prog_instruction
*inst
;
1280 if (n
->Opcode
== IR_CONT
) {
1281 /* we need to execute the loop's tail code before doing CONT */
1283 assert(n
->Parent
->Opcode
== IR_LOOP
);
1284 if (n
->Parent
->Children
[1]) {
1285 /* emit tail code */
1286 if (emitInfo
->EmitComments
) {
1287 emit_comment(emitInfo
, "continue - tail code:");
1289 emit(emitInfo
, n
->Parent
->Children
[1]);
1293 /* opcode selection */
1294 if (emitInfo
->EmitHighLevelInstructions
) {
1295 opcode
= (n
->Opcode
== IR_CONT
) ? OPCODE_CONT
: OPCODE_BRK
;
1298 opcode
= OPCODE_BRA
;
1300 n
->InstLocation
= emitInfo
->prog
->NumInstructions
;
1301 inst
= new_instruction(emitInfo
, opcode
);
1302 inst
->DstReg
.CondMask
= COND_TR
; /* always true */
1308 * Conditional "continue" or "break" statement.
1309 * Either OPCODE_CONT, OPCODE_BRK or OPCODE_BRA will be emitted.
1311 static struct prog_instruction
*
1312 emit_cont_break_if_true(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
1314 struct prog_instruction
*inst
;
1316 assert(n
->Opcode
== IR_CONT_IF_TRUE
||
1317 n
->Opcode
== IR_BREAK_IF_TRUE
);
1319 /* evaluate condition expr, setting cond codes */
1320 inst
= emit(emitInfo
, n
->Children
[0]);
1321 if (emitInfo
->EmitCondCodes
) {
1323 inst
->CondUpdate
= GL_TRUE
;
1326 n
->InstLocation
= emitInfo
->prog
->NumInstructions
;
1328 /* opcode selection */
1329 if (emitInfo
->EmitHighLevelInstructions
) {
1330 const gl_inst_opcode opcode
1331 = (n
->Opcode
== IR_CONT_IF_TRUE
) ? OPCODE_CONT
: OPCODE_BRK
;
1332 if (emitInfo
->EmitCondCodes
) {
1333 /* Get the writemask from the previous instruction which set
1334 * the condcodes. Use that writemask as the CondSwizzle.
1336 const GLuint condWritemask
= inst
->DstReg
.WriteMask
;
1337 inst
= new_instruction(emitInfo
, opcode
);
1338 inst
->DstReg
.CondMask
= COND_NE
;
1339 inst
->DstReg
.CondSwizzle
= writemask_to_swizzle(condWritemask
);
1348 ifInstLoc
= emitInfo
->prog
->NumInstructions
;
1349 inst
= new_instruction(emitInfo
, OPCODE_IF
);
1350 storage_to_src_reg(&inst
->SrcReg
[0], n
->Children
[0]->Store
);
1351 n
->InstLocation
= emitInfo
->prog
->NumInstructions
;
1353 inst
= new_instruction(emitInfo
, opcode
);
1354 inst
= new_instruction(emitInfo
, OPCODE_ENDIF
);
1356 emitInfo
->prog
->Instructions
[ifInstLoc
].BranchTarget
1357 = emitInfo
->prog
->NumInstructions
;
1362 const GLuint condWritemask
= inst
->DstReg
.WriteMask
;
1363 assert(emitInfo
->EmitCondCodes
);
1364 inst
= new_instruction(emitInfo
, OPCODE_BRA
);
1365 inst
->DstReg
.CondMask
= COND_NE
;
1366 inst
->DstReg
.CondSwizzle
= writemask_to_swizzle(condWritemask
);
1374 * Remove any SWIZZLE_NIL terms from given swizzle mask (smear prev term).
1375 * Ex: fix_swizzle("zyNN") -> "zyyy"
1378 fix_swizzle(GLuint swizzle
)
1381 for (i
= 0; i
< 4; i
++) {
1382 swz
[i
] = GET_SWZ(swizzle
, i
);
1383 if (swz
[i
] == SWIZZLE_NIL
) {
1384 swz
[i
] = swz
[i
- 1];
1387 return MAKE_SWIZZLE4(swz
[0], swz
[1], swz
[2], swz
[3]);
1392 * Return the number of components actually named by the swizzle.
1393 * Recall that swizzles may have undefined/don't-care values.
1396 swizzle_size(GLuint swizzle
)
1399 for (i
= 0; i
< 4; i
++) {
1400 GLuint swz
= GET_SWZ(swizzle
, i
);
1401 size
+= (swz
>= 0 && swz
<= 3);
1407 static struct prog_instruction
*
1408 emit_swizzle(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
1411 struct prog_instruction
*inst
;
1413 inst
= emit(emitInfo
, n
->Children
[0]);
1417 GLuint s
= n
->Children
[0]->Store
->Swizzle
;
1418 assert(GET_SWZ(s
, 0) != SWIZZLE_NIL
);
1419 assert(GET_SWZ(s
, 1) != SWIZZLE_NIL
);
1420 assert(GET_SWZ(s
, 2) != SWIZZLE_NIL
);
1421 assert(GET_SWZ(s
, 3) != SWIZZLE_NIL
);
1424 /* For debug: n->Var = n->Children[0]->Var; */
1426 /* "pull-up" the child's storage info, applying our swizzle info */
1427 n
->Store
->File
= n
->Children
[0]->Store
->File
;
1428 n
->Store
->Index
= n
->Children
[0]->Store
->Index
;
1429 n
->Store
->Size
= swizzle_size(n
->Store
->Swizzle
);
1431 printf("Emit Swizzle %s reg %d chSize %d mySize %d\n",
1432 _mesa_swizzle_string(n
->Store
->Swizzle
, 0, 0),
1433 n
->Store
->Index
, n
->Children
[0]->Store
->Size
,
1437 /* apply this swizzle to child's swizzle to get composed swizzle */
1438 swizzle
= fix_swizzle(n
->Store
->Swizzle
); /* remove the don't care terms */
1439 n
->Store
->Swizzle
= swizzle_swizzle(n
->Children
[0]->Store
->Swizzle
,
1447 * Dereference array element. Just resolve storage for the array
1448 * element represented by this node.
1450 static struct prog_instruction
*
1451 emit_array_element(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
1454 assert(n
->Store
->File
!= PROGRAM_UNDEFINED
);
1455 assert(n
->Store
->Size
> 0);
1457 if (n
->Store
->File
== PROGRAM_STATE_VAR
) {
1458 n
->Store
->Index
= _slang_alloc_statevar(n
, emitInfo
->prog
->Parameters
);
1462 if (n
->Children
[1]->Opcode
== IR_FLOAT
) {
1463 /* Constant index */
1464 const GLint arrayAddr
= n
->Children
[0]->Store
->Index
;
1465 const GLint index
= (GLint
) n
->Children
[1]->Value
[0];
1466 n
->Store
->Index
= arrayAddr
+ index
;
1469 /* Variable index - PROBLEM */
1470 const GLint arrayAddr
= n
->Children
[0]->Store
->Index
;
1471 const GLint index
= 0;
1472 _mesa_problem(NULL
, "variable array indexes not supported yet!");
1473 n
->Store
->Index
= arrayAddr
+ index
;
1475 return NULL
; /* no instruction */
1480 * Resolve storage for accessing a structure field.
1482 static struct prog_instruction
*
1483 emit_struct_field(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
1485 if (n
->Store
->File
== PROGRAM_STATE_VAR
) {
1486 n
->Store
->Index
= _slang_alloc_statevar(n
, emitInfo
->prog
->Parameters
);
1489 GLint offset
= n
->FieldOffset
/ 4;
1490 assert(n
->Children
[0]->Store
->Index
>= 0);
1491 n
->Store
->Index
= n
->Children
[0]->Store
->Index
+ offset
;
1492 if (n
->Store
->Size
== 1) {
1493 GLint swz
= n
->FieldOffset
% 4;
1494 n
->Store
->Swizzle
= MAKE_SWIZZLE4(swz
, swz
, swz
, swz
);
1497 n
->Store
->Swizzle
= SWIZZLE_XYZW
;
1500 return NULL
; /* no instruction */
1504 static struct prog_instruction
*
1505 emit(slang_emit_info
*emitInfo
, slang_ir_node
*n
)
1507 struct prog_instruction
*inst
;
1511 switch (n
->Opcode
) {
1513 /* sequence of two sub-trees */
1514 assert(n
->Children
[0]);
1515 assert(n
->Children
[1]);
1516 emit(emitInfo
, n
->Children
[0]);
1517 inst
= emit(emitInfo
, n
->Children
[1]);
1521 n
->Store
= n
->Children
[1]->Store
;
1525 /* new variable scope */
1526 _slang_push_var_table(emitInfo
->vt
);
1527 inst
= emit(emitInfo
, n
->Children
[0]);
1528 _slang_pop_var_table(emitInfo
->vt
);
1532 /* Variable declaration - allocate a register for it */
1534 assert(n
->Store
->File
!= PROGRAM_UNDEFINED
);
1535 assert(n
->Store
->Size
> 0);
1536 /*assert(n->Store->Index < 0);*/
1537 if (!n
->Var
|| n
->Var
->isTemp
) {
1538 /* a nameless/temporary variable, will be freed after first use */
1540 if (n
->Store
->Index
< 0 && !_slang_alloc_temp(emitInfo
->vt
, n
->Store
)) {
1541 slang_info_log_error(emitInfo
->log
,
1542 "Ran out of registers, too many temporaries");
1547 /* a regular variable */
1548 _slang_add_variable(emitInfo
->vt
, n
->Var
);
1549 if (!_slang_alloc_var(emitInfo
->vt
, n
->Store
)) {
1550 slang_info_log_error(emitInfo
->log
,
1551 "Ran out of registers, too many variables");
1555 printf("IR_VAR_DECL %s %d store %p\n",
1556 (char*) n->Var->a_name, n->Store->Index, (void*) n->Store);
1558 assert(n
->Var
->aux
== n
->Store
);
1560 if (emitInfo
->EmitComments
) {
1561 /* emit NOP with comment describing the variable's storage location */
1563 sprintf(s
, "TEMP[%d]%s = variable %s (size %d)",
1565 _mesa_swizzle_string(n
->Store
->Swizzle
, 0, GL_FALSE
),
1566 (n
->Var
? (char *) n
->Var
->a_name
: "anonymous"),
1568 inst
= emit_comment(emitInfo
, s
);
1574 /* Reference to a variable
1575 * Storage should have already been resolved/allocated.
1578 assert(n
->Store
->File
!= PROGRAM_UNDEFINED
);
1580 if (n
->Store
->File
== PROGRAM_STATE_VAR
&&
1581 n
->Store
->Index
< 0) {
1582 n
->Store
->Index
= _slang_alloc_statevar(n
, emitInfo
->prog
->Parameters
);
1585 if (n
->Store
->Index
< 0) {
1586 /* probably ran out of registers */
1589 assert(n
->Store
->Size
> 0);
1593 return emit_array_element(emitInfo
, n
);
1595 return emit_struct_field(emitInfo
, n
);
1597 return emit_swizzle(emitInfo
, n
);
1601 emit(emitInfo
, n
->Children
[0]);
1602 inst
= new_instruction(emitInfo
, OPCODE_MOV
);
1604 if (!alloc_temp_storage(emitInfo
, n
, 1))
1607 storage_to_dst_reg(&inst
->DstReg
, n
->Store
, n
->Writemask
);
1608 storage_to_src_reg(&inst
->SrcReg
[0], n
->Children
[0]->Store
);
1609 if (emitInfo
->EmitComments
)
1610 inst
->Comment
= _mesa_strdup("int to float");
1613 /* Simple arithmetic */
1647 /* trinary operators */
1649 return emit_arith(emitInfo
, n
);
1653 return emit_compare(emitInfo
, n
);
1656 return emit_clamp(emitInfo
, n
);
1660 return emit_tex(emitInfo
, n
);
1662 return emit_negation(emitInfo
, n
);
1664 /* find storage location for this float constant */
1665 n
->Store
->Index
= _mesa_add_unnamed_constant(emitInfo
->prog
->Parameters
,
1668 &n
->Store
->Swizzle
);
1669 if (n
->Store
->Index
< 0) {
1670 slang_info_log_error(emitInfo
->log
, "Ran out of space for constants");
1676 return emit_move(emitInfo
, n
);
1679 return emit_cond(emitInfo
, n
);
1682 return emit_not(emitInfo
, n
);
1685 return emit_label(emitInfo
, n
);
1688 return emit_kill(emitInfo
);
1691 /* new variable scope for subroutines/function calls*/
1692 _slang_push_var_table(emitInfo
->vt
);
1693 inst
= emit_func(emitInfo
, n
);
1694 _slang_pop_var_table(emitInfo
->vt
);
1698 return emit_if(emitInfo
, n
);
1701 return emit_loop(emitInfo
, n
);
1702 case IR_BREAK_IF_TRUE
:
1703 case IR_CONT_IF_TRUE
:
1704 return emit_cont_break_if_true(emitInfo
, n
);
1708 return emit_cont_break(emitInfo
, n
);
1711 return new_instruction(emitInfo
, OPCODE_BGNSUB
);
1713 return new_instruction(emitInfo
, OPCODE_ENDSUB
);
1715 return emit_return(emitInfo
, n
);
1721 _mesa_problem(NULL
, "Unexpected IR opcode in emit()\n");
1728 * After code generation, any subroutines will be in separate program
1729 * objects. This function appends all the subroutines onto the main
1730 * program and resolves the linking of all the branch/call instructions.
1731 * XXX this logic should really be part of the linking process...
1734 _slang_resolve_subroutines(slang_emit_info
*emitInfo
)
1736 GET_CURRENT_CONTEXT(ctx
);
1737 struct gl_program
*mainP
= emitInfo
->prog
;
1738 GLuint
*subroutineLoc
, i
, total
;
1741 = (GLuint
*) _mesa_malloc(emitInfo
->NumSubroutines
* sizeof(GLuint
));
1743 /* total number of instructions */
1744 total
= mainP
->NumInstructions
;
1745 for (i
= 0; i
< emitInfo
->NumSubroutines
; i
++) {
1746 subroutineLoc
[i
] = total
;
1747 total
+= emitInfo
->Subroutines
[i
]->NumInstructions
;
1750 /* adjust BrancTargets within the functions */
1751 for (i
= 0; i
< emitInfo
->NumSubroutines
; i
++) {
1752 struct gl_program
*sub
= emitInfo
->Subroutines
[i
];
1754 for (j
= 0; j
< sub
->NumInstructions
; j
++) {
1755 struct prog_instruction
*inst
= sub
->Instructions
+ j
;
1756 if (inst
->Opcode
!= OPCODE_CAL
&& inst
->BranchTarget
>= 0) {
1757 inst
->BranchTarget
+= subroutineLoc
[i
];
1762 /* append subroutines' instructions after main's instructions */
1763 mainP
->Instructions
= _mesa_realloc_instructions(mainP
->Instructions
,
1764 mainP
->NumInstructions
,
1766 mainP
->NumInstructions
= total
;
1767 for (i
= 0; i
< emitInfo
->NumSubroutines
; i
++) {
1768 struct gl_program
*sub
= emitInfo
->Subroutines
[i
];
1769 _mesa_copy_instructions(mainP
->Instructions
+ subroutineLoc
[i
],
1771 sub
->NumInstructions
);
1772 /* delete subroutine code */
1773 sub
->Parameters
= NULL
; /* prevent double-free */
1774 _mesa_delete_program(ctx
, sub
);
1777 /* free subroutine list */
1778 if (emitInfo
->Subroutines
) {
1779 _mesa_free(emitInfo
->Subroutines
);
1780 emitInfo
->Subroutines
= NULL
;
1782 emitInfo
->NumSubroutines
= 0;
1784 /* Examine CAL instructions.
1785 * At this point, the BranchTarget field of the CAL instructions is
1786 * the number/id of the subroutine to call (an index into the
1787 * emitInfo->Subroutines list).
1788 * Translate that into an actual instruction location now.
1790 for (i
= 0; i
< mainP
->NumInstructions
; i
++) {
1791 struct prog_instruction
*inst
= mainP
->Instructions
+ i
;
1792 if (inst
->Opcode
== OPCODE_CAL
) {
1793 const GLuint f
= inst
->BranchTarget
;
1794 inst
->BranchTarget
= subroutineLoc
[f
];
1798 _mesa_free(subroutineLoc
);
1805 _slang_emit_code(slang_ir_node
*n
, slang_var_table
*vt
,
1806 struct gl_program
*prog
, GLboolean withEnd
,
1807 slang_info_log
*log
)
1809 GET_CURRENT_CONTEXT(ctx
);
1811 slang_emit_info emitInfo
;
1815 emitInfo
.prog
= prog
;
1816 emitInfo
.Subroutines
= NULL
;
1817 emitInfo
.NumSubroutines
= 0;
1819 emitInfo
.EmitHighLevelInstructions
= ctx
->Shader
.EmitHighLevelInstructions
;
1820 emitInfo
.EmitCondCodes
= ctx
->Shader
.EmitCondCodes
;
1821 emitInfo
.EmitComments
= ctx
->Shader
.EmitComments
;
1822 emitInfo
.EmitBeginEndSub
= GL_TRUE
;
1824 if (!emitInfo
.EmitCondCodes
) {
1825 emitInfo
.EmitHighLevelInstructions
= GL_TRUE
;
1828 (void) emit(&emitInfo
, n
);
1830 /* finish up by adding the END opcode to program */
1832 struct prog_instruction
*inst
;
1833 inst
= new_instruction(&emitInfo
, OPCODE_END
);
1836 _slang_resolve_subroutines(&emitInfo
);
1841 printf("*********** End emit code (%u inst):\n", prog
->NumInstructions
);
1842 _mesa_print_program(prog
);
1843 _mesa_print_program_parameters(ctx
,prog
);