7beb5b5d2409539fa96583505eea5781c1326702
[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 /**
127  * Emit the name of the source register at given input position.
128  */
129 void mips_emit_source_register(mips_emit_env_t *env, const ir_node *node,
130                                int pos)
131 {
132         const arch_register_t *reg = get_in_reg(env->arch_env, node, pos);
133         be_emit_char(env->emit, '$');
134         be_emit_string(env->emit, arch_register_get_name(reg));
135 }
136
137 /**
138  * Emit the name of the destination register at given output position.
139  */
140 void mips_emit_dest_register(mips_emit_env_t *env, const ir_node *node,
141                              int pos)
142 {
143         const arch_register_t *reg = get_out_reg(env->arch_env, node, pos);
144         be_emit_char(env->emit, '$');
145         be_emit_string(env->emit, arch_register_get_name(reg));
146 }
147
148 #if 0
149 static const char *get_symconst_str(ir_node *node)
150 {
151         ident *id;
152
153         switch(get_SymConst_kind(node)) {
154         case symconst_addr_name:
155                 id = get_SymConst_name(node);
156                 return get_id_str(id);
157         case symconst_addr_ent:
158                 id = get_entity_ident(get_SymConst_entity(node));
159                 return get_id_str(id);
160         default:
161                 assert(0);
162         }
163
164         return NULL;
165 }
166
167 /**
168  * Return a const or symconst as string.
169  */
170 static const char *node_const_to_str(ir_node *n)
171 {
172         static char buf[64];
173         const mips_attr_t *attr = get_mips_attr(n);
174         long val;
175
176         if(is_mips_load_r(n) || is_mips_store_r(n)) {
177                 mips_attr_t *attr = get_mips_attr(n);
178                 ir_node *symconst;
179
180                 if(attr->tv != NULL) {
181                         val = get_tarval_long(attr->tv);
182                         snprintf(buf, sizeof(buf), "%ld", val);
183
184                         return buf;
185                 }
186                 if(attr->stack_entity != NULL) {
187                         snprintf(buf, sizeof(buf), "%d", attr->stack_entity_offset);
188                         return buf;
189                 }
190
191                 symconst = get_irn_n(n, 1);
192                 assert(get_irn_opcode(symconst) == iro_SymConst);
193
194                 return get_symconst_str(symconst);
195         } else if(is_mips_la(n)) {
196                 snprintf(buf, sizeof(buf), "%s", get_id_str(attr->symconst_id));
197                 return buf;
198         } else if(is_mips_lli(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                         snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
203                 } else {
204                         unsigned long val = get_tarval_long(attr->tv);
205                         snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
206                 }
207
208                 return buf;
209         } else if(is_mips_lui(n)) {
210                 assert(attr->tv != NULL);
211                 if(get_mode_sign(get_tarval_mode(attr->tv))) {
212                         long val = get_tarval_long(attr->tv);
213                         val = (val & 0xffff0000) >> 16;
214                         snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
215                 } else {
216                         unsigned long val = get_tarval_long(attr->tv);
217                         val = (val & 0xffff0000) >> 16;
218                         snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
219                 }
220
221                 return buf;
222         }
223
224         assert(attr->tv != NULL);
225         val = get_tarval_long(attr->tv);
226         snprintf(buf, sizeof(buf), "%ld", val);
227
228         return buf;
229 }
230 #endif
231
232 void mips_emit_immediate(mips_emit_env_t *env, const ir_node *node)
233 {
234         const mips_attr_t *attr;
235
236         attr = get_mips_attr(node);
237         be_emit_tarval(env->emit, attr->tv);
238 }
239
240 /*
241  * Add a number to a prefix. This number will not be used a second time.
242  */
243 static
244 char *get_unique_label(char *buf, size_t buflen, const char *prefix)
245 {
246         static unsigned long id = 0;
247         snprintf(buf, buflen, "%s%lu", prefix, ++id);
248         return buf;
249 }
250
251 /************************************************************************/
252 /* ABI Handling                                                         */
253 /************************************************************************/
254
255 static
256 void mips_emit_IncSP(mips_emit_env_t *env, const ir_node *node)
257 {
258         int   offset = be_get_IncSP_offset(node);
259
260         if(offset == 0) {
261                 be_emit_cstring(env->emit, "\t/* omitted IncSP with 0 */");
262                 be_emit_finish_line_gas(env->emit, node);
263                 return;
264         }
265
266         if(offset > 0xffff || offset < -0xffff) {
267                 panic("stackframe > 2^16 bytes not supported yet\n");
268         }
269
270         if(offset > 0) {
271                 be_emit_irprintf(env->emit, "\tsubu $sp, $sp, %d", offset);
272         } else {
273                 be_emit_irprintf(env->emit, "\taddu $sp, $sp, %d", -offset);
274         }
275         be_emit_finish_line_gas(env->emit, node);
276 }
277
278 static void mips_emit_Copy(mips_emit_env_t *env, const ir_node *node)
279 {
280         be_emit_cstring(env->emit, "\tmove ");
281         mips_emit_dest_register(env, node, 0);
282         be_emit_cstring(env->emit, ", ");
283         mips_emit_source_register(env, node, 0);
284         be_emit_finish_line_gas(env->emit, node);
285 }
286
287 static void mips_emit_Return(mips_emit_env_t *env, const ir_node* node)
288 {
289         be_emit_cstring(env->emit, "\tj $ra");
290         be_emit_finish_line_gas(env->emit, node);
291 }
292
293 static __attribute__((unused))
294 void mips_emit_nops(mips_emit_env_t *env, int n)
295 {
296         int i;
297
298         for(i = 0; i < n; ++i) {
299                 be_emit_cstring(env->emit, "\tnop\n");
300                 be_emit_write_line(env->emit);
301         }
302 }
303
304 static void mips_emit_Perm(mips_emit_env_t *env, const ir_node *node)
305 {
306         assert(get_irn_arity(node) == 2);
307
308         be_emit_cstring(env->emit, "\txor ");
309         mips_emit_source_register(env, node, 0);
310         be_emit_cstring(env->emit, ", ");
311         mips_emit_source_register(env, node, 0);
312         be_emit_cstring(env->emit, ", ");
313         mips_emit_source_register(env, node, 1);
314         be_emit_finish_line_gas(env->emit, node);
315
316         /* mips_emit_nops(env, 3); */
317
318         be_emit_cstring(env->emit, "\txor ");
319         mips_emit_source_register(env, node, 1);
320         be_emit_cstring(env->emit, ", ");
321         mips_emit_source_register(env, node, 1);
322         be_emit_cstring(env->emit, ", ");
323         mips_emit_source_register(env, node, 0);
324         be_emit_finish_line_gas(env->emit, node);
325
326         /* mips_emit_nops(env, 3); */
327
328         be_emit_cstring(env->emit, "\txor ");
329         mips_emit_source_register(env, node, 0);
330         be_emit_cstring(env->emit, ", ");
331         mips_emit_source_register(env, node, 0);
332         be_emit_cstring(env->emit, ", ");
333         mips_emit_source_register(env, node, 1);
334         be_emit_finish_line_gas(env->emit, node);
335
336         /* mips_emit_nops(env, 3); */
337 }
338
339 /************************************************************************/
340 /* Calls                                                                */
341 /************************************************************************/
342
343 static void mips_emit_Call(mips_emit_env_t *env, const ir_node *node)
344 {
345         ir_entity *callee;
346
347         be_emit_cstring(env->emit, "\tjal ");
348
349         /* call of immediate value (label) */
350         callee = be_Call_get_entity(node);
351         if(callee != NULL) {
352                 be_emit_ident(env->emit, get_entity_ld_ident(callee));
353         } else {
354                 mips_emit_source_register(env, node, be_pos_Call_ptr);
355         }
356         be_emit_finish_line_gas(env->emit, node);
357 }
358
359 /************************************************************************
360  *      _
361  *     | |_   _ _ __ ___  _ __  ___
362  *  _  | | | | | '_ ` _ \| '_ \/ __|
363  * | |_| | |_| | | | | | | |_) \__ \
364  *  \___/ \__,_|_| |_| |_| .__/|___/
365  *                       |_|
366  ************************************************************************/
367
368 const char* mips_get_block_label(const ir_node* block)
369 {
370         static char buf[64];
371         snprintf(buf, sizeof(buf), "BLOCK_%ld", get_irn_node_nr(block));
372
373         return buf;
374 }
375
376 /**
377  * Emits a block label from the given block.
378  */
379 static
380 void mips_emit_block_label(mips_emit_env_t *env, const ir_node *block)
381 {
382         be_emit_irprintf(env->emit, "BLOCK_%ld", get_irn_node_nr(block));
383 }
384
385 static void mips_emit_Jump(mips_emit_env_t *env, const ir_node *node)
386 {
387         const ir_node *block = get_irn_link(node);
388         assert(is_Block(block));
389
390         be_emit_cstring(env->emit, "\tb ");
391         mips_emit_block_label(env, block);
392         be_emit_finish_line_gas(env->emit, node);
393 }
394
395 ir_node *mips_get_jump_block(const ir_node* node, int projn)
396 {
397         const ir_edge_t *oute;
398         for(oute = get_irn_out_edge_first(node); oute != NULL;
399             oute = get_irn_out_edge_next(node, oute)) {
400                 ir_node *proj = get_edge_src_irn(oute);
401                 long n;
402                 assert(is_Proj(proj));
403
404                 n = get_Proj_proj(proj);
405                 if(n == projn)
406                         return get_irn_link(proj);
407         }
408
409         return NULL;
410 }
411
412 void mips_emit_jump_target_proj(mips_emit_env_t *env, const ir_node *node, int projn)
413 {
414         ir_node *jumpblock = mips_get_jump_block(node, projn);
415         assert(jumpblock != NULL);
416
417         mips_emit_block_label(env, jumpblock);
418 }
419
420 void mips_emit_jump_target(mips_emit_env_t *env, const ir_node *node)
421 {
422         ir_node *jumpblock = get_irn_link(node);
423         assert(jumpblock != NULL);
424
425         mips_emit_block_label(env, jumpblock);
426 }
427
428 /************************************************************************
429  *  ____          _ _       _         _                                 *
430  * / ___|_      _(_) |_ ___| |__     | |_   _ _ __ ___  _ __            *
431  * \___ \ \ /\ / / | __/ __| '_ \ _  | | | | | '_ ` _ \| '_ \           *
432  *  ___) \ V  V /| | || (__| | | | |_| | |_| | | | | | | |_) |          *
433  * |____/ \_/\_/ |_|\__\___|_| |_|\___/ \__,_|_| |_| |_| .__/           *
434  *                                                     |_|              *
435  *                                                                      *
436  ************************************************************************/
437
438 /* jump table entry (target and corresponding number) */
439 typedef struct _branch_t {
440         ir_node *target;
441         int      value;
442 } branch_t;
443
444 /* jump table for switch generation */
445 typedef struct _jmp_tbl_t {
446         ir_node  *defBlock;        /**< default target */
447         int       min_value;       /**< smallest switch case */
448         int       max_value;       /**< largest switch case */
449         int       num_branches;    /**< number of jumps */
450         char     *label;           /**< label of the jump table */
451         branch_t *branches;        /**< jump array */
452 } jmp_tbl_t;
453
454 /**
455  * Compare two variables of type branch_t. Used to sort all switch cases
456  */
457 static int mips_cmp_branch_t(const void *a, const void *b) {
458         branch_t *b1 = (branch_t *)a;
459         branch_t *b2 = (branch_t *)b;
460
461         if (b1->value <= b2->value)
462                 return -1;
463         else
464                 return 1;
465 }
466
467 const char* mips_get_jumptbl_label(const ir_node* switchjmp)
468 {
469         static char buf[64];
470         snprintf(buf, sizeof(buf), "__JUMPTBL%ld", get_irn_node_nr(switchjmp));
471
472         return buf;
473 }
474
475 /**
476  * Emits code for a SwitchJmp (creates a jump table if
477  * possible otherwise a cmp-jmp cascade). Stolen from ia32
478  */
479 void emit_mips_jump_table(mips_emit_env_t *env, const ir_node *irn) {
480         int              lastval, i, i2, pn;
481         jmp_tbl_t        tbl;
482         ir_node         *proj;
483         const ir_edge_t *edge;
484         mips_attr_t     *attr = get_mips_attr(irn);
485
486         /* fill the table structure */
487         tbl.label        = xmalloc(SNPRINTF_BUF_LEN);
488         tbl.label        = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_");
489         tbl.defBlock     = NULL;
490         tbl.num_branches = get_irn_n_edges(irn);
491         tbl.branches     = xcalloc(tbl.num_branches, sizeof(tbl.branches[0]));
492         tbl.min_value    = INT_MAX;
493         tbl.max_value    = INT_MIN;
494
495         i = 0;
496         /* go over all proj's and collect them */
497         foreach_out_edge(irn, edge) {
498                 proj = get_edge_src_irn(edge);
499                 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
500
501                 pn = get_Proj_proj(proj);
502
503                 /* create branch entry */
504                 tbl.branches[i].target = get_irn_link(proj);
505                 tbl.branches[i].value  = pn;
506
507                 tbl.min_value = pn < tbl.min_value ? pn : tbl.min_value;
508                 tbl.max_value = pn > tbl.max_value ? pn : tbl.max_value;
509
510                 i++;
511         }
512
513         /* sort the branches by their number */
514         qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), mips_cmp_branch_t);
515
516         be_emit_string(env->emit, mips_get_jumptbl_label(irn));
517         be_emit_cstring(env->emit, ":\n");
518         be_emit_write_line(env->emit);
519         lastval = tbl.min_value;
520         for(i = 0; i < tbl.num_branches; ++i) {
521                 const branch_t *branch = &tbl.branches[i];
522                 int value = branch->value;
523
524                 for(i2 = lastval + 1; i2 < value; ++i2) {
525                         be_emit_cstring(env->emit, "\t.word ");
526                         be_emit_ident(env->emit, attr->symconst_id);
527                         be_emit_char(env->emit, '\n');
528                         be_emit_write_line(env->emit);
529                 }
530
531                 be_emit_cstring(env->emit, "\t.word ");
532                 mips_emit_block_label(env, branch->target);
533                 be_emit_char(env->emit, '\n');
534                 be_emit_write_line(env->emit);
535
536                 lastval = branch->value;
537         }
538
539         if (tbl.label)
540                 free(tbl.label);
541         if (tbl.branches)
542                 free(tbl.branches);
543 }
544
545 static
546 void dump_jump_tables(ir_node* node, void *data)
547 {
548         mips_emit_env_t *env = data;
549
550         // emit jump tables
551         if(is_mips_SwitchJump(node)) {
552                 be_emit_cstring(env->emit, ".data\n");
553                 be_emit_write_line(env->emit);
554
555                 emit_mips_jump_table(env, node);
556
557                 be_emit_cstring(env->emit, ".text\n");
558                 be_emit_write_line(env->emit);
559         }
560 }
561
562 /***********************************************************************************
563  *                  _          __                                             _
564  *                 (_)        / _|                                           | |
565  *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
566  * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
567  * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
568  * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
569  *
570  ***********************************************************************************/
571
572 static void mips_emit_nothing(mips_emit_env_t *env, const ir_node *node)
573 {
574         (void) env;
575         (void) node;
576 }
577
578 static void mips_emit_this_shouldnt_happen(mips_emit_env_t *env, const ir_node *node)
579 {
580         (void) env;
581         panic("Found non-lowered node %+F while emitting", node);
582 }
583
584 /**
585  * The type of a emitter function.
586  */
587 typedef void (*emit_func) (mips_emit_env_t *, const ir_node *);
588
589 /**
590  * Set a node emitter. Make it a bit more type safe.
591  */
592 static void register_emitter(ir_op *op, emit_func func) {
593         op->ops.generic = (op_func) func;
594 }
595
596 /**
597  * Register emitter functions for mips backend
598  */
599 void mips_register_emitters(void) {
600         /* first clear the generic function pointer for all ops */
601         clear_irp_opcodes_generic_func();
602
603         /* register all emitter functions defined in spec */
604         mips_register_spec_emitters();
605
606         /* benode emitter */
607         register_emitter(op_be_IncSP, mips_emit_IncSP);
608         register_emitter(op_be_SetSP, mips_emit_this_shouldnt_happen);
609         register_emitter(op_be_AddSP, mips_emit_this_shouldnt_happen);
610         register_emitter(op_be_Call, mips_emit_Call);
611         register_emitter(op_be_Copy, mips_emit_Copy);
612         register_emitter(op_be_Keep, mips_emit_nothing);
613         register_emitter(op_be_Barrier, mips_emit_nothing);
614         register_emitter(op_be_Return, mips_emit_Return);
615         register_emitter(op_be_RegParams, mips_emit_nothing);
616         register_emitter(op_be_Spill, mips_emit_this_shouldnt_happen);
617         register_emitter(op_be_Reload, mips_emit_this_shouldnt_happen);
618         register_emitter(op_be_Perm, mips_emit_Perm);
619
620         register_emitter(op_Start, mips_emit_nothing);
621         register_emitter(op_Proj, mips_emit_nothing);
622         register_emitter(op_SymConst, mips_emit_this_shouldnt_happen);
623         register_emitter(op_Const, mips_emit_this_shouldnt_happen);
624         register_emitter(op_Jmp, mips_emit_Jump);
625         register_emitter(op_Cmp, mips_emit_this_shouldnt_happen);
626         register_emitter(op_Cond, mips_emit_this_shouldnt_happen);
627 }
628
629 /**
630  * Emits assembly for a single node
631  */
632 static void mips_emit_node(mips_emit_env_t *env, const ir_node *node)
633 {
634         ir_op *op = get_irn_op(node);
635
636         if (op->ops.generic) {
637                 emit_func emit = (emit_func) op->ops.generic;
638                 (*emit) (env, node);
639         } else {
640                 panic("No emitter defined for node %+F", 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_ld_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 }