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