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