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