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