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