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