fix mips
[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_char(env->emit, '$');
131         be_emit_string(env->emit, arch_register_get_name(reg));
132 }
133
134 void mips_emit_dest_register(mips_emit_env_t *env, const ir_node *node,
135                              int pos)
136 {
137         const arch_register_t *reg = get_out_reg(env->arch_env, node, pos);
138         be_emit_char(env->emit, '$');
139         be_emit_string(env->emit, 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                 assert(0);
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_immediate(mips_emit_env_t *env, const ir_node *node)
227 {
228         const mips_attr_t *attr;
229
230         attr = get_mips_attr(node);
231         be_emit_tarval(env->emit, attr->tv);
232 }
233
234 /*
235  * Add a number to a prefix. This number will not be used a second time.
236  */
237 static
238 char *get_unique_label(char *buf, size_t buflen, const char *prefix)
239 {
240         static unsigned long id = 0;
241         snprintf(buf, buflen, "%s%lu", prefix, ++id);
242         return buf;
243 }
244
245 /************************************************************************/
246 /* ABI Handling                                                         */
247 /************************************************************************/
248
249 static
250 void mips_emit_IncSP(mips_emit_env_t *env, const ir_node *node)
251 {
252         int   offset = be_get_IncSP_offset(node);
253
254         if(offset == 0) {
255                 be_emit_cstring(env->emit, "\t/* omitted IncSP with 0 */");
256                 be_emit_finish_line_gas(env->emit, node);
257                 return;
258         }
259
260         if(offset > 0xffff || offset < -0xffff) {
261                 panic("stackframe > 2^16 bytes not supported yet\n");
262         }
263
264         if(offset > 0) {
265                 be_emit_irprintf(env->emit, "\tsubu $sp, $sp, %d", offset);
266         } else {
267                 be_emit_irprintf(env->emit, "\taddu $sp, $sp, %d", -offset);
268         }
269         be_emit_finish_line_gas(env->emit, node);
270 }
271
272 static void mips_emit_Copy(mips_emit_env_t *env, const ir_node *node)
273 {
274         be_emit_cstring(env->emit, "\tmove ");
275         mips_emit_dest_register(env, node, 0);
276         be_emit_cstring(env->emit, ", ");
277         mips_emit_source_register(env, node, 0);
278         be_emit_finish_line_gas(env->emit, node);
279 }
280
281 static void mips_emit_Return(mips_emit_env_t *env, const ir_node* node)
282 {
283         be_emit_cstring(env->emit, "\tj $ra");
284         be_emit_finish_line_gas(env->emit, node);
285 }
286
287 static __attribute__((unused))
288 void mips_emit_nops(mips_emit_env_t *env, int n)
289 {
290         int i;
291
292         for(i = 0; i < n; ++i) {
293                 be_emit_cstring(env->emit, "\tnop\n");
294                 be_emit_write_line(env->emit);
295         }
296 }
297
298 static void mips_emit_Perm(mips_emit_env_t *env, const ir_node *node)
299 {
300         assert(get_irn_arity(node) == 2);
301
302         be_emit_cstring(env->emit, "\txor ");
303         mips_emit_source_register(env, node, 0);
304         be_emit_cstring(env->emit, ", ");
305         mips_emit_source_register(env, node, 0);
306         be_emit_cstring(env->emit, ", ");
307         mips_emit_source_register(env, node, 1);
308         be_emit_finish_line_gas(env->emit, node);
309
310         /* mips_emit_nops(env, 3); */
311
312         be_emit_cstring(env->emit, "\txor ");
313         mips_emit_source_register(env, node, 1);
314         be_emit_cstring(env->emit, ", ");
315         mips_emit_source_register(env, node, 1);
316         be_emit_cstring(env->emit, ", ");
317         mips_emit_source_register(env, node, 0);
318         be_emit_finish_line_gas(env->emit, node);
319
320         /* mips_emit_nops(env, 3); */
321
322         be_emit_cstring(env->emit, "\txor ");
323         mips_emit_source_register(env, node, 0);
324         be_emit_cstring(env->emit, ", ");
325         mips_emit_source_register(env, node, 0);
326         be_emit_cstring(env->emit, ", ");
327         mips_emit_source_register(env, node, 1);
328         be_emit_finish_line_gas(env->emit, node);
329
330         /* mips_emit_nops(env, 3); */
331 }
332
333 /************************************************************************/
334 /* Calls                                                                */
335 /************************************************************************/
336
337 static void mips_emit_Call(mips_emit_env_t *env, const ir_node *node)
338 {
339         ir_entity *callee;
340
341         be_emit_cstring(env->emit, "\tjal ");
342
343         /* call of immediate value (label) */
344         callee = be_Call_get_entity(node);
345         if(callee != NULL) {
346                 be_emit_ident(env->emit, get_entity_ident(callee));
347         } else {
348                 mips_emit_source_register(env, node, be_pos_Call_ptr);
349         }
350         be_emit_finish_line_gas(env->emit, node);
351 }
352
353 /************************************************************************
354  *      _
355  *     | |_   _ _ __ ___  _ __  ___
356  *  _  | | | | | '_ ` _ \| '_ \/ __|
357  * | |_| | |_| | | | | | | |_) \__ \
358  *  \___/ \__,_|_| |_| |_| .__/|___/
359  *                       |_|
360  ************************************************************************/
361
362 const char* mips_get_block_label(const ir_node* block)
363 {
364         static char buf[64];
365         snprintf(buf, sizeof(buf), "BLOCK_%ld", get_irn_node_nr(block));
366
367         return buf;
368 }
369
370 static
371 void mips_emit_block_label(mips_emit_env_t *env, const ir_node *block)
372 {
373         be_emit_irprintf(env->emit, "BLOCK_%ld", get_irn_node_nr(block));
374 }
375
376 static void mips_emit_Jump(mips_emit_env_t *env, const ir_node *node)
377 {
378         const ir_node *block = get_irn_link(node);
379         assert(is_Block(block));
380
381         be_emit_cstring(env->emit, "\tb ");
382         mips_emit_block_label(env, block);
383         be_emit_finish_line_gas(env->emit, node);
384 }
385
386 ir_node *mips_get_jump_block(const ir_node* node, int projn)
387 {
388         const ir_edge_t *oute;
389         for(oute = get_irn_out_edge_first(node); oute != NULL;
390             oute = get_irn_out_edge_next(node, oute)) {
391                 ir_node *proj = get_edge_src_irn(oute);
392                 long n;
393                 assert(is_Proj(proj));
394
395                 n = get_Proj_proj(proj);
396                 if(n == projn)
397                         return get_irn_link(proj);
398         }
399
400         return NULL;
401 }
402
403 void mips_emit_jump_target_proj(mips_emit_env_t *env, const ir_node *node, int projn)
404 {
405         ir_node *jumpblock = mips_get_jump_block(node, projn);
406         assert(jumpblock != NULL);
407
408         mips_emit_block_label(env, jumpblock);
409 }
410
411 void mips_emit_jump_target(mips_emit_env_t *env, const ir_node *node)
412 {
413         ir_node *jumpblock = get_irn_link(node);
414         assert(jumpblock != NULL);
415
416         mips_emit_block_label(env, jumpblock);
417 }
418
419 /************************************************************************
420  *  ____          _ _       _         _                                                                 *
421  * / ___|_      _(_) |_ ___| |__     | |_   _ _ __ ___  _ __                    *
422  * \___ \ \ /\ / / | __/ __| '_ \ _  | | | | | '_ ` _ \| '_ \                   *
423  *  ___) \ V  V /| | || (__| | | | |_| | |_| | | | | | | |_) |                  *
424  * |____/ \_/\_/ |_|\__\___|_| |_|\___/ \__,_|_| |_| |_| .__/                   *
425  *                                                     |_|                              *
426  *                                                                      *
427  ************************************************************************/
428
429 /* jump table entry (target and corresponding number) */
430 typedef struct _branch_t {
431         ir_node *target;
432         int      value;
433 } branch_t;
434
435 /* jump table for switch generation */
436 typedef struct _jmp_tbl_t {
437         ir_node  *defBlock;        /**< default target */
438         int       min_value;       /**< smallest switch case */
439         int       max_value;       /**< largest switch case */
440         int       num_branches;    /**< number of jumps */
441         char     *label;           /**< label of the jump table */
442         branch_t *branches;        /**< jump array */
443 } jmp_tbl_t;
444
445 /**
446  * Compare two variables of type branch_t. Used to sort all switch cases
447  */
448 static int mips_cmp_branch_t(const void *a, const void *b) {
449         branch_t *b1 = (branch_t *)a;
450         branch_t *b2 = (branch_t *)b;
451
452         if (b1->value <= b2->value)
453                 return -1;
454         else
455                 return 1;
456 }
457
458 const char* mips_get_jumptbl_label(const ir_node* switchjmp)
459 {
460         static char buf[64];
461         snprintf(buf, sizeof(buf), "__JUMPTBL%ld", get_irn_node_nr(switchjmp));
462
463         return buf;
464 }
465
466 /**
467  * Emits code for a SwitchJmp (creates a jump table if
468  * possible otherwise a cmp-jmp cascade). Stolen from ia32
469  */
470 void emit_mips_jump_table(mips_emit_env_t *env, const ir_node *irn) {
471         int              lastval, i, i2, pn;
472         jmp_tbl_t        tbl;
473         ir_node         *proj;
474         const ir_edge_t *edge;
475         mips_attr_t     *attr = get_mips_attr(irn);
476
477         /* fill the table structure */
478         tbl.label        = xmalloc(SNPRINTF_BUF_LEN);
479         tbl.label        = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_");
480         tbl.defBlock     = NULL;
481         tbl.num_branches = get_irn_n_edges(irn);
482         tbl.branches     = xcalloc(tbl.num_branches, sizeof(tbl.branches[0]));
483         tbl.min_value    = INT_MAX;
484         tbl.max_value    = INT_MIN;
485
486         i = 0;
487         /* go over all proj's and collect them */
488         foreach_out_edge(irn, edge) {
489                 proj = get_edge_src_irn(edge);
490                 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
491
492                 pn = get_Proj_proj(proj);
493
494                 /* create branch entry */
495                 tbl.branches[i].target = get_irn_link(proj);
496                 tbl.branches[i].value  = pn;
497
498                 tbl.min_value = pn < tbl.min_value ? pn : tbl.min_value;
499                 tbl.max_value = pn > tbl.max_value ? pn : tbl.max_value;
500
501                 i++;
502         }
503
504         /* sort the branches by their number */
505         qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), mips_cmp_branch_t);
506
507         be_emit_string(env->emit, mips_get_jumptbl_label(irn));
508         be_emit_cstring(env->emit, ":\n");
509         be_emit_write_line(env->emit);
510         lastval = tbl.min_value;
511         for(i = 0; i < tbl.num_branches; ++i) {
512                 const branch_t *branch = &tbl.branches[i];
513                 int value = branch->value;
514
515                 for(i2 = lastval + 1; i2 < value; ++i2) {
516                         be_emit_cstring(env->emit, "\t.word ");
517                         be_emit_ident(env->emit, attr->symconst_id);
518                         be_emit_char(env->emit, '\n');
519                         be_emit_write_line(env->emit);
520                 }
521
522                 be_emit_cstring(env->emit, "\t.word ");
523                 mips_emit_block_label(env, branch->target);
524                 be_emit_char(env->emit, '\n');
525                 be_emit_write_line(env->emit);
526
527                 lastval = branch->value;
528         }
529
530         if (tbl.label)
531                 free(tbl.label);
532         if (tbl.branches)
533                 free(tbl.branches);
534 }
535
536 static
537 void dump_jump_tables(ir_node* node, void *data)
538 {
539         mips_emit_env_t *env = data;
540
541         // emit jump tables
542         if(is_mips_SwitchJump(node)) {
543                 be_emit_cstring(env->emit, ".data\n");
544                 be_emit_write_line(env->emit);
545
546                 emit_mips_jump_table(env, node);
547
548                 be_emit_cstring(env->emit, ".text\n");
549                 be_emit_write_line(env->emit);
550         }
551 }
552
553 /***********************************************************************************
554  *                  _          __                                             _
555  *                 (_)        / _|                                           | |
556  *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
557  * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
558  * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
559  * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
560  *
561  ***********************************************************************************/
562
563 static void mips_emit_nothing(mips_emit_env_t *env, const ir_node *node)
564 {
565         (void) env;
566         (void) node;
567 }
568
569 static void mips_emit_this_shouldnt_happen(mips_emit_env_t *env, const ir_node *node)
570 {
571         (void) env;
572         panic("Found non-lowered node %+F while emitting", node);
573 }
574
575 typedef void (*emit_func) (mips_emit_env_t *, const ir_node *);
576
577 static void register_emitter(ir_op *op, emit_func func)
578 {
579         op->ops.generic = (op_func) func;
580 }
581
582 /**
583  * Register emitter functions for mips backend
584  */
585 void mips_register_emitters(void)
586 {
587         /* first clear the generic function pointer for all ops */
588         clear_irp_opcodes_generic_func();
589
590         /* register all emitter functions defined in spec */
591         mips_register_spec_emitters();
592
593         register_emitter(op_be_IncSP, mips_emit_IncSP);
594         register_emitter(op_be_SetSP, mips_emit_this_shouldnt_happen);
595         register_emitter(op_be_AddSP, mips_emit_this_shouldnt_happen);
596         register_emitter(op_be_Call, mips_emit_Call);
597         register_emitter(op_be_Copy, mips_emit_Copy);
598         register_emitter(op_be_Keep, mips_emit_nothing);
599         register_emitter(op_be_Barrier, mips_emit_nothing);
600         register_emitter(op_be_Return, mips_emit_Return);
601         register_emitter(op_be_RegParams, mips_emit_nothing);
602         register_emitter(op_be_Spill, mips_emit_this_shouldnt_happen);
603         register_emitter(op_be_Reload, mips_emit_this_shouldnt_happen);
604         register_emitter(op_be_Perm, mips_emit_Perm);
605
606         register_emitter(op_Start, mips_emit_nothing);
607         register_emitter(op_Proj, mips_emit_nothing);
608         register_emitter(op_SymConst, mips_emit_this_shouldnt_happen);
609         register_emitter(op_Const, mips_emit_this_shouldnt_happen);
610         register_emitter(op_Jmp, mips_emit_Jump);
611         register_emitter(op_Cmp, mips_emit_this_shouldnt_happen);
612         register_emitter(op_Cond, mips_emit_this_shouldnt_happen);
613 }
614
615 /**
616  * Emits assembly for a single node
617  */
618 static void mips_emit_node(mips_emit_env_t *env, const ir_node *node)
619 {
620         ir_op *op = get_irn_op(node);
621
622         if (op->ops.generic) {
623                 emit_func emit = (emit_func) op->ops.generic;
624                 (*emit) (env, node);
625         } else {
626                 panic("No emitter defined for node %+F", node);
627         }
628 }
629
630 /**
631  * Walks over the nodes in a block connected by scheduling edges
632  * and emits code for each node.
633  */
634 void mips_gen_block(mips_emit_env_t *env, ir_node *block)
635 {
636         ir_node *node;
637
638         if (! is_Block(block))
639                 return;
640
641         mips_emit_block_label(env, block);
642         be_emit_cstring(env->emit, ":\n");
643         be_emit_write_line(env->emit);
644
645         sched_foreach(block, node) {
646                 mips_emit_node(env, node);
647         }
648
649         be_emit_char(env->emit, '\n');
650         be_emit_write_line(env->emit);
651 }
652
653 /**
654  * Emits code for function start.
655  */
656 void mips_emit_func_prolog(mips_emit_env_t *env, ir_graph *irg)
657 {
658         ident *irg_ident = get_entity_ident(get_irg_entity(irg));
659         be_emit_env_t *eenv = env->emit;
660
661         // dump jump tables
662         irg_walk_graph(irg, NULL, dump_jump_tables, env);
663
664         be_emit_write_line(eenv);
665         be_gas_emit_switch_section(eenv, GAS_SECTION_TEXT);
666
667         be_emit_cstring(eenv, "\t.balign\t4\n");
668
669         be_emit_cstring(eenv, "\t.global\t")
670         be_emit_ident(eenv, irg_ident);
671         be_emit_char(eenv, '\n');
672
673         be_emit_cstring(eenv, "\t.set\tnomips16\n");
674
675         be_emit_cstring(eenv, "\t.ent\t");
676         be_emit_ident(eenv, irg_ident);
677         be_emit_char(eenv, '\n');
678
679         be_emit_ident(eenv, irg_ident);
680         be_emit_cstring(eenv, ":\n");
681
682         be_emit_cstring(eenv, "\t.frame\t$fp, 24, $ra\n");
683         be_emit_cstring(eenv, "\t.mask\t0xc0000000, -4\n");
684         be_emit_cstring(eenv, "\t.fmask\t0x00000000, 0\n");
685
686         be_emit_write_line(eenv);
687 }
688
689 /**
690  * Emits code for function end
691  */
692 void mips_emit_func_epilog(mips_emit_env_t *env, ir_graph *irg)
693 {
694         ident *irg_ident = get_entity_ident(get_irg_entity(irg));
695
696         be_emit_cstring(env->emit, "\t.end\t");
697         be_emit_ident(env->emit, irg_ident);
698         be_emit_char(env->emit, '\n');
699         be_emit_write_line(env->emit);
700 }
701
702 /**
703  * Sets labels for control flow nodes (jump target)
704  */
705 void mips_gen_labels(ir_node *block, void *env)
706 {
707         ir_node *pred;
708         int n = get_Block_n_cfgpreds(block);
709
710         for (n--; n >= 0; n--) {
711                 pred = get_Block_cfgpred(block, n);
712                 set_irn_link(pred, block);
713         }
714 }
715
716 /**
717  * Main driver
718  */
719 void mips_gen_routine(mips_code_gen_t *cg, ir_graph *irg)
720 {
721         mips_emit_env_t  env;
722         int i, n;
723
724         env.isa      = (mips_isa_t*) cg->arch_env->isa;
725         env.emit     = &env.isa->emit;
726         env.arch_env = cg->arch_env;
727         env.cg       = cg;
728
729         mips_register_emitters();
730
731         irg_block_walk_graph(irg, mips_gen_labels, NULL, &env);
732
733         mips_emit_func_prolog(&env, irg);
734
735         dump_ir_block_graph_sched(irg, "-kaputtelist");
736
737         for (i = 0, n = mips_get_sched_n_blocks(cg); i < n; ++i) {
738                 ir_node *block = mips_get_sched_block(cg, i);
739                 mips_gen_block(&env, block);
740         }
741
742         mips_emit_func_epilog(&env, irg);
743 }
744
745 void mips_init_emitter(void)
746 {
747         FIRM_DBG_REGISTER(dbg, "firm.be.mips.emitter");
748 }