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