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