used new FIRM_DBG_REGISTER() macro
[libfirm] / ir / be / mips / mips_emitter.c
1 /* mips emitter */
2 /* $Id$ */
3
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
7
8 #include <limits.h>
9
10 #include "xmalloc.h"
11 #include "tv.h"
12 #include "iredges.h"
13 #include "debug.h"
14 #include "irgwalk.h"
15 #include "irprintf.h"
16 #include "irop_t.h"
17 #include "irargs_t.h"
18 #include "irprog_t.h"
19 #include "irouts.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%04X", val & 0xffff);
101                 } else {
102                         unsigned long val = get_tarval_long(attr->tv);
103                         snprintf(buf, sizeof(buf), "0x%04X", 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%04X", val & 0xffff);
113                 } else {
114                         unsigned long val = get_tarval_long(attr->tv);
115                         val = (val & 0xffff0000) >> 16;
116                         snprintf(buf, sizeof(buf), "0x%04X", 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 /**
337  * Returns the target label for a control flow node.
338  */
339 static char *get_cfop_target(const ir_node *irn, char *buf)
340 {
341         ir_node *bl = get_irn_link(irn);
342
343         snprintf(buf, SNPRINTF_BUF_LEN, "BLOCK_%ld", get_irn_node_nr(bl));
344         return buf;
345 }
346
347 /************************************************************************/
348 /* ABI Handling
349 /************************************************************************/
350
351 static void mips_emit_IncSP(const ir_node *node, mips_emit_env_t *env)
352 {
353         FILE *F = env->out;
354         int offset = be_get_IncSP_offset(node);
355         if(offset == 0)
356                 return;
357
358         if(be_get_IncSP_direction(node) != be_stack_dir_expand)
359                 offset = -offset;
360
361         fprintf(F, "\taddi $sp, $sp, %d\n", -offset);
362 }
363
364 static void mips_emit_Copy(const ir_node *node, mips_emit_env_t *env)
365 {
366         FILE *F = env->out;
367
368         lc_efprintf(mips_get_arg_env(), F, "\tor %1D, $zero, %1S\t\t\t# copy\n", node, node);
369 }
370
371 static void mips_emit_Return(const ir_node* node, mips_emit_env_t *env)
372 {
373         FILE *F = env->out;
374         fprintf(F, "\tj $ra\t\t\t\t# return\n");
375 }
376
377 static void mips_emit_nops(FILE* F, int n)
378 {
379         int i;
380
381         for(i = 0; i < n; ++i) {
382                 fprintf(F, "\tnop\n");
383         }
384 }
385
386 static void mips_emit_Perm(const ir_node *node, mips_emit_env_t *env)
387 {
388         FILE* F = env->out;
389
390         assert(/*get_irn_n_outs(node) == 2 &&*/ get_irn_arity(node) == 2);
391
392         lc_efprintf(mips_get_arg_env(), F, "\txor %1S, %1S, %2S\t\t\t# perm\n", node, node, node);
393         mips_emit_nops(F, 3);
394         lc_efprintf(mips_get_arg_env(), F, "\txor %2S, %2S, %1S\n", node, node, node);
395         mips_emit_nops(F, 3);
396         lc_efprintf(mips_get_arg_env(), F, "\txor %1S, %1S, %2S\n", node, node, node);
397         mips_emit_nops(F, 3);
398 }
399
400 static void mips_emit_Spill(const ir_node* node, mips_emit_env_t *env)
401 {
402         FILE* F = env->out;
403
404         ir_node* context = be_get_Spill_context(node);
405         entity* ent = be_get_spill_entity(node);
406         lc_efprintf(mips_get_arg_env(), F, "\tsw %1S, %d($fp)\n", node, get_entity_offset_bytes(ent));
407 }
408
409 static void mips_emit_Reload(const ir_node* node, mips_emit_env_t *env)
410 {
411         FILE* F = env->out;
412
413         entity* ent = be_get_spill_entity(node);
414         lc_efprintf(mips_get_arg_env(), F, "\tlw %1D, %d($fp)\n", node, get_entity_offset_bytes(ent));
415 }
416
417 /************************************************************************/
418 /* Calls
419 /************************************************************************/
420
421 static void mips_emit_Call(ir_node *node, mips_emit_env_t *env)
422 {
423         FILE *F = env->out;
424         const arch_register_t *callee_reg;
425
426         // call to imediate value (label)
427         entity *callee = be_Call_get_entity(node);
428         if(callee != NULL) {
429                 fprintf(F, "\tjal %s\n", get_entity_name(callee));
430                 return;
431         }
432
433         // call to function pointer
434         callee_reg = get_in_reg(node, be_pos_Call_ptr);
435         assert(callee_reg != NULL);
436
437         fprintf(F, "\tjal %s\n", arch_register_get_name(callee_reg));
438 }
439
440 /************************************************************************
441  *      _
442  *     | |_   _ _ __ ___  _ __  ___
443  *  _  | | | | | '_ ` _ \| '_ \/ __|
444  * | |_| | |_| | | | | | | |_) \__ \
445  *  \___/ \__,_|_| |_| |_| .__/|___/
446  *                       |_|
447  ************************************************************************/
448
449 const char* mips_get_block_label(const ir_node* block)
450 {
451         static char buf[64];
452         snprintf(buf, sizeof(buf), "BLOCK_%ld", get_irn_node_nr(block));
453
454         return buf;
455 }
456
457 static void mips_emit_Jump(ir_node *node, mips_emit_env_t *env)
458 {
459         FILE *F = env->out;
460         const ir_node *block = get_irn_link(node);
461
462         assert(is_Block(block));
463
464         fprintf(F, "\tb %s\n", mips_get_block_label(block));
465 }
466
467 ir_node *mips_get_jump_block(const ir_node* node, int projn)
468 {
469         const ir_edge_t *oute;
470         for(oute = get_irn_out_edge_first(node); oute != NULL;
471             oute = get_irn_out_edge_next(node, oute)) {
472                 ir_node *proj = get_edge_src_irn(oute);
473                 long n;
474                 assert(is_Proj(proj));
475
476                 n = get_Proj_proj(proj);
477                 if(n == projn)
478                         return get_irn_link(proj);
479         }
480
481         return NULL;
482 }
483
484 /************************************************************************
485  *  ____          _ _       _         _                                                                 *
486  * / ___|_      _(_) |_ ___| |__     | |_   _ _ __ ___  _ __                    *
487  * \___ \ \ /\ / / | __/ __| '_ \ _  | | | | | '_ ` _ \| '_ \                   *
488  *  ___) \ V  V /| | || (__| | | | |_| | |_| | | | | | | |_) |                  *
489  * |____/ \_/\_/ |_|\__\___|_| |_|\___/ \__,_|_| |_| |_| .__/                   *
490  *                                                     |_|                              *
491  *                                                                      *
492  ************************************************************************/
493
494 /* jump table entry (target and corresponding number) */
495 typedef struct _branch_t {
496         ir_node *target;
497         int      value;
498 } branch_t;
499
500 /* jump table for switch generation */
501 typedef struct _jmp_tbl_t {
502         ir_node  *defBlock;        /**< default target */
503         int       min_value;       /**< smallest switch case */
504         int       max_value;       /**< largest switch case */
505         int       num_branches;    /**< number of jumps */
506         char     *label;           /**< label of the jump table */
507         branch_t *branches;        /**< jump array */
508 } jmp_tbl_t;
509
510 /**
511  * Compare two variables of type branch_t. Used to sort all switch cases
512  */
513 static int mips_cmp_branch_t(const void *a, const void *b) {
514         branch_t *b1 = (branch_t *)a;
515         branch_t *b2 = (branch_t *)b;
516
517         if (b1->value <= b2->value)
518                 return -1;
519         else
520                 return 1;
521 }
522
523 const char* mips_get_jumptbl_label(const ir_node* switchjmp)
524 {
525         static char buf[64];
526         snprintf(buf, sizeof(buf), "__JUMPTBL%ld", get_irn_node_nr(switchjmp));
527
528         return buf;
529 }
530
531 /**
532  * Emits code for a SwitchJmp (creates a jump table if
533  * possible otherwise a cmp-jmp cascade). Stolen from ia32
534  */
535 void emit_mips_jump_table(const ir_node *irn, FILE* F) {
536         int                 lastval, i, pn, do_jmp_tbl = 1;
537         jmp_tbl_t           tbl;
538         ir_node            *proj;
539         const ir_edge_t    *edge;
540         const lc_arg_env_t *env = mips_get_arg_env();
541         mips_attr_t *attr;
542         int i2;
543
544         attr = get_mips_attr(irn);
545
546         /* fill the table structure */
547         tbl.label        = xmalloc(SNPRINTF_BUF_LEN);
548         tbl.label        = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_");
549         tbl.defBlock     = NULL;
550         tbl.num_branches = get_irn_n_edges(irn);
551         tbl.branches     = xcalloc(tbl.num_branches, sizeof(tbl.branches[0]));
552         tbl.min_value    = INT_MAX;
553         tbl.max_value    = INT_MIN;
554
555         i = 0;
556         /* go over all proj's and collect them */
557         foreach_out_edge(irn, edge) {
558                 proj = get_edge_src_irn(edge);
559                 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
560
561                 pn = get_Proj_proj(proj);
562
563                 /* create branch entry */
564                 tbl.branches[i].target = get_irn_link(proj);
565                 tbl.branches[i].value  = pn;
566
567                 tbl.min_value = pn < tbl.min_value ? pn : tbl.min_value;
568                 tbl.max_value = pn > tbl.max_value ? pn : tbl.max_value;
569
570                 i++;
571         }
572
573         /* sort the branches by their number */
574         qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), mips_cmp_branch_t);
575
576         fprintf(F, "%s:\n", mips_get_jumptbl_label(irn));
577         lastval = tbl.min_value;
578         for(i = 0; i < tbl.num_branches; ++i) {
579                 const branch_t *branch = &tbl.branches[i];
580                 int value = branch->value;
581
582                 for(i2 = lastval + 1; i2 < value; ++i2) {
583                         fprintf(F, "\t.word %s\n", get_id_str(attr->symconst_id));
584                 }
585
586                 fprintf(F, "\t.word %s\n", mips_get_block_label(branch->target));
587                 lastval = branch->value;
588         }
589
590         if (tbl.label)
591                 free(tbl.label);
592         if (tbl.branches)
593                 free(tbl.branches);
594 }
595
596 static void dump_jump_tables(ir_node* node, void *env)
597 {
598         FILE* F = (FILE*) env;
599
600         // emit jump tables
601         if(is_mips_SwitchJump(node)) {
602                 fprintf(F, ".data\n");
603                 emit_mips_jump_table(node, F);
604                 fprintf(F, ".text\n");
605         }
606 }
607
608 /***********************************************************************************
609  *                  _          __                                             _
610  *                 (_)        / _|                                           | |
611  *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
612  * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
613  * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
614  * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
615  *
616  ***********************************************************************************/
617
618 static void mips_emit_nothing(ir_mode *mode, mips_emit_env_t *env)
619 {
620 }
621
622 static void mips_emit_this_shouldnt_happen(ir_mode *mode, mips_emit_env_t *env)
623 {
624         assert(0);
625 }
626
627 /**
628  * Register emitter functions for mips backend
629  */
630 void mips_register_emitters(void)
631 {
632         /* first clear the generic function pointer for all ops */
633         clear_irp_opcodes_generic_func();
634
635         /* register all emitter functions defined in spec */
636         mips_register_spec_emitters();
637
638         /* benode emitter */
639         op_be_IncSP->ops.generic = (op_func) mips_emit_IncSP;
640         op_be_SetSP->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
641         op_be_AddSP->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
642         op_be_Call->ops.generic = (op_func) mips_emit_Call;
643         op_be_Keep->ops.generic = (op_func) mips_emit_nothing;
644         op_be_Copy->ops.generic = (op_func) mips_emit_Copy;
645         op_be_Return->ops.generic = (op_func) mips_emit_Return;
646         op_be_RegParams->ops.generic = (op_func) mips_emit_nothing;
647         op_be_Spill->ops.generic = (op_func) mips_emit_Spill;
648         op_be_Reload->ops.generic = (op_func) mips_emit_Reload;
649
650         op_Start->ops.generic = (op_func) mips_emit_nothing;
651         op_Proj->ops.generic = (op_func) mips_emit_nothing;
652         op_SymConst->ops.generic = (op_func) mips_emit_nothing;
653         op_Jmp->ops.generic = (op_func) mips_emit_Jump;
654         op_Cmp->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
655         op_Cond->ops.generic = (op_func) mips_emit_this_shouldnt_happen;
656 }
657
658 typedef void (*emit_func) (const ir_node *, mips_emit_env_t *);
659
660 /**
661  * Emits assembly for a single node
662  */
663 static void mips_emit_node(ir_node *irn, mips_emit_env_t* env)
664 {
665         mips_emit_env_t        *emit_env = env;
666         firm_dbg_module_t *mod      = emit_env->mod;
667         FILE              *F        = emit_env->out;
668         ir_op             *op       = get_irn_op(irn);
669
670         DBG((mod, LEVEL_1, "emitting code for %+F\n", irn));
671
672         if (op->ops.generic) {
673                 emit_func emit = (emit_func) op->ops.generic;
674                 (*emit) (irn, env);
675
676 #if 0
677                 if(emit != (emit_func) mips_emit_nothing)
678                         mips_emit_nops(F, 5);
679 #endif
680         } else {
681                 ir_fprintf(F, "\t\t\t\t\t# %+F\n", irn);
682         }
683 }
684
685 /**
686  * Walks over the nodes in a block connected by scheduling edges
687  * and emits code for each node.
688  */
689 void mips_gen_block(ir_node *block, void *env)
690 {
691         FILE *F = ((mips_emit_env_t *)env)->out;
692         ir_node *irn;
693
694         if (! is_Block(block))
695                 return;
696
697         fprintf(F, "%s:\n", mips_get_block_label(block));
698         sched_foreach(block, irn) {
699                 mips_emit_node(irn, env);
700         }
701         fprintf(F, "\n");
702 }
703
704 /**
705  * Emits code for function start.
706  */
707 void mips_emit_start(FILE *F, ir_graph *irg)
708 {
709         const char *irg_name = get_entity_name(get_irg_entity(irg));
710
711         // dump jump tables
712         irg_walk_graph(irg, NULL, dump_jump_tables, F);
713
714         fprintf(F, "\n\n");
715         fprintf(F, "# Function Start of %s\n", irg_name);
716         fprintf(F, "%s:\n", irg_name);
717 }
718
719 /**
720  * Emits code for function end
721  */
722 void mips_emit_end(FILE *F, ir_graph *irg)
723 {
724         const char *irg_name = get_entity_name(get_irg_entity(irg));
725
726         fprintf(F, "# End of function %s we should never get here...\n", irg_name);
727         fprintf(F, "\tjal exit\n");
728 }
729
730 /**
731  * Sets labels for control flow nodes (jump target)
732  * TODO: Jump optimization
733  */
734 void mips_gen_labels(ir_node *block, void *env)
735 {
736         ir_node *pred;
737         int n = get_Block_n_cfgpreds(block);
738
739         for (n--; n >= 0; n--) {
740                 pred = get_Block_cfgpred(block, n);
741                 set_irn_link(pred, block);
742         }
743 }
744
745 /**
746  * Main driver
747  */
748 void mips_gen_routine(FILE *F, ir_graph *irg, const mips_code_gen_t *cg)
749 {
750         mips_emit_env_t emit_env;
751         int i, n;
752
753         emit_env.out      = F;
754         emit_env.arch_env = cg->arch_env;
755         emit_env.cg       = cg;
756         FIRM_DBG_REGISTER(emit_env.mod, "firm.be.mips.emit");
757
758         /* set the global arch_env (needed by print hooks) */
759         arch_env = cg->arch_env;
760
761         irg_block_walk_graph(irg, mips_gen_labels, NULL, &emit_env);
762         mips_emit_start(F, irg);
763 //      irg_walk_blkwise_graph(irg, NULL, mips_gen_block, &emit_env);
764
765         dump_ir_block_graph_sched(irg, "-kaputtelist");
766
767         for (i = 0, n = mips_get_sched_n_blocks(cg); i < n; ++i) {
768                 ir_node *block = mips_get_sched_block(cg, i);
769                 mips_gen_block(block, &emit_env);
770         }
771
772         mips_emit_end(F, irg);
773 }