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.
26 * \file slang_codegen.c
27 * Mesa GLSL code generator. Convert AST to IR tree.
33 #include "slang_assemble.h"
34 #include "slang_codegen.h"
35 #include "slang_compile.h"
36 #include "slang_storage.h"
37 #include "slang_error.h"
38 #include "slang_simplify.h"
39 #include "slang_emit.h"
43 #include "prog_instruction.h"
44 #include "prog_parameter.h"
45 #include "slang_print.h"
49 * XXX move these into the slang_assemble_ctx struct
51 static slang_function
*CurFunction
= NULL
;
52 static slang_atom CurLoopBreak
= 0;
53 static slang_atom CurLoopCont
= 0;
56 static slang_ir_node
*
57 _slang_gen_operation(slang_assemble_ctx
* A
, slang_operation
*oper
);
61 * Map "_asm foo" to IR_FOO, etc.
66 slang_ir_opcode Opcode
;
67 GLuint HaveRetValue
, NumParams
;
71 static slang_asm_info AsmInfo
[] = {
73 { "vec4_add", IR_ADD
, 1, 2 },
74 { "vec4_multiply", IR_MUL
, 1, 2 },
75 { "vec4_dot", IR_DOT4
, 1, 2 },
76 { "vec3_dot", IR_DOT3
, 1, 2 },
77 { "vec3_cross", IR_CROSS
, 1, 2 },
78 { "vec4_min", IR_MIN
, 1, 2 },
79 { "vec4_max", IR_MAX
, 1, 2 },
80 { "vec4_seq", IR_SEQ
, 1, 2 },
81 { "vec4_sge", IR_SGE
, 1, 2 },
82 { "vec4_sgt", IR_SGT
, 1, 2 },
84 { "vec4_floor", IR_FLOOR
, 1, 1 },
85 { "vec4_frac", IR_FRAC
, 1, 1 },
86 { "vec4_abs", IR_ABS
, 1, 1 },
87 { "vec4_negate", IR_NEG
, 1, 1 },
89 { "float_add", IR_ADD
, 1, 2 },
90 { "float_subtract", IR_SUB
, 1, 2 },
91 { "float_multiply", IR_MUL
, 1, 2 },
92 { "float_divide", IR_DIV
, 1, 2 },
93 { "float_power", IR_POW
, 1, 2 },
94 /* texture / sampler */
95 { "vec4_tex2d", IR_TEX
, 1, 1 },
96 { "vec4_texb2d", IR_TEXB
, 1, 3 },
98 { "int_to_float", IR_I_TO_F
, 1, 1 },
99 { "float_exp", IR_EXP
, 1, 1 },
100 { "float_exp2", IR_EXP2
, 1, 1 },
101 { "float_log2", IR_LOG2
, 1, 1 },
102 { "float_rsq", IR_RSQ
, 1, 1 },
103 { "float_rcp", IR_RCP
, 1, 1 },
104 { "float_sine", IR_SIN
, 1, 1 },
105 { "float_cosine", IR_COS
, 1, 1 },
106 { NULL
, IR_NOP
, 0, 0 }
111 static slang_ir_node
*
112 new_node(slang_ir_opcode op
, slang_ir_node
*left
, slang_ir_node
*right
)
114 slang_ir_node
*n
= (slang_ir_node
*) calloc(1, sizeof(slang_ir_node
));
117 n
->Children
[0] = left
;
118 n
->Children
[1] = right
;
119 n
->Swizzle
= SWIZZLE_NOOP
;
120 n
->Writemask
= WRITEMASK_XYZW
;
125 static slang_ir_node
*
126 new_seq(slang_ir_node
*left
, slang_ir_node
*right
)
128 /* XXX if either left or right is null, just return pointer to other?? */
131 return new_node(IR_SEQ
, left
, right
);
134 static slang_ir_node
*
135 new_label(slang_atom labName
)
137 slang_ir_node
*n
= new_node(IR_LABEL
, NULL
, NULL
);
138 n
->Target
= (char *) labName
; /*_mesa_strdup(name);*/
142 static slang_ir_node
*
143 new_float_literal(float x
, float y
, float z
, float w
)
145 slang_ir_node
*n
= new_node(IR_FLOAT
, NULL
, NULL
);
154 * XXX maybe pass an IR node as second param to indicate the jump target???
156 static slang_ir_node
*
157 new_cjump(slang_atom target
)
159 slang_ir_node
*n
= new_node(IR_CJUMP
, NULL
, NULL
);
161 n
->Target
= (char *) target
;
166 * XXX maybe pass an IR node as second param to indicate the jump target???
168 static slang_ir_node
*
169 new_jump(slang_atom target
)
171 slang_ir_node
*n
= new_node(IR_JUMP
, NULL
, NULL
);
173 n
->Target
= (char *) target
;
179 * New IR_VAR node - a reference to a previously declared variable.
181 static slang_ir_node
*
182 new_var(slang_assemble_ctx
*A
, slang_operation
*oper
,
183 slang_atom name
, GLuint swizzle
)
185 slang_variable
*v
= _slang_locate_variable(oper
->locals
, name
, GL_TRUE
);
186 slang_ir_node
*n
= new_node(IR_VAR
, NULL
, NULL
);
188 printf("VAR NOT FOUND %s\n", (char *) name
);
194 assert(!oper
->var
|| oper
->var
== v
);
197 n
->Swizzle
= swizzle
;
199 slang_resolve_storage(A
->codegen
/**NULL**/, n
, A
->program
);
205 slang_is_writemask(const char *field
, GLuint
*mask
)
208 GLuint i
, bit
, c
= 0;
210 for (i
= 0; i
< n
&& field
[i
]; i
++) {
241 * Check if the given function is really just a wrapper for an
242 * basic assembly instruction.
245 slang_is_asm_function(const slang_function
*fun
)
247 if (fun
->body
->type
== slang_oper_block_no_new_scope
&&
248 fun
->body
->num_children
== 1 &&
249 fun
->body
->children
[0].type
== slang_oper_asm
) {
257 * Produce inline code for a call to an assembly instruction.
259 static slang_operation
*
260 slang_inline_asm_function(slang_assemble_ctx
*A
,
261 slang_function
*fun
, slang_operation
*oper
)
263 const int numArgs
= oper
->num_children
;
264 const slang_operation
*args
= oper
->children
;
266 slang_operation
*inlined
= slang_operation_new(1);
268 /*assert(oper->type == slang_oper_call); or vec4_add, etc */
270 inlined
->type
= fun
->body
->children
[0].type
;
271 inlined
->a_id
= fun
->body
->children
[0].a_id
;
272 inlined
->num_children
= numArgs
;
273 inlined
->children
= slang_operation_new(numArgs
);
275 inlined
->locals
= slang_variable_scope_copy(oper
->locals
);
277 assert(inlined
->locals
);
278 inlined
->locals
->outer_scope
= oper
->locals
->outer_scope
;
281 for (i
= 0; i
< numArgs
; i
++) {
282 slang_operation_copy(inlined
->children
+ i
, args
+ i
);
290 slang_resolve_variable(slang_operation
*oper
)
292 if (oper
->type
!= slang_oper_identifier
)
295 oper
->var
= _slang_locate_variable(oper
->locals
,
296 (const slang_atom
) oper
->a_id
,
299 oper
->var
->used
= GL_TRUE
;
305 * Replace particular variables (slang_oper_identifier) with new expressions.
308 slang_substitute(slang_assemble_ctx
*A
, slang_operation
*oper
,
309 GLuint substCount
, slang_variable
**substOld
,
310 slang_operation
**substNew
, GLboolean isLHS
)
312 switch (oper
->type
) {
313 case slang_oper_variable_decl
:
315 slang_variable
*v
= _slang_locate_variable(oper
->locals
,
316 oper
->a_id
, GL_TRUE
);
318 if (v
->initializer
&& oper
->num_children
== 0) {
319 /* set child of oper to copy of initializer */
320 oper
->num_children
= 1;
321 oper
->children
= slang_operation_new(1);
322 slang_operation_copy(&oper
->children
[0], v
->initializer
);
324 if (oper
->num_children
== 1) {
325 /* the initializer */
326 slang_substitute(A
, &oper
->children
[0], substCount
, substOld
, substNew
, GL_FALSE
);
330 case slang_oper_identifier
:
331 assert(oper
->num_children
== 0);
332 if (1/**!isLHS XXX FIX */) {
333 slang_atom id
= oper
->a_id
;
336 v
= _slang_locate_variable(oper
->locals
, id
, GL_TRUE
);
338 printf("var %s not found!\n", (char *) oper
->a_id
);
342 /* look for a substitution */
343 for (i
= 0; i
< substCount
; i
++) {
344 if (v
== substOld
[i
]) {
345 /* OK, replace this slang_oper_identifier with a new expr */
346 assert(substNew
[i
]->type
== slang_oper_identifier
||
347 substNew
[i
]->type
== slang_oper_literal_float
);
348 #if 0 /* DEBUG only */
349 if (substNew
[i
]->type
== slang_oper_identifier
) {
350 assert(substNew
[i
]->var
);
351 assert(substNew
[i
]->var
->a_name
);
352 printf("Substitute %s with %s in id node %p\n",
353 (char*)v
->a_name
, (char*) substNew
[i
]->var
->a_name
,
357 printf("Substitute %s with %f in id node %p\n",
358 (char*)v
->a_name
, substNew
[i
]->literal
[0],
361 slang_operation_copy(oper
, substNew
[i
]);
367 #if 0 /* XXX rely on default case below */
368 case slang_oper_return
:
369 /* do return replacement here too */
370 assert(oper
->num_children
== 0 || oper
->num_children
== 1);
371 if (oper
->num_children
== 1) {
372 slang_substitute(A
, &oper
->children
[0],
373 substCount
, substOld
, substNew
, GL_FALSE
);
377 case slang_oper_assign
:
378 case slang_oper_subscript
:
380 * child[0] can't have substitutions but child[1] can.
382 slang_substitute(A
, &oper
->children
[0],
383 substCount
, substOld
, substNew
, GL_TRUE
);
384 slang_substitute(A
, &oper
->children
[1],
385 substCount
, substOld
, substNew
, GL_FALSE
);
387 case slang_oper_field
:
389 slang_substitute(A
, &oper
->children
[0],
390 substCount
, substOld
, substNew
, GL_TRUE
);
395 for (i
= 0; i
< oper
->num_children
; i
++)
396 slang_substitute(A
, &oper
->children
[i
],
397 substCount
, substOld
, substNew
, GL_FALSE
);
405 * Inline the given function call operation.
406 * Return a new slang_operation that corresponds to the inlined code.
408 static slang_operation
*
409 slang_inline_function_call(slang_assemble_ctx
* A
, slang_function
*fun
,
410 slang_operation
*oper
, slang_operation
*returnOper
)
417 ParamMode
*paramMode
;
418 const GLboolean haveRetValue
= _slang_function_has_return_value(fun
);
419 const GLuint numArgs
= oper
->num_children
;
420 const GLuint totalArgs
= numArgs
+ haveRetValue
;
421 slang_operation
*args
= oper
->children
;
422 slang_operation
*inlined
, *top
;
423 slang_variable
**substOld
;
424 slang_operation
**substNew
;
425 GLuint substCount
, numCopyIn
, i
;
427 /*assert(oper->type == slang_oper_call); (or (matrix) multiply, etc) */
428 assert(fun
->param_count
== totalArgs
);
430 /* allocate temporary arrays */
431 paramMode
= (ParamMode
*)
432 _mesa_calloc(totalArgs
* sizeof(ParamMode
));
433 substOld
= (slang_variable
**)
434 _mesa_calloc(totalArgs
* sizeof(slang_variable
*));
435 substNew
= (slang_operation
**)
436 _mesa_calloc(totalArgs
* sizeof(slang_operation
*));
438 printf("\nInline call to %s (total vars=%d nparams=%d)\n",
439 (char *) fun
->header
.a_name
,
440 fun
->parameters
->num_variables
, numArgs
);
443 if (haveRetValue
&& !returnOper
) {
444 /* Create comma sequence for inlined code, the left child will be the
445 * function body and the right child will be a variable (__retVal)
446 * that will get the return value.
448 slang_operation
*commaSeq
;
449 slang_operation
*declOper
= NULL
;
450 slang_variable
*resultVar
;
452 commaSeq
= slang_operation_new(1);
453 commaSeq
->type
= slang_oper_sequence
;
454 assert(commaSeq
->locals
);
455 commaSeq
->locals
->outer_scope
= oper
->locals
->outer_scope
;
456 commaSeq
->num_children
= 3;
457 commaSeq
->children
= slang_operation_new(3);
458 /* allocate the return var */
459 resultVar
= slang_variable_scope_grow(commaSeq
->locals
);
461 printf("ALLOC __retVal from scope %p\n", (void*) commaSeq->locals);
463 printf("Alloc __resultTemp in scope %p for retval of calling %s\n",
464 (void*)commaSeq
->locals
, (char *) fun
->header
.a_name
);
466 resultVar
->a_name
= slang_atom_pool_atom(A
->atoms
, "__resultTmp");
467 resultVar
->type
= fun
->header
.type
; /* XXX copy? */
468 /*resultVar->type.qualifier = slang_qual_out;*/
470 /* child[0] = __resultTmp declaration */
471 declOper
= &commaSeq
->children
[0];
472 declOper
->type
= slang_oper_variable_decl
;
473 declOper
->a_id
= resultVar
->a_name
;
474 declOper
->locals
->outer_scope
= commaSeq
->locals
; /*** ??? **/
476 /* child[1] = function body */
477 inlined
= &commaSeq
->children
[1];
478 /* XXXX this may be inappropriate!!!!: */
479 inlined
->locals
->outer_scope
= commaSeq
->locals
;
481 /* child[2] = __resultTmp reference */
482 returnOper
= &commaSeq
->children
[2];
483 returnOper
->type
= slang_oper_identifier
;
484 returnOper
->a_id
= resultVar
->a_name
;
485 returnOper
->locals
->outer_scope
= commaSeq
->locals
;
486 declOper
->locals
->outer_scope
= commaSeq
->locals
;
491 top
= inlined
= slang_operation_new(1);
492 /* XXXX this may be inappropriate!!!! */
493 inlined
->locals
->outer_scope
= oper
->locals
->outer_scope
;
497 assert(inlined
->locals
);
499 /* Examine the parameters, look for inout/out params, look for possible
500 * substitutions, etc:
501 * param type behaviour
502 * in copy actual to local
503 * const in substitute param with actual
507 for (i
= 0; i
< totalArgs
; i
++) {
508 slang_variable
*p
= &fun
->parameters
->variables
[i
];
509 printf("Param %d: %s %s \n", i
,
510 slang_type_qual_string(p
->type
.qualifier
),
512 if (p
->type
.qualifier
== slang_qual_inout
||
513 p
->type
.qualifier
== slang_qual_out
) {
514 /* an output param */
515 slang_operation
*arg
;
520 paramMode
[i
] = SUBST
;
521 assert(arg
->type
== slang_oper_identifier
522 /*||arg->type == slang_oper_variable_decl*/);
523 slang_resolve_variable(arg
);
524 /* replace parameter 'p' with argument 'arg' */
525 substOld
[substCount
] = p
;
526 substNew
[substCount
] = arg
; /* will get copied */
529 else if (p
->type
.qualifier
== slang_qual_const
) {
530 /* a constant input param */
531 if (args
[i
].type
== slang_oper_identifier
||
532 args
[i
].type
== slang_oper_literal_float
) {
533 /* replace all occurances of this parameter variable with the
534 * actual argument variable or a literal.
536 paramMode
[i
] = SUBST
;
537 slang_resolve_variable(&args
[i
]);
538 substOld
[substCount
] = p
;
539 substNew
[substCount
] = &args
[i
]; /* will get copied */
543 paramMode
[i
] = COPY_IN
;
547 paramMode
[i
] = COPY_IN
;
549 assert(paramMode
[i
]);
553 printf("ABOUT to inline body %p with checksum %d\n",
554 (char *) fun
->body
, slang_checksum_tree(fun
->body
));
557 /* actual code inlining: */
558 slang_operation_copy(inlined
, fun
->body
);
561 printf("======================= orig body code ======================\n");
562 printf("=== params scope = %p\n", (void*) fun
->parameters
);
563 slang_print_tree(fun
->body
, 8);
564 printf("======================= copied code =========================\n");
565 slang_print_tree(inlined
, 8);
568 /* do parameter substitution in inlined code: */
569 slang_substitute(A
, inlined
, substCount
, substOld
, substNew
, GL_FALSE
);
572 printf("======================= subst code ==========================\n");
573 slang_print_tree(inlined
, 8);
574 printf("=============================================================\n");
577 /* New prolog statements: (inserted before the inlined code)
578 * Copy the 'in' arguments.
581 for (i
= 0; i
< numArgs
; i
++) {
582 if (paramMode
[i
] == COPY_IN
) {
583 slang_variable
*p
= &fun
->parameters
->variables
[i
];
584 /* declare parameter 'p' */
585 slang_operation
*decl
= slang_operation_insert(&inlined
->num_children
,
588 printf("COPY_IN %s from expr\n", (char*)p
->a_name
);
589 decl
->type
= slang_oper_variable_decl
;
590 assert(decl
->locals
);
591 decl
->locals
= fun
->parameters
;
592 decl
->a_id
= p
->a_name
;
593 decl
->num_children
= 1;
594 decl
->children
= slang_operation_new(1);
596 /* child[0] is the var's initializer */
597 slang_operation_copy(&decl
->children
[0], args
+ i
);
603 /* New epilog statements:
604 * 1. Create end of function label to jump to from return statements.
605 * 2. Copy the 'out' parameter vars
608 slang_operation
*lab
= slang_operation_insert(&inlined
->num_children
,
610 inlined
->num_children
);
611 lab
->type
= slang_oper_label
;
612 lab
->a_id
= slang_atom_pool_atom(A
->atoms
, CurFunction
->end_label
);
615 for (i
= 0; i
< totalArgs
; i
++) {
616 if (paramMode
[i
] == COPY_OUT
) {
617 const slang_variable
*p
= &fun
->parameters
->variables
[i
];
618 /* actualCallVar = outParam */
619 /*if (i > 0 || !haveRetValue)*/
620 slang_operation
*ass
= slang_operation_insert(&inlined
->num_children
,
622 inlined
->num_children
);
623 ass
->type
= slang_oper_assign
;
624 ass
->num_children
= 2;
625 ass
->locals
= _slang_variable_scope_new(inlined
->locals
);
627 ass
->children
= slang_operation_new(2);
628 ass
->children
[0] = args
[i
]; /*XXX copy */
629 ass
->children
[1].type
= slang_oper_identifier
;
630 ass
->children
[1].a_id
= p
->a_name
;
631 ass
->children
[1].locals
= _slang_variable_scope_new(ass
->locals
);
635 _mesa_free(paramMode
);
636 _mesa_free(substOld
);
637 _mesa_free(substNew
);
639 printf("Done Inline call to %s (total vars=%d nparams=%d)\n",
640 (char *) fun
->header
.a_name
,
641 fun
->parameters
->num_variables
, numArgs
);
647 static slang_ir_node
*
648 _slang_gen_function_call(slang_assemble_ctx
*A
, slang_function
*fun
,
649 slang_operation
*oper
, slang_operation
*dest
)
652 slang_operation
*inlined
;
653 slang_function
*prevFunc
;
655 prevFunc
= CurFunction
;
658 if (!CurFunction
->end_label
) {
660 sprintf(name
, "__endOfFunc_%s_", (char *) CurFunction
->header
.a_name
);
661 CurFunction
->end_label
= slang_atom_pool_gen(A
->atoms
, name
);
664 if (slang_is_asm_function(fun
) && !dest
) {
665 /* assemble assembly function - tree style */
666 inlined
= slang_inline_asm_function(A
, fun
, oper
);
669 /* non-assembly function */
670 inlined
= slang_inline_function_call(A
, fun
, oper
, dest
);
673 /* Replace the function call with the inlined block */
675 slang_operation_construct(oper
);
676 slang_operation_copy(oper
, inlined
);
683 assert(inlined
->locals
);
684 printf("*** Inlined code for call to %s:\n",
685 (char*) fun
->header
.a_name
);
687 slang_print_tree(oper
, 10);
691 /* assemble what we just made XXX here??? */
692 n
= _slang_gen_operation(A
, oper
);
694 CurFunction
= prevFunc
;
700 static slang_asm_info
*
701 slang_find_asm_info(const char *name
)
704 for (i
= 0; AsmInfo
[i
].Name
; i
++) {
705 if (_mesa_strcmp(AsmInfo
[i
].Name
, name
) == 0) {
714 make_writemask(char *field
)
737 return WRITEMASK_XYZW
;
744 * Generate IR tree for an asm instruction/operation such as:
745 * __asm vec4_dot __retVal.x, v1, v2;
747 static slang_ir_node
*
748 _slang_gen_asm(slang_assemble_ctx
*A
, slang_operation
*oper
,
749 slang_operation
*dest
)
751 const slang_asm_info
*info
;
752 slang_ir_node
*kids
[2], *n
;
753 GLuint j
, firstOperand
;
755 assert(oper
->type
== slang_oper_asm
);
757 info
= slang_find_asm_info((char *) oper
->a_id
);
759 assert(info
->NumParams
<= 2);
761 if (info
->NumParams
== oper
->num_children
) {
762 /* storage for result not specified */
766 /* storage for result (child[0]) is specified */
770 /* assemble child(ren) */
771 kids
[0] = kids
[1] = NULL
;
772 for (j
= 0; j
< info
->NumParams
; j
++) {
773 kids
[j
] = _slang_gen_operation(A
, &oper
->children
[firstOperand
+ j
]);
776 n
= new_node(info
->Opcode
, kids
[0], kids
[1]);
779 /* Setup n->Store to be a particular location. Otherwise, storage
780 * for the result (a temporary) will be allocated later.
782 GLuint writemask
= WRITEMASK_XYZW
;
783 slang_operation
*dest_oper
;
786 dest_oper
= &oper
->children
[0];
787 if (dest_oper
->type
== slang_oper_field
) {
789 writemask
= make_writemask((char*) dest_oper
->a_id
);
790 dest_oper
= &dest_oper
->children
[0];
793 assert(dest_oper
->type
== slang_oper_identifier
);
794 n0
= _slang_gen_operation(A
, dest_oper
);
798 n
->Store
= n0
->Store
;
799 n
->Writemask
= writemask
;
804 if (info
->Opcode
== IR_TEX
|| info
->Opcode
== IR_TEXB
) {
805 n
->TexTarget
= TEXTURE_2D_INDEX
;
814 _slang_is_noop(const slang_operation
*oper
)
817 oper
->type
== slang_oper_void
||
818 (oper
->num_children
== 1 && oper
->children
[0].type
== slang_oper_void
))
825 static slang_ir_node
*
826 _slang_gen_cond(slang_ir_node
*n
)
828 slang_ir_node
*c
= new_node(IR_COND
, n
, NULL
);
834 * Assemble a function call, given a particular function name.
835 * \param name the function's name (operators like '*' are possible).
837 static slang_ir_node
*
838 _slang_gen_function_call_name(slang_assemble_ctx
*A
, const char *name
,
839 slang_operation
*oper
, slang_operation
*dest
)
841 slang_operation
*params
= oper
->children
;
842 const GLuint param_count
= oper
->num_children
;
846 atom
= slang_atom_pool_atom(A
->atoms
, name
);
847 if (atom
== SLANG_ATOM_NULL
)
850 fun
= _slang_locate_function(A
->space
.funcs
, atom
, params
, param_count
,
851 &A
->space
, A
->atoms
);
853 RETURN_ERROR2("Undefined function", name
, 0);
856 return _slang_gen_function_call(A
, fun
, oper
, dest
);
861 * Generate IR tree for a while-loop.
863 static slang_ir_node
*
864 _slang_gen_while(slang_assemble_ctx
* A
, const slang_operation
*oper
)
867 * label "__startWhile"
868 * eval expr (child[0]), updating condcodes
869 * branch if false to "__endWhile"
871 * jump "__startWhile"
874 slang_atom startAtom
= slang_atom_pool_gen(A
->atoms
, "__startWhile");
875 slang_atom endAtom
= slang_atom_pool_gen(A
->atoms
, "__endWhile");
876 slang_ir_node
*startLab
, *cond
, *bra
, *body
, *jump
, *endLab
, *tree
;
877 slang_atom prevLoopBreak
= CurLoopBreak
;
878 slang_atom prevLoopCont
= CurLoopCont
;
881 CurLoopBreak
= endAtom
;
882 CurLoopCont
= startAtom
;
884 startLab
= new_label(startAtom
);
885 cond
= _slang_gen_operation(A
, &oper
->children
[0]);
886 cond
= _slang_gen_cond(cond
);
887 tree
= new_seq(startLab
, cond
);
889 bra
= new_cjump(endAtom
);
890 tree
= new_seq(tree
, bra
);
892 body
= _slang_gen_operation(A
, &oper
->children
[1]);
893 tree
= new_seq(tree
, body
);
895 jump
= new_jump(startAtom
);
896 tree
= new_seq(tree
, jump
);
898 endLab
= new_label(endAtom
);
899 tree
= new_seq(tree
, endLab
);
902 CurLoopBreak
= prevLoopBreak
;
903 CurLoopCont
= prevLoopCont
;
910 * Generate IR tree for a for-loop.
912 static slang_ir_node
*
913 _slang_gen_for(slang_assemble_ctx
* A
, const slang_operation
*oper
)
916 * init code (child[0])
918 * eval expr (child[1]), updating condcodes
919 * branch if false to "__endFor"
920 * code body (child[3])
921 * label "__continueFor"
922 * incr code (child[2])
926 slang_atom startAtom
= slang_atom_pool_gen(A
->atoms
, "__startFor");
927 slang_atom contAtom
= slang_atom_pool_gen(A
->atoms
, "__continueFor");
928 slang_atom endAtom
= slang_atom_pool_gen(A
->atoms
, "__endFor");
929 slang_ir_node
*init
, *startLab
, *cond
, *bra
, *body
, *contLab
;
930 slang_ir_node
*incr
, *jump
, *endLab
, *tree
;
931 slang_atom prevLoopBreak
= CurLoopBreak
;
932 slang_atom prevLoopCont
= CurLoopCont
;
935 CurLoopBreak
= endAtom
;
936 CurLoopCont
= contAtom
;
938 init
= _slang_gen_operation(A
, &oper
->children
[0]);
939 startLab
= new_label(startAtom
);
940 tree
= new_seq(init
, startLab
);
942 cond
= _slang_gen_operation(A
, &oper
->children
[1]);
943 cond
= _slang_gen_cond(cond
);
944 tree
= new_seq(tree
, cond
);
946 bra
= new_cjump(endAtom
);
947 tree
= new_seq(tree
, bra
);
949 body
= _slang_gen_operation(A
, &oper
->children
[3]);
950 tree
= new_seq(tree
, body
);
952 contLab
= new_label(contAtom
);
953 tree
= new_seq(tree
, contLab
);
955 incr
= _slang_gen_operation(A
, &oper
->children
[2]);
956 tree
= new_seq(tree
, incr
);
958 jump
= new_jump(startAtom
);
959 tree
= new_seq(tree
, jump
);
961 endLab
= new_label(endAtom
);
962 tree
= new_seq(tree
, endLab
);
965 CurLoopBreak
= prevLoopBreak
;
966 CurLoopCont
= prevLoopCont
;
973 * Generate IR tree for an if/then/else conditional.
975 static slang_ir_node
*
976 _slang_gen_if(slang_assemble_ctx
* A
, const slang_operation
*oper
)
979 * eval expr (child[0]), updating condcodes
980 * branch if false to _else or _endif
982 * if haveElseClause clause:
988 const GLboolean haveElseClause
= !_slang_is_noop(&oper
->children
[2]);
989 slang_ir_node
*cond
, *bra
, *trueBody
, *endifLab
, *tree
;
990 slang_atom elseAtom
= slang_atom_pool_gen(A
->atoms
, "__else");
991 slang_atom endifAtom
= slang_atom_pool_gen(A
->atoms
, "__endif");
993 cond
= _slang_gen_operation(A
, &oper
->children
[0]);
994 cond
= _slang_gen_cond(cond
);
995 /*assert(cond->Store);*/
996 bra
= new_cjump(haveElseClause
? elseAtom
: endifAtom
);
997 tree
= new_seq(cond
, bra
);
999 trueBody
= _slang_gen_operation(A
, &oper
->children
[1]);
1000 tree
= new_seq(tree
, trueBody
);
1002 if (haveElseClause
) {
1004 slang_ir_node
*jump
, *elseLab
, *falseBody
;
1005 jump
= new_jump(endifAtom
);
1006 tree
= new_seq(tree
, jump
);
1008 elseLab
= new_label(elseAtom
);
1009 tree
= new_seq(tree
, elseLab
);
1011 falseBody
= _slang_gen_operation(A
, &oper
->children
[2]);
1012 tree
= new_seq(tree
, falseBody
);
1015 endifLab
= new_label(endifAtom
);
1016 tree
= new_seq(tree
, endifLab
);
1023 * Generate IR tree for a return statement.
1025 static slang_ir_node
*
1026 _slang_gen_return(slang_assemble_ctx
* A
, slang_operation
*oper
)
1028 if (oper
->num_children
== 0 ||
1029 (oper
->num_children
== 1 &&
1030 oper
->children
[0].type
== slang_oper_void
)) {
1034 * goto __endOfFunction;
1037 slang_operation gotoOp
;
1038 slang_operation_construct(&gotoOp
);
1039 gotoOp
.type
= slang_oper_goto
;
1040 gotoOp
.a_id
= slang_atom_pool_atom(A
->atoms
, CurFunction
->end_label
);
1041 /* assemble the new code */
1042 n
= _slang_gen_operation(A
, &gotoOp
);
1043 /* destroy temp code */
1044 slang_operation_destruct(&gotoOp
);
1053 * goto __endOfFunction;
1055 slang_operation
*block
, *assign
, *jump
;
1056 slang_atom a_retVal
;
1059 a_retVal
= slang_atom_pool_atom(A
->atoms
, "__retVal");
1065 = _slang_locate_variable(oper
->locals
, a_retVal
, GL_TRUE
);
1070 block
= slang_operation_new(1);
1071 block
->type
= slang_oper_block_no_new_scope
;
1072 block
->num_children
= 2;
1073 block
->children
= slang_operation_new(2);
1074 assert(block
->locals
);
1075 block
->locals
->outer_scope
= oper
->locals
->outer_scope
;
1077 /* child[0]: __retVal = expr; */
1078 assign
= &block
->children
[0];
1079 assign
->type
= slang_oper_assign
;
1080 assign
->locals
->outer_scope
= block
->locals
;
1081 assign
->num_children
= 2;
1082 assign
->children
= slang_operation_new(2);
1083 /* lhs (__retVal) */
1084 assign
->children
[0].type
= slang_oper_identifier
;
1085 assign
->children
[0].a_id
= a_retVal
;
1086 assign
->children
[0].locals
->outer_scope
= assign
->locals
;
1088 /* XXX we might be able to avoid this copy someday */
1089 slang_operation_copy(&assign
->children
[1], &oper
->children
[0]);
1091 /* child[1]: goto __endOfFunction */
1092 jump
= &block
->children
[1];
1093 jump
->type
= slang_oper_goto
;
1094 assert(CurFunction
->end_label
);
1095 jump
->a_id
= slang_atom_pool_atom(A
->atoms
, CurFunction
->end_label
);
1098 printf("NEW RETURN:\n");
1099 slang_print_tree(block
, 0);
1102 /* assemble the new code */
1103 n
= _slang_gen_operation(A
, block
);
1104 slang_operation_delete(block
);
1111 * Generate IR tree for a variable declaration.
1113 static slang_ir_node
*
1114 _slang_gen_declaration(slang_assemble_ctx
*A
, slang_operation
*oper
)
1117 slang_ir_node
*varDecl
;
1120 assert(oper
->num_children
== 0 || oper
->num_children
== 1);
1122 v
= _slang_locate_variable(oper
->locals
, oper
->a_id
, GL_TRUE
);
1125 varDecl
= new_node(IR_VAR_DECL
, NULL
, NULL
);
1130 v
->declared
= GL_TRUE
;
1132 slang_resolve_storage(A
->codegen
, varDecl
, A
->program
);
1134 if (oper
->num_children
> 0) {
1135 /* child is initializer */
1136 slang_ir_node
*var
, *init
, *rhs
;
1137 assert(oper
->num_children
== 1);
1138 var
= new_var(A
, oper
, oper
->a_id
, SWIZZLE_NOOP
);
1139 /* XXX make copy of this initializer? */
1141 printf("\n*** ASSEMBLE INITIALIZER %p\n", (void*) v->initializer);
1143 rhs
= _slang_gen_operation(A
, &oper
->children
[0]);
1144 init
= new_node(IR_MOVE
, var
, rhs
);
1145 /*assert(rhs->Opcode != IR_SEQ);*/
1146 n
= new_seq(varDecl
, init
);
1148 else if (v
->initializer
) {
1149 slang_ir_node
*var
, *init
, *rhs
;
1150 var
= new_var(A
, oper
, oper
->a_id
, SWIZZLE_NOOP
);
1151 /* XXX make copy of this initializer? */
1153 printf("\n*** ASSEMBLE INITIALIZER %p\n", (void*) v->initializer);
1155 rhs
= _slang_gen_operation(A
, v
->initializer
);
1156 init
= new_node(IR_MOVE
, var
, rhs
);
1158 assert(rhs->Opcode != IR_SEQ);
1160 n
= new_seq(varDecl
, init
);
1170 * Generate IR tree for a variable (such as in an expression).
1172 static slang_ir_node
*
1173 _slang_gen_variable(slang_assemble_ctx
* A
, slang_operation
*oper
)
1175 /* If there's a variable associated with this oper (from inlining)
1176 * use it. Otherwise, use the oper's var id.
1178 slang_atom aVar
= oper
->var
? oper
->var
->a_name
: oper
->a_id
;
1179 slang_ir_node
*n
= new_var(A
, oper
, aVar
, SWIZZLE_NOOP
);
1186 * Generate IR tree for an assignment (=).
1188 static slang_ir_node
*
1189 _slang_gen_assignment(slang_assemble_ctx
* A
, slang_operation
*oper
)
1191 if (oper
->children
[0].type
== slang_oper_identifier
&&
1192 oper
->children
[1].type
== slang_oper_call
) {
1193 /* Sspecial case of: x = f(a, b)
1194 * Replace with f(a, b, x) (where x == hidden __retVal out param)
1197 n
= _slang_gen_function_call_name(A
,
1198 (const char *) oper
->children
[1].a_id
,
1199 &oper
->children
[1], &oper
->children
[0]);
1203 slang_operation
*lhs
= &oper
->children
[0];
1204 slang_ir_node
*n
, *c0
, *c1
;
1205 GLuint mask
= WRITEMASK_XYZW
;
1206 if (lhs
->type
== slang_oper_field
) {
1207 /* XXXX this is a hack! */
1209 if (!slang_is_writemask((char *) lhs
->a_id
, &mask
))
1210 mask
= WRITEMASK_XYZW
;
1211 lhs
= &lhs
->children
[0];
1213 c0
= _slang_gen_operation(A
, lhs
);
1214 c1
= _slang_gen_operation(A
, &oper
->children
[1]);
1216 n
= new_node(IR_MOVE
, c0
, c1
);
1218 assert(c1->Opcode != IR_SEQ);
1220 if (c0
->Writemask
!= WRITEMASK_XYZW
)
1221 /* XXX this is a hack! */
1222 n
->Writemask
= c0
->Writemask
;
1224 n
->Writemask
= mask
;
1231 * Generate IR tree for referencing a field in a struct (or basic vector type)
1233 static slang_ir_node
*
1234 _slang_gen_field(slang_assemble_ctx
* A
, slang_operation
*oper
)
1236 slang_assembly_typeinfo ti
;
1238 slang_assembly_typeinfo_construct(&ti
);
1239 _slang_typeof_operation(A
, &oper
->children
[0], &ti
);
1241 if (_slang_type_is_vector(ti
.spec
.type
)) {
1242 /* the field should be a swizzle */
1243 const GLuint rows
= _slang_type_dim(ti
.spec
.type
);
1246 if (!_slang_is_swizzle((char *) oper
->a_id
, rows
, &swz
)) {
1247 RETURN_ERROR("Bad swizzle", 0);
1249 n
= _slang_gen_operation(A
, &oper
->children
[0]);
1250 n
->Swizzle
= MAKE_SWIZZLE4(swz
.swizzle
[0],
1256 else if (ti
.spec
.type
== slang_spec_float
) {
1257 const GLuint rows
= 1;
1260 if (!_slang_is_swizzle((char *) oper
->a_id
, rows
, &swz
)) {
1261 RETURN_ERROR("Bad swizzle", 0);
1263 n
= _slang_gen_operation(A
, &oper
->children
[0]);
1264 n
->Swizzle
= MAKE_SWIZZLE4(swz
.swizzle
[0],
1271 /* the field is a structure member */
1278 * Generate IR tree for an array element reference.
1280 static slang_ir_node
*
1281 _slang_gen_subscript(slang_assemble_ctx
* A
, slang_operation
*oper
)
1283 if (oper
->children
[1].type
== slang_oper_literal_int
) {
1284 /* compile-time constant index - OK */
1285 slang_assembly_typeinfo array_ti
, elem_ti
;
1286 slang_ir_node
*base
;
1289 /* get type of array element */
1290 slang_assembly_typeinfo_construct(&elem_ti
);
1291 _slang_typeof_operation(A
, oper
, &elem_ti
);
1293 /* get type of array */
1294 slang_assembly_typeinfo_construct(&array_ti
);
1295 _slang_typeof_operation(A
, &oper
->children
[0], &array_ti
);
1298 base
= _slang_gen_operation(A
, &oper
->children
[0]);
1299 assert(base
->Opcode
== IR_VAR
);
1300 assert(base
->Store
);
1302 index
= (GLint
) oper
->children
[1].literal
[0];
1303 /*printf("element[%d]\n", index);*/
1304 /* new storage info since we don't want to change the original */
1305 base
->Store
= _slang_clone_ir_storage(base
->Store
);
1306 if (_slang_type_is_vector(array_ti
.spec
.type
)) {
1307 /* scalar element (float) of a basic vector (vec3) */
1308 const GLuint max
= _slang_type_dim(array_ti
.spec
.type
);
1310 RETURN_ERROR("array index out of bounds", 0);
1313 /* use swizzle to access the element */
1314 base
->Swizzle
= SWIZZLE_X
+ index
;
1315 base
->Writemask
= WRITEMASK_X
<< index
;
1318 /* bias Index by array subscript, update storage size */
1319 base
->Store
->Index
+= index
;
1320 base
->Store
->Size
= _slang_sizeof_type_specifier(&elem_ti
.spec
);
1325 /* run-time index - not supported yet - TBD */
1333 * Generate IR tree for a slang_operation (AST node)
1335 static slang_ir_node
*
1336 _slang_gen_operation(slang_assemble_ctx
* A
, slang_operation
*oper
)
1338 switch (oper
->type
) {
1339 case slang_oper_block_no_new_scope
:
1340 case slang_oper_block_new_scope
:
1341 /* list of operations */
1342 assert(oper
->num_children
> 0);
1344 slang_ir_node
*n
, *tree
= NULL
;
1346 for (i
= 0; i
< oper
->num_children
; i
++) {
1347 n
= _slang_gen_operation(A
, &oper
->children
[i
]);
1349 return NULL
; /* error must have occured */
1350 tree
= tree
? new_seq(tree
, n
) : n
;
1355 case slang_oper_expression
:
1356 return _slang_gen_operation(A
, &oper
->children
[0]);
1358 case slang_oper_while
:
1359 return _slang_gen_while(A
, oper
);
1360 case slang_oper_for
:
1361 return _slang_gen_for(A
, oper
);
1362 case slang_oper_break
:
1363 if (!CurLoopBreak
) {
1364 RETURN_ERROR("'break' not in loop", 0);
1366 return new_jump(CurLoopBreak
);
1367 case slang_oper_continue
:
1369 RETURN_ERROR("'continue' not in loop", 0);
1371 return new_jump(CurLoopCont
);
1372 case slang_oper_equal
:
1373 return new_node(IR_SEQUAL
,
1374 _slang_gen_operation(A
, &oper
->children
[0]),
1375 _slang_gen_operation(A
, &oper
->children
[1]));
1376 case slang_oper_notequal
:
1377 return new_node(IR_SNEQUAL
,
1378 _slang_gen_operation(A
, &oper
->children
[0]),
1379 _slang_gen_operation(A
, &oper
->children
[1]));
1380 case slang_oper_greater
:
1381 return new_node(IR_SGT
,
1382 _slang_gen_operation(A
, &oper
->children
[0]),
1383 _slang_gen_operation(A
, &oper
->children
[1]));
1384 case slang_oper_less
:
1385 /* child[0] < child[1] ----> child[1] > child[0] */
1389 assert(oper
->num_children
== 2);
1390 /* XXX tranpose children */
1391 n
= _slang_gen_function_call_name(A
, "<", oper
, NULL
);
1395 /** the operands must be ints or floats, not vectors */
1396 return new_node(IR_SGT
,
1397 _slang_gen_operation(A
, &oper
->children
[1]),
1398 _slang_gen_operation(A
, &oper
->children
[0]));
1400 case slang_oper_greaterequal
:
1401 return new_node(IR_SGE
,
1402 _slang_gen_operation(A
, &oper
->children
[0]),
1403 _slang_gen_operation(A
, &oper
->children
[1]));
1404 case slang_oper_lessequal
:
1405 /* child[0] <= child[1] ----> child[1] >= child[0] */
1406 return new_node(IR_SGE
,
1407 _slang_gen_operation(A
, &oper
->children
[1]),
1408 _slang_gen_operation(A
, &oper
->children
[0]));
1409 case slang_oper_add
:
1412 assert(oper
->num_children
== 2);
1413 n
= _slang_gen_function_call_name(A
, "+", oper
, NULL
);
1416 case slang_oper_subtract
:
1419 assert(oper
->num_children
== 2);
1420 n
= _slang_gen_function_call_name(A
, "-", oper
, NULL
);
1423 case slang_oper_multiply
:
1426 assert(oper
->num_children
== 2);
1427 n
= _slang_gen_function_call_name(A
, "*", oper
, NULL
);
1430 case slang_oper_divide
:
1433 assert(oper
->num_children
== 2);
1434 n
= _slang_gen_function_call_name(A
, "/", oper
, NULL
);
1437 case slang_oper_minus
:
1440 assert(oper
->num_children
== 1);
1441 n
= _slang_gen_function_call_name(A
, "-", oper
, NULL
);
1444 case slang_oper_plus
:
1445 /* +expr --> do nothing */
1446 return _slang_gen_operation(A
, &oper
->children
[0]);
1447 case slang_oper_variable_decl
:
1448 return _slang_gen_declaration(A
, oper
);
1449 case slang_oper_assign
:
1450 return _slang_gen_assignment(A
, oper
);
1451 case slang_oper_addassign
:
1454 assert(oper
->num_children
== 2);
1455 n
= _slang_gen_function_call_name(A
, "+=", oper
, NULL
);
1456 /* The result of this operation should be stored back into child[0] */
1457 assert(n
->Children
[0]->Store
);
1458 n
->Store
= n
->Children
[0]->Store
;
1461 case slang_oper_subassign
:
1464 assert(oper
->num_children
== 2);
1465 n
= _slang_gen_function_call_name(A
, "-=", oper
, NULL
);
1466 /* The result of this operation should be stored back into child[0] */
1467 assert(n
->Children
[0]->Store
);
1468 n
->Store
= n
->Children
[0]->Store
;
1472 case slang_oper_mulassign
:
1475 assert(oper
->num_children
== 2);
1476 n
= _slang_gen_function_call_name(A
, "*=", oper
, NULL
);
1477 /* The result of this operation should be stored back into child[0] */
1478 assert(n
->Children
[0]->Store
);
1479 n
->Store
= n
->Children
[0]->Store
;
1482 case slang_oper_divassign
:
1485 assert(oper
->num_children
== 2);
1486 n
= _slang_gen_function_call_name(A
, "/=", oper
, NULL
);
1487 /* The result of this operation should be stored back into child[0] */
1488 assert(n
->Children
[0]->Store
);
1489 n
->Store
= n
->Children
[0]->Store
;
1492 case slang_oper_asm
:
1493 return _slang_gen_asm(A
, oper
, NULL
);
1494 case slang_oper_call
:
1495 return _slang_gen_function_call_name(A
, (const char *) oper
->a_id
,
1497 case slang_oper_return
:
1498 return _slang_gen_return(A
, oper
);
1499 case slang_oper_goto
:
1500 return new_jump((char*) oper
->a_id
);
1501 case slang_oper_label
:
1502 return new_label((char*) oper
->a_id
);
1503 case slang_oper_identifier
:
1504 return _slang_gen_variable(A
, oper
);
1506 return _slang_gen_if(A
, oper
);
1507 case slang_oper_field
:
1508 return _slang_gen_field(A
, oper
);
1509 case slang_oper_subscript
:
1510 return _slang_gen_subscript(A
, oper
);
1511 case slang_oper_literal_float
:
1512 return new_float_literal(oper
->literal
[0], oper
->literal
[1],
1513 oper
->literal
[2], oper
->literal
[3]);
1514 case slang_oper_literal_int
:
1515 return new_float_literal(oper
->literal
[0], 0, 0, 0);
1516 case slang_oper_literal_bool
:
1517 return new_float_literal(oper
->literal
[0], 0, 0, 0);
1518 case slang_oper_postincrement
:
1519 /* XXX not 100% about this */
1521 slang_ir_node
*var
= _slang_gen_operation(A
, &oper
->children
[0]);
1522 slang_ir_node
*one
= new_float_literal(1.0, 1.0, 1.0, 1.0);
1523 slang_ir_node
*sum
= new_node(IR_ADD
, var
, one
);
1524 slang_ir_node
*assign
= new_node(IR_MOVE
, var
, sum
);
1525 assert(sum
->Opcode
!= IR_SEQ
);
1529 case slang_oper_sequence
:
1531 slang_ir_node
*tree
= NULL
;
1533 for (i
= 0; i
< oper
->num_children
; i
++) {
1534 slang_ir_node
*n
= _slang_gen_operation(A
, &oper
->children
[i
]);
1535 tree
= tree
? new_seq(tree
, n
) : n
;
1540 case slang_oper_none
:
1543 printf("Unhandled node type %d\n", oper
->type
);
1545 return new_node(IR_NOP
, NULL
, NULL
);
1553 * Produce an IR tree from a function AST.
1554 * Then call the code emitter to convert the IR tree into a gl_program.
1556 struct slang_ir_node_
*
1557 _slang_codegen_function(slang_assemble_ctx
* A
, slang_function
* fun
)
1559 slang_ir_node
*n
, *endLabel
;
1561 if (_mesa_strcmp((char *) fun
->header
.a_name
, "main") != 0 &&
1562 _mesa_strcmp((char *) fun
->header
.a_name
, "foo") != 0 &&
1563 _mesa_strcmp((char *) fun
->header
.a_name
, "bar") != 0)
1566 printf("\n*********** Assemble function2(%s)\n", (char*)fun
->header
.a_name
);
1568 slang_print_function(fun
, 1);
1571 A
->program
->Parameters
= _mesa_new_parameter_list();
1572 A
->program
->Varying
= _mesa_new_parameter_list();
1573 A
->codegen
= _slang_new_codegen_context();
1575 /*printf("** Begin Simplify\n");*/
1576 slang_simplify(fun
->body
, &A
->space
, A
->atoms
);
1577 /*printf("** End Simplify\n");*/
1581 if (!CurFunction
->end_label
)
1582 CurFunction
->end_label
= slang_atom_pool_gen(A
->atoms
, "__endOfFunc_main_");
1584 n
= _slang_gen_operation(A
, fun
->body
);
1587 endLabel
= new_label(fun
->end_label
);
1588 n
= new_seq(n
, endLabel
);
1595 printf("************* New body for %s *****\n", (char*)fun
->header
.a_name
);
1596 slang_print_function(fun
, 1);
1598 printf("************* IR for %s *******\n", (char*)fun
->header
.a_name
);
1599 slang_print_ir(n
, 0);
1600 printf("************* End assemble function2 ************\n\n");
1603 if (_mesa_strcmp((char*) fun
->header
.a_name
, "main") == 0) {
1604 _slang_emit_code(n
, A
->codegen
, A
->program
);