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