no environment anymore for emitters
[libfirm] / ir / be / mips / mips_emitter.c
1 /*
2  * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   implementation of mips assembly emitter
23  * @author  Matthias Braun, Mehdi
24  * @version $Id$
25  */
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include <limits.h>
31
32 #include "xmalloc.h"
33 #include "iredges.h"
34 #include "debug.h"
35 #include "irgwalk.h"
36 #include "irprintf.h"
37 #include "irop_t.h"
38 #include "irargs_t.h"
39 #include "irprog_t.h"
40 #include "irouts.h"
41 #include "tv.h"
42 #include "error.h"
43
44 #include "../besched.h"
45 #include "../benode_t.h"
46 #include "../beutil.h"
47 #include "../begnuas.h"
48
49 #include "mips_emitter.h"
50 #include "gen_mips_emitter.h"
51 #include "mips_nodes_attr.h"
52 #include "mips_new_nodes.h"
53 #include "mips_map_regs.h"
54
55 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
56
57 #define BLOCK_PREFIX ".L"
58
59 #define SNPRINTF_BUF_LEN 128
60
61 static const mips_isa_t      *isa;
62 static const arch_env_t      *arch_env;
63 static const mips_code_gen_t *cg;
64
65 /**
66  * Returns the register at in position pos.
67  */
68 static const arch_register_t *get_in_reg(const ir_node *node, int pos)
69 {
70         ir_node                *op;
71         const arch_register_t  *reg = NULL;
72
73         assert(get_irn_arity(node) > pos && "Invalid IN position");
74
75         /* The out register of the operator at position pos is the
76            in register we need. */
77         op = get_irn_n(node, pos);
78
79         reg = arch_get_irn_register(arch_env, op);
80
81         assert(reg && "no in register found");
82         return reg;
83 }
84
85 /**
86  * Returns the register at out position pos.
87  */
88 static const arch_register_t *get_out_reg(const ir_node *node, int pos)
89 {
90         ir_node                *proj;
91         const arch_register_t  *reg = NULL;
92
93         /* 1st case: irn is not of mode_T, so it has only                 */
94         /*           one OUT register -> good                             */
95         /* 2nd case: irn is of mode_T -> collect all Projs and ask the    */
96         /*           Proj with the corresponding projnum for the register */
97
98         if (get_irn_mode(node) != mode_T) {
99                 reg = arch_get_irn_register(arch_env, node);
100         } else if (is_mips_irn(node)) {
101                 reg = get_mips_out_reg(node, pos);
102         } else {
103                 const ir_edge_t *edge;
104
105                 foreach_out_edge(node, edge) {
106                         proj = get_edge_src_irn(edge);
107                         assert(is_Proj(proj) && "non-Proj from mode_T node");
108                         if (get_Proj_proj(proj) == pos) {
109                                 reg = arch_get_irn_register(arch_env, proj);
110                                 break;
111                         }
112                 }
113         }
114
115         assert(reg && "no out register found");
116         return reg;
117 }
118
119 /*************************************************************
120  *             _       _    __   _          _
121  *            (_)     | |  / _| | |        | |
122  *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
123  * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
124  * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
125  * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
126  * | |                                       | |
127  * |_|                                       |_|
128  *************************************************************/
129
130 /**
131  * Emit the name of the source register at given input position.
132  */
133 void mips_emit_source_register(const ir_node *node, int pos)
134 {
135         const arch_register_t *reg = get_in_reg(node, pos);
136         be_emit_char('$');
137         be_emit_string(arch_register_get_name(reg));
138 }
139
140 /**
141  * Emit the name of the destination register at given output position.
142  */
143 void mips_emit_dest_register(const ir_node *node, int pos)
144 {
145         const arch_register_t *reg = get_out_reg(node, pos);
146         be_emit_char('$');
147         be_emit_string(arch_register_get_name(reg));
148 }
149
150 #if 0
151 static const char *get_symconst_str(ir_node *node)
152 {
153         ident *id;
154
155         switch(get_SymConst_kind(node)) {
156         case symconst_addr_name:
157                 id = get_SymConst_name(node);
158                 return get_id_str(id);
159         case symconst_addr_ent:
160                 id = get_entity_ident(get_SymConst_entity(node));
161                 return get_id_str(id);
162         default:
163                 assert(0);
164         }
165
166         return NULL;
167 }
168
169 /**
170  * Return a const or symconst as string.
171  */
172 static const char *node_const_to_str(ir_node *n)
173 {
174         static char buf[64];
175         const mips_attr_t *attr = get_mips_attr(n);
176         long val;
177
178         if(is_mips_load_r(n) || is_mips_store_r(n)) {
179                 mips_attr_t *attr = get_mips_attr(n);
180                 ir_node *symconst;
181
182                 if(attr->tv != NULL) {
183                         val = get_tarval_long(attr->tv);
184                         snprintf(buf, sizeof(buf), "%ld", val);
185
186                         return buf;
187                 }
188                 if(attr->stack_entity != NULL) {
189                         snprintf(buf, sizeof(buf), "%d", attr->stack_entity_offset);
190                         return buf;
191                 }
192
193                 symconst = get_irn_n(n, 1);
194                 assert(get_irn_opcode(symconst) == iro_SymConst);
195
196                 return get_symconst_str(symconst);
197         } else if(is_mips_la(n)) {
198                 snprintf(buf, sizeof(buf), "%s", get_id_str(attr->symconst_id));
199                 return buf;
200         } else if(is_mips_lli(n)) {
201                 assert(attr->tv != NULL);
202                 if(get_mode_sign(get_tarval_mode(attr->tv))) {
203                         long val = get_tarval_long(attr->tv);
204                         snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
205                 } else {
206                         unsigned long val = get_tarval_long(attr->tv);
207                         snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
208                 }
209
210                 return buf;
211         } else if(is_mips_lui(n)) {
212                 assert(attr->tv != NULL);
213                 if(get_mode_sign(get_tarval_mode(attr->tv))) {
214                         long val = get_tarval_long(attr->tv);
215                         val = (val & 0xffff0000) >> 16;
216                         snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
217                 } else {
218                         unsigned long val = get_tarval_long(attr->tv);
219                         val = (val & 0xffff0000) >> 16;
220                         snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
221                 }
222
223                 return buf;
224         }
225
226         assert(attr->tv != NULL);
227         val = get_tarval_long(attr->tv);
228         snprintf(buf, sizeof(buf), "%ld", val);
229
230         return buf;
231 }
232 #endif
233
234 void mips_emit_load_store_address(const ir_node *node, int pos)
235 {
236         const mips_load_store_attr_t *attr = get_mips_load_store_attr_const(node);
237
238         be_emit_irprintf("%d(", attr->offset);
239         mips_emit_source_register(node, pos);
240         be_emit_char(')');
241 }
242
243 void mips_emit_immediate_suffix(const ir_node *node, int pos)
244 {
245         ir_node *op = get_irn_n(node, pos);
246         if(is_mips_Immediate(op))
247                 be_emit_char('i');
248 }
249
250 void mips_emit_immediate(const ir_node *node)
251 {
252         const mips_immediate_attr_t *attr = get_mips_immediate_attr_const(node);
253
254         switch(attr->imm_type) {
255         case MIPS_IMM_CONST:
256                 be_emit_irprintf("%d", attr->val);
257                 break;
258         case MIPS_IMM_SYMCONST_LO:
259                 be_emit_cstring("%lo($");
260                 be_emit_ident(get_entity_ld_ident(attr->entity));
261                 if(attr->val != 0) {
262                         be_emit_irprintf("%+d", attr->val);
263                 }
264                 be_emit_char(')');
265                 break;
266         case MIPS_IMM_SYMCONST_HI:
267                 be_emit_cstring("%hi($");
268                 be_emit_ident(get_entity_ld_ident(attr->entity));
269                 if(attr->val != 0) {
270                         be_emit_irprintf("%+d", attr->val);
271                 }
272                 be_emit_char(')');
273                 break;
274         default:
275                 panic("invalid immediate type found");
276         }
277 }
278
279 /**
280  * Emit the name of the destination register at given output position.
281  */
282 void mips_emit_source_register_or_immediate(const ir_node *node, int pos)
283 {
284         const ir_node *op = get_irn_n(node, pos);
285         if(is_mips_Immediate(op)) {
286                 mips_emit_immediate(op);
287         } else {
288                 mips_emit_source_register(node, pos);
289         }
290 }
291
292 #if 0
293 /*
294  * Add a number to a prefix. This number will not be used a second time.
295  */
296 static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
297 {
298         static unsigned long id = 0;
299         snprintf(buf, buflen, "%s%lu", prefix, ++id);
300         return buf;
301 }
302 #endif
303
304 /************************************************************************/
305 /* ABI Handling                                                         */
306 /************************************************************************/
307
308 static
309 void mips_emit_IncSP(const ir_node *node)
310 {
311         int   offset = be_get_IncSP_offset(node);
312
313         if(offset == 0) {
314                 be_emit_cstring("\t/* omitted IncSP with 0 */");
315                 be_emit_finish_line_gas(node);
316                 return;
317         }
318
319         if(offset > 0xffff || offset < -0xffff) {
320                 panic("stackframe > 2^16 bytes not supported yet\n");
321         }
322
323         if(offset > 0) {
324                 be_emit_irprintf("\tsubu $sp, $sp, %d", offset);
325         } else {
326                 be_emit_irprintf("\taddu $sp, $sp, %d", -offset);
327         }
328         be_emit_finish_line_gas(node);
329 }
330
331 static void mips_emit_Copy(const ir_node *node)
332 {
333         be_emit_cstring("\tmove ");
334         mips_emit_dest_register(node, 0);
335         be_emit_cstring(", ");
336         mips_emit_source_register(node, 0);
337         be_emit_finish_line_gas(node);
338 }
339
340 static void mips_emit_Return(const ir_node* node)
341 {
342         be_emit_cstring("\tj $ra");
343         be_emit_finish_line_gas(node);
344 }
345
346 static __attribute__((unused))
347 void mips_emit_nops(int n)
348 {
349         int i;
350
351         for(i = 0; i < n; ++i) {
352                 be_emit_cstring("\tnop\n");
353                 be_emit_write_line();
354         }
355 }
356
357 static void mips_emit_Perm(const ir_node *node)
358 {
359         assert(get_irn_arity(node) == 2);
360
361         be_emit_cstring("\txor ");
362         mips_emit_source_register(node, 0);
363         be_emit_cstring(", ");
364         mips_emit_source_register(node, 0);
365         be_emit_cstring(", ");
366         mips_emit_source_register(node, 1);
367         be_emit_finish_line_gas(node);
368
369         /* mips_emit_nops(3); */
370
371         be_emit_cstring("\txor ");
372         mips_emit_source_register(node, 1);
373         be_emit_cstring(", ");
374         mips_emit_source_register(node, 1);
375         be_emit_cstring(", ");
376         mips_emit_source_register(node, 0);
377         be_emit_finish_line_gas(node);
378
379         /* mips_emit_nops(3); */
380
381         be_emit_cstring("\txor ");
382         mips_emit_source_register(node, 0);
383         be_emit_cstring(", ");
384         mips_emit_source_register(node, 0);
385         be_emit_cstring(", ");
386         mips_emit_source_register(node, 1);
387         be_emit_finish_line_gas(node);
388
389         /* mips_emit_nops(3); */
390 }
391
392 /************************************************************************/
393 /* Calls                                                                */
394 /************************************************************************/
395
396 static void mips_emit_Call(const ir_node *node)
397 {
398         ir_entity *callee;
399
400         be_emit_cstring("\tjal ");
401
402         /* call of immediate value (label) */
403         callee = be_Call_get_entity(node);
404         if(callee != NULL) {
405                 be_emit_ident(get_entity_ld_ident(callee));
406         } else {
407                 mips_emit_source_register(node, be_pos_Call_ptr);
408         }
409         be_emit_finish_line_gas(node);
410 }
411
412 /************************************************************************
413  *      _
414  *     | |_   _ _ __ ___  _ __  ___
415  *  _  | | | | | '_ ` _ \| '_ \/ __|
416  * | |_| | |_| | | | | | | |_) \__ \
417  *  \___/ \__,_|_| |_| |_| .__/|___/
418  *                       |_|
419  ************************************************************************/
420
421 const char* mips_get_block_label(const ir_node* block)
422 {
423         static char buf[64];
424         snprintf(buf, sizeof(buf), "BLOCK_%ld", get_irn_node_nr(block));
425
426         return buf;
427 }
428
429 /**
430  * Emits a block label from the given block.
431  */
432 static void mips_emit_block_label(const ir_node *block)
433 {
434         if (has_Block_label(block)) {
435                 be_emit_string(be_gas_label_prefix());
436                 be_emit_irprintf("%lu", get_Block_label(block));
437         } else {
438                 be_emit_cstring(BLOCK_PREFIX);
439                 be_emit_irprintf("%d", get_irn_node_nr(block));
440
441         }
442 }
443
444 static void mips_emit_Jump(const ir_node *node)
445 {
446         const ir_node *block = get_irn_link(node);
447         assert(is_Block(block));
448
449         be_emit_cstring("\tb ");
450         mips_emit_block_label(block);
451         be_emit_finish_line_gas(node);
452 }
453
454 ir_node *mips_get_jump_block(const ir_node* node, long projn)
455 {
456         const ir_edge_t *oute;
457         for(oute = get_irn_out_edge_first(node); oute != NULL;
458             oute = get_irn_out_edge_next(node, oute)) {
459                 ir_node *proj = get_edge_src_irn(oute);
460                 long n;
461                 assert(is_Proj(proj));
462
463                 n = get_Proj_proj(proj);
464                 if(n == projn)
465                         return get_irn_link(proj);
466         }
467
468         return NULL;
469 }
470
471 void mips_emit_jump_target_proj(const ir_node *node, long projn)
472 {
473         ir_node *jumpblock = mips_get_jump_block(node, projn);
474         assert(jumpblock != NULL);
475
476         mips_emit_block_label(jumpblock);
477 }
478
479 void mips_emit_jump_target(const ir_node *node)
480 {
481         ir_node *jumpblock = get_irn_link(node);
482         assert(jumpblock != NULL);
483
484         mips_emit_block_label(jumpblock);
485 }
486
487 void mips_emit_jump_or_fallthrough(const ir_node *node, long pn)
488 {
489         ir_node *jumpblock = mips_get_jump_block(node, pn);
490         assert(jumpblock != NULL);
491
492         /* TODO: use fallthrough when possible */
493         be_emit_cstring("b ");
494         mips_emit_block_label(jumpblock);
495 }
496
497 /************************************************************************
498  *  ____          _ _       _         _                                 *
499  * / ___|_      _(_) |_ ___| |__     | |_   _ _ __ ___  _ __            *
500  * \___ \ \ /\ / / | __/ __| '_ \ _  | | | | | '_ ` _ \| '_ \           *
501  *  ___) \ V  V /| | || (__| | | | |_| | |_| | | | | | | |_) |          *
502  * |____/ \_/\_/ |_|\__\___|_| |_|\___/ \__,_|_| |_| |_| .__/           *
503  *                                                     |_|              *
504  *                                                                      *
505  ************************************************************************/
506
507 #if 0
508 /* jump table entry (target and corresponding number) */
509 typedef struct _branch_t {
510         ir_node *target;
511         int      value;
512 } branch_t;
513
514 /* jump table for switch generation */
515 typedef struct _jmp_tbl_t {
516         ir_node  *defBlock;        /**< default target */
517         int       min_value;       /**< smallest switch case */
518         int       max_value;       /**< largest switch case */
519         int       num_branches;    /**< number of jumps */
520         char     *label;           /**< label of the jump table */
521         branch_t *branches;        /**< jump array */
522 } jmp_tbl_t;
523
524 /**
525  * Compare two variables of type branch_t. Used to sort all switch cases
526  */
527 static int mips_cmp_branch_t(const void *a, const void *b)
528 {
529         branch_t *b1 = (branch_t *)a;
530         branch_t *b2 = (branch_t *)b;
531
532         if (b1->value <= b2->value)
533                 return -1;
534         else
535                 return 1;
536 }
537
538 const char* mips_get_jumptbl_label(const ir_node* switchjmp)
539 {
540         static char buf[64];
541         snprintf(buf, sizeof(buf), "__JUMPTBL%ld", get_irn_node_nr(switchjmp));
542
543         return buf;
544 }
545
546 /**
547  * Emits code for a SwitchJmp (creates a jump table if
548  * possible otherwise a cmp-jmp cascade). Stolen from ia32
549  */
550 void emit_mips_jump_table(const ir_node *irn)
551 {
552         int                lastval, i, i2, pn;
553         jmp_tbl_t          tbl;
554         ir_node           *proj;
555         const ir_edge_t   *edge;
556         const mips_attr_t *attr = get_mips_attr_const(irn);
557
558         /* fill the table structure */
559         tbl.label        = xmalloc(SNPRINTF_BUF_LEN);
560         tbl.label        = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_");
561         tbl.defBlock     = NULL;
562         tbl.num_branches = get_irn_n_edges(irn);
563         tbl.branches     = xcalloc(tbl.num_branches, sizeof(tbl.branches[0]));
564         tbl.min_value    = INT_MAX;
565         tbl.max_value    = INT_MIN;
566
567         i = 0;
568         /* go over all proj's and collect them */
569         foreach_out_edge(irn, edge) {
570                 proj = get_edge_src_irn(edge);
571                 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
572
573                 pn = get_Proj_proj(proj);
574
575                 /* create branch entry */
576                 tbl.branches[i].target = get_irn_link(proj);
577                 tbl.branches[i].value  = pn;
578
579                 tbl.min_value = pn < tbl.min_value ? pn : tbl.min_value;
580                 tbl.max_value = pn > tbl.max_value ? pn : tbl.max_value;
581
582                 i++;
583         }
584
585         /* sort the branches by their number */
586         qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), mips_cmp_branch_t);
587
588         be_emit_string(mips_get_jumptbl_label(irn));
589         be_emit_cstring(":\n");
590         be_emit_write_line();
591         lastval = tbl.min_value;
592         for(i = 0; i < tbl.num_branches; ++i) {
593                 const branch_t *branch = &tbl.branches[i];
594                 int value = branch->value;
595
596                 for(i2 = lastval + 1; i2 < value; ++i2) {
597                         be_emit_cstring("\t.word ");
598                         be_emit_ident(get_entity_ld_ident(attr->symconst));
599                         be_emit_char('\n');
600                         be_emit_write_line();
601                 }
602
603                 be_emit_cstring("\t.word ");
604                 mips_emit_block_label(branch->target);
605                 be_emit_char('\n');
606                 be_emit_write_line();
607
608                 lastval = branch->value;
609         }
610
611         if (tbl.label)
612                 free(tbl.label);
613         if (tbl.branches)
614                 free(tbl.branches);
615 }
616
617 static void dump_jump_tables(ir_node* node, void *data)
618 {
619         (void) data;
620
621         // emit jump tables
622         if(is_mips_SwitchJump(node)) {
623                 be_emit_cstring(".data\n");
624                 be_emit_write_line();
625
626                 emit_mips_jump_table(node);
627
628                 be_emit_cstring(".text\n");
629                 be_emit_write_line();
630         }
631 }
632 #endif
633
634 /***********************************************************************************
635  *                  _          __                                             _
636  *                 (_)        / _|                                           | |
637  *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
638  * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
639  * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
640  * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
641  *
642  ***********************************************************************************/
643
644 static void mips_emit_nothing(const ir_node *node)
645 {
646         (void) node;
647 }
648
649 static void mips_emit_this_shouldnt_happen(const ir_node *node)
650 {
651         panic("Found non-lowered node %+F while emitting", node);
652 }
653
654 /**
655  * The type of a emitter function.
656  */
657 typedef void (*emit_func) (const ir_node *);
658
659 /**
660  * Set a node emitter. Make it a bit more type safe.
661  */
662 static void register_emitter(ir_op *op, emit_func func)
663 {
664         op->ops.generic = (op_func) func;
665 }
666
667 /**
668  * Register emitter functions for mips backend
669  */
670 void mips_register_emitters(void)
671 {
672         /* first clear the generic function pointer for all ops */
673         clear_irp_opcodes_generic_func();
674
675         /* register all emitter functions defined in spec */
676         mips_register_spec_emitters();
677
678         /* benode emitter */
679         register_emitter(op_be_IncSP, mips_emit_IncSP);
680         register_emitter(op_be_AddSP, mips_emit_this_shouldnt_happen);
681         register_emitter(op_be_Call, mips_emit_Call);
682         register_emitter(op_be_Copy, mips_emit_Copy);
683         register_emitter(op_be_Keep, mips_emit_nothing);
684         register_emitter(op_be_Barrier, mips_emit_nothing);
685         register_emitter(op_be_Return, mips_emit_Return);
686         register_emitter(op_be_RegParams, mips_emit_nothing);
687         register_emitter(op_be_Spill, mips_emit_this_shouldnt_happen);
688         register_emitter(op_be_Reload, mips_emit_this_shouldnt_happen);
689         register_emitter(op_be_Perm, mips_emit_Perm);
690
691         register_emitter(op_Start, mips_emit_nothing);
692         register_emitter(op_Proj, mips_emit_nothing);
693         register_emitter(op_SymConst, mips_emit_this_shouldnt_happen);
694         register_emitter(op_Const, mips_emit_this_shouldnt_happen);
695         register_emitter(op_Jmp, mips_emit_Jump);
696         register_emitter(op_Cmp, mips_emit_this_shouldnt_happen);
697         register_emitter(op_Cond, mips_emit_this_shouldnt_happen);
698         register_emitter(op_Phi, mips_emit_nothing);
699 }
700
701 /**
702  * Emits assembly for a single node
703  */
704 static void mips_emit_node(const ir_node *node)
705 {
706         ir_op *op = get_irn_op(node);
707
708         if (op->ops.generic) {
709                 emit_func emit = (emit_func) op->ops.generic;
710                 (*emit) (node);
711         } else {
712                 panic("No emitter defined for node %+F", node);
713         }
714 }
715
716 /**
717  * Walks over the nodes in a block connected by scheduling edges
718  * and emits code for each node.
719  */
720 void mips_gen_block(const ir_node *block)
721 {
722         ir_node *node;
723
724         if (! is_Block(block))
725                 return;
726
727         mips_emit_block_label(block);
728         be_emit_cstring(":\n");
729         be_emit_write_line();
730
731         sched_foreach(block, node) {
732                 mips_emit_node(node);
733         }
734
735         be_emit_char('\n');
736         be_emit_write_line();
737 }
738
739 /**
740  * Emits code for function start.
741  */
742 void mips_emit_func_prolog(ir_graph *irg)
743 {
744         ident *irg_ident = get_entity_ld_ident(get_irg_entity(irg));
745
746         // dump jump tables
747         //irg_walk_graph(irg, NULL, dump_jump_tables, env);
748
749         be_emit_write_line();
750         be_gas_emit_switch_section(GAS_SECTION_TEXT);
751
752         be_emit_cstring("\t.balign\t4\n");
753
754         be_emit_cstring("\t.global\t");
755         be_emit_ident(irg_ident);
756         be_emit_char('\n');
757
758         be_emit_cstring("\t.set\tnomips16\n");
759
760         be_emit_cstring("\t.ent\t");
761         be_emit_ident(irg_ident);
762         be_emit_char('\n');
763
764         be_emit_ident(irg_ident);
765         be_emit_cstring(":\n");
766
767         be_emit_cstring("\t.frame\t$fp, 24, $ra\n");
768         be_emit_cstring("\t.mask\t0xc0000000, -4\n");
769         be_emit_cstring("\t.fmask\t0x00000000, 0\n");
770
771         be_emit_write_line();
772 }
773
774 /**
775  * Emits code for function end
776  */
777 void mips_emit_func_epilog(ir_graph *irg)
778 {
779         ident *irg_ident = get_entity_ident(get_irg_entity(irg));
780
781         be_emit_cstring("\t.end\t");
782         be_emit_ident(irg_ident);
783         be_emit_char('\n');
784         be_emit_write_line();
785 }
786
787 /**
788  * Sets labels for control flow nodes (jump target)
789  */
790 void mips_gen_labels(ir_node *block, void *env)
791 {
792         ir_node *pred;
793         int n = get_Block_n_cfgpreds(block);
794         (void) env;
795
796         for (n--; n >= 0; n--) {
797                 pred = get_Block_cfgpred(block, n);
798                 set_irn_link(pred, block);
799         }
800 }
801
802 /**
803  * Main driver
804  */
805 void mips_gen_routine(mips_code_gen_t *mips_cg, ir_graph *irg)
806 {
807         int i, n;
808
809         cg       = mips_cg;
810         isa      = (const mips_isa_t*) cg->arch_env->isa;
811         arch_env = cg->arch_env;
812
813         mips_register_emitters();
814
815         irg_block_walk_graph(irg, mips_gen_labels, NULL, NULL);
816
817         mips_emit_func_prolog(irg);
818
819         dump_ir_block_graph_sched(irg, "-kaputtelist");
820
821         for (i = 0, n = mips_get_sched_n_blocks(cg); i < n; ++i) {
822                 ir_node *block = mips_get_sched_block(cg, i);
823                 mips_gen_block(block);
824         }
825
826         mips_emit_func_epilog(irg);
827 }
828
829 void mips_init_emitter(void)
830 {
831         FIRM_DBG_REGISTER(dbg, "firm.be.mips.emitter");
832 }