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