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