fix mips immediate dumper
[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_load_store_address(mips_emit_env_t *env, const ir_node *node,
233                                   int pos)
234 {
235         const mips_load_store_attr_t *attr = get_mips_load_store_attr_const(node);
236
237         be_emit_irprintf(env->emit, "%d(", attr->offset);
238         mips_emit_source_register(env, node, pos);
239         be_emit_char(env->emit, ')');
240 }
241
242 void mips_emit_immediate_suffix(mips_emit_env_t *env, const ir_node *node,
243                                 int pos)
244 {
245         ir_node *op = get_irn_n(node, pos);
246         if(is_mips_Immediate(op))
247                 be_emit_char(env->emit, 'i');
248 }
249
250 void mips_emit_immediate(mips_emit_env_t *env, const ir_node *node)
251 {
252         const mips_immediate_attr_t *attr = get_mips_immediate_attr_const(node);
253
254         switch(attr->imm_type) {
255         case MIPS_IMM_CONST:
256                 be_emit_irprintf(env->emit, "%d", attr->val);
257                 break;
258         case MIPS_IMM_SYMCONST_LO:
259                 be_emit_cstring(env->emit, "%lo($");
260                 be_emit_ident(env->emit, get_entity_ld_ident(attr->entity));
261                 if(attr->val != 0) {
262                         be_emit_irprintf(env->emit, "%+d", attr->val);
263                 }
264                 be_emit_char(env->emit, ')');
265                 break;
266         case MIPS_IMM_SYMCONST_HI:
267                 be_emit_cstring(env->emit, "%hi($");
268                 be_emit_ident(env->emit, get_entity_ld_ident(attr->entity));
269                 if(attr->val != 0) {
270                         be_emit_irprintf(env->emit, "%+d", attr->val);
271                 }
272                 be_emit_char(env->emit, ')');
273                 break;
274         default:
275                 panic("invalid immediate type found");
276         }
277 }
278
279 /**
280  * Emit the name of the destination register at given output position.
281  */
282 void mips_emit_source_register_or_immediate(mips_emit_env_t *env,
283                                             const ir_node *node, int pos)
284 {
285         const ir_node *op = get_irn_n(node, pos);
286         if(is_mips_Immediate(op)) {
287                 mips_emit_immediate(env, op);
288         } else {
289                 mips_emit_source_register(env, node, pos);
290         }
291 }
292
293 #if 0
294 /*
295  * Add a number to a prefix. This number will not be used a second time.
296  */
297 static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
298 {
299         static unsigned long id = 0;
300         snprintf(buf, buflen, "%s%lu", prefix, ++id);
301         return buf;
302 }
303 #endif
304
305 /************************************************************************/
306 /* ABI Handling                                                         */
307 /************************************************************************/
308
309 static
310 void mips_emit_IncSP(mips_emit_env_t *env, const ir_node *node)
311 {
312         int   offset = be_get_IncSP_offset(node);
313
314         if(offset == 0) {
315                 be_emit_cstring(env->emit, "\t/* omitted IncSP with 0 */");
316                 be_emit_finish_line_gas(env->emit, node);
317                 return;
318         }
319
320         if(offset > 0xffff || offset < -0xffff) {
321                 panic("stackframe > 2^16 bytes not supported yet\n");
322         }
323
324         if(offset > 0) {
325                 be_emit_irprintf(env->emit, "\tsubu $sp, $sp, %d", offset);
326         } else {
327                 be_emit_irprintf(env->emit, "\taddu $sp, $sp, %d", -offset);
328         }
329         be_emit_finish_line_gas(env->emit, node);
330 }
331
332 static void mips_emit_Copy(mips_emit_env_t *env, const ir_node *node)
333 {
334         be_emit_cstring(env->emit, "\tmove ");
335         mips_emit_dest_register(env, node, 0);
336         be_emit_cstring(env->emit, ", ");
337         mips_emit_source_register(env, node, 0);
338         be_emit_finish_line_gas(env->emit, node);
339 }
340
341 static void mips_emit_Return(mips_emit_env_t *env, const ir_node* node)
342 {
343         be_emit_cstring(env->emit, "\tj $ra");
344         be_emit_finish_line_gas(env->emit, node);
345 }
346
347 static __attribute__((unused))
348 void mips_emit_nops(mips_emit_env_t *env, int n)
349 {
350         int i;
351
352         for(i = 0; i < n; ++i) {
353                 be_emit_cstring(env->emit, "\tnop\n");
354                 be_emit_write_line(env->emit);
355         }
356 }
357
358 static void mips_emit_Perm(mips_emit_env_t *env, const ir_node *node)
359 {
360         assert(get_irn_arity(node) == 2);
361
362         be_emit_cstring(env->emit, "\txor ");
363         mips_emit_source_register(env, node, 0);
364         be_emit_cstring(env->emit, ", ");
365         mips_emit_source_register(env, node, 0);
366         be_emit_cstring(env->emit, ", ");
367         mips_emit_source_register(env, node, 1);
368         be_emit_finish_line_gas(env->emit, node);
369
370         /* mips_emit_nops(env, 3); */
371
372         be_emit_cstring(env->emit, "\txor ");
373         mips_emit_source_register(env, node, 1);
374         be_emit_cstring(env->emit, ", ");
375         mips_emit_source_register(env, node, 1);
376         be_emit_cstring(env->emit, ", ");
377         mips_emit_source_register(env, node, 0);
378         be_emit_finish_line_gas(env->emit, node);
379
380         /* mips_emit_nops(env, 3); */
381
382         be_emit_cstring(env->emit, "\txor ");
383         mips_emit_source_register(env, node, 0);
384         be_emit_cstring(env->emit, ", ");
385         mips_emit_source_register(env, node, 0);
386         be_emit_cstring(env->emit, ", ");
387         mips_emit_source_register(env, node, 1);
388         be_emit_finish_line_gas(env->emit, node);
389
390         /* mips_emit_nops(env, 3); */
391 }
392
393 /************************************************************************/
394 /* Calls                                                                */
395 /************************************************************************/
396
397 static void mips_emit_Call(mips_emit_env_t *env, const ir_node *node)
398 {
399         ir_entity *callee;
400
401         be_emit_cstring(env->emit, "\tjal ");
402
403         /* call of immediate value (label) */
404         callee = be_Call_get_entity(node);
405         if(callee != NULL) {
406                 be_emit_ident(env->emit, get_entity_ld_ident(callee));
407         } else {
408                 mips_emit_source_register(env, node, be_pos_Call_ptr);
409         }
410         be_emit_finish_line_gas(env->emit, node);
411 }
412
413 /************************************************************************
414  *      _
415  *     | |_   _ _ __ ___  _ __  ___
416  *  _  | | | | | '_ ` _ \| '_ \/ __|
417  * | |_| | |_| | | | | | | |_) \__ \
418  *  \___/ \__,_|_| |_| |_| .__/|___/
419  *                       |_|
420  ************************************************************************/
421
422 const char* mips_get_block_label(const ir_node* block)
423 {
424         static char buf[64];
425         snprintf(buf, sizeof(buf), "BLOCK_%ld", get_irn_node_nr(block));
426
427         return buf;
428 }
429
430 /**
431  * Emits a block label from the given block.
432  */
433 static
434 void mips_emit_block_label(mips_emit_env_t *env, const ir_node *block)
435 {
436         be_emit_irprintf(env->emit, "BLOCK_%d", get_irn_node_nr(block));
437 }
438
439 static void mips_emit_Jump(mips_emit_env_t *env, const ir_node *node)
440 {
441         const ir_node *block = get_irn_link(node);
442         assert(is_Block(block));
443
444         be_emit_cstring(env->emit, "\tb ");
445         mips_emit_block_label(env, block);
446         be_emit_finish_line_gas(env->emit, node);
447 }
448
449 ir_node *mips_get_jump_block(const ir_node* node, long projn)
450 {
451         const ir_edge_t *oute;
452         for(oute = get_irn_out_edge_first(node); oute != NULL;
453             oute = get_irn_out_edge_next(node, oute)) {
454                 ir_node *proj = get_edge_src_irn(oute);
455                 long n;
456                 assert(is_Proj(proj));
457
458                 n = get_Proj_proj(proj);
459                 if(n == projn)
460                         return get_irn_link(proj);
461         }
462
463         return NULL;
464 }
465
466 void mips_emit_jump_target_proj(mips_emit_env_t *env, const ir_node *node,
467                                 long projn)
468 {
469         ir_node *jumpblock = mips_get_jump_block(node, projn);
470         assert(jumpblock != NULL);
471
472         mips_emit_block_label(env, jumpblock);
473 }
474
475 void mips_emit_jump_target(mips_emit_env_t *env, const ir_node *node)
476 {
477         ir_node *jumpblock = get_irn_link(node);
478         assert(jumpblock != NULL);
479
480         mips_emit_block_label(env, jumpblock);
481 }
482
483 void mips_emit_jump_or_fallthrough(mips_emit_env_t *env, const ir_node *node,
484                                    long pn)
485 {
486         ir_node *jumpblock = mips_get_jump_block(node, pn);
487         assert(jumpblock != NULL);
488
489         /* TODO: use fallthrough when possible */
490         be_emit_cstring(env->emit, "b ");
491         mips_emit_block_label(env, jumpblock);
492 }
493
494 /************************************************************************
495  *  ____          _ _       _         _                                 *
496  * / ___|_      _(_) |_ ___| |__     | |_   _ _ __ ___  _ __            *
497  * \___ \ \ /\ / / | __/ __| '_ \ _  | | | | | '_ ` _ \| '_ \           *
498  *  ___) \ V  V /| | || (__| | | | |_| | |_| | | | | | | |_) |          *
499  * |____/ \_/\_/ |_|\__\___|_| |_|\___/ \__,_|_| |_| |_| .__/           *
500  *                                                     |_|              *
501  *                                                                      *
502  ************************************************************************/
503
504 #if 0
505 /* jump table entry (target and corresponding number) */
506 typedef struct _branch_t {
507         ir_node *target;
508         int      value;
509 } branch_t;
510
511 /* jump table for switch generation */
512 typedef struct _jmp_tbl_t {
513         ir_node  *defBlock;        /**< default target */
514         int       min_value;       /**< smallest switch case */
515         int       max_value;       /**< largest switch case */
516         int       num_branches;    /**< number of jumps */
517         char     *label;           /**< label of the jump table */
518         branch_t *branches;        /**< jump array */
519 } jmp_tbl_t;
520
521 /**
522  * Compare two variables of type branch_t. Used to sort all switch cases
523  */
524 static int mips_cmp_branch_t(const void *a, const void *b)
525 {
526         branch_t *b1 = (branch_t *)a;
527         branch_t *b2 = (branch_t *)b;
528
529         if (b1->value <= b2->value)
530                 return -1;
531         else
532                 return 1;
533 }
534
535 const char* mips_get_jumptbl_label(const ir_node* switchjmp)
536 {
537         static char buf[64];
538         snprintf(buf, sizeof(buf), "__JUMPTBL%ld", get_irn_node_nr(switchjmp));
539
540         return buf;
541 }
542
543 /**
544  * Emits code for a SwitchJmp (creates a jump table if
545  * possible otherwise a cmp-jmp cascade). Stolen from ia32
546  */
547 void emit_mips_jump_table(mips_emit_env_t *env, const ir_node *irn) {
548         int                lastval, i, i2, pn;
549         jmp_tbl_t          tbl;
550         ir_node           *proj;
551         const ir_edge_t   *edge;
552         const mips_attr_t *attr = get_mips_attr_const(irn);
553
554         /* fill the table structure */
555         tbl.label        = xmalloc(SNPRINTF_BUF_LEN);
556         tbl.label        = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_");
557         tbl.defBlock     = NULL;
558         tbl.num_branches = get_irn_n_edges(irn);
559         tbl.branches     = xcalloc(tbl.num_branches, sizeof(tbl.branches[0]));
560         tbl.min_value    = INT_MAX;
561         tbl.max_value    = INT_MIN;
562
563         i = 0;
564         /* go over all proj's and collect them */
565         foreach_out_edge(irn, edge) {
566                 proj = get_edge_src_irn(edge);
567                 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
568
569                 pn = get_Proj_proj(proj);
570
571                 /* create branch entry */
572                 tbl.branches[i].target = get_irn_link(proj);
573                 tbl.branches[i].value  = pn;
574
575                 tbl.min_value = pn < tbl.min_value ? pn : tbl.min_value;
576                 tbl.max_value = pn > tbl.max_value ? pn : tbl.max_value;
577
578                 i++;
579         }
580
581         /* sort the branches by their number */
582         qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), mips_cmp_branch_t);
583
584         be_emit_string(env->emit, mips_get_jumptbl_label(irn));
585         be_emit_cstring(env->emit, ":\n");
586         be_emit_write_line(env->emit);
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                         be_emit_cstring(env->emit, "\t.word ");
594                         be_emit_ident(env->emit, get_entity_ld_ident(attr->symconst));
595                         be_emit_char(env->emit, '\n');
596                         be_emit_write_line(env->emit);
597                 }
598
599                 be_emit_cstring(env->emit, "\t.word ");
600                 mips_emit_block_label(env, branch->target);
601                 be_emit_char(env->emit, '\n');
602                 be_emit_write_line(env->emit);
603
604                 lastval = branch->value;
605         }
606
607         if (tbl.label)
608                 free(tbl.label);
609         if (tbl.branches)
610                 free(tbl.branches);
611 }
612
613 static
614 void dump_jump_tables(ir_node* node, void *data)
615 {
616         mips_emit_env_t *env = data;
617
618         // emit jump tables
619         if(is_mips_SwitchJump(node)) {
620                 be_emit_cstring(env->emit, ".data\n");
621                 be_emit_write_line(env->emit);
622
623                 emit_mips_jump_table(env, node);
624
625                 be_emit_cstring(env->emit, ".text\n");
626                 be_emit_write_line(env->emit);
627         }
628 }
629 #endif
630
631 /***********************************************************************************
632  *                  _          __                                             _
633  *                 (_)        / _|                                           | |
634  *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
635  * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
636  * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
637  * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
638  *
639  ***********************************************************************************/
640
641 static void mips_emit_nothing(mips_emit_env_t *env, const ir_node *node)
642 {
643         (void) env;
644         (void) node;
645 }
646
647 static void mips_emit_this_shouldnt_happen(mips_emit_env_t *env, const ir_node *node)
648 {
649         (void) env;
650         panic("Found non-lowered node %+F while emitting", node);
651 }
652
653 /**
654  * The type of a emitter function.
655  */
656 typedef void (*emit_func) (mips_emit_env_t *, const ir_node *);
657
658 /**
659  * Set a node emitter. Make it a bit more type safe.
660  */
661 static void register_emitter(ir_op *op, emit_func func) {
662         op->ops.generic = (op_func) func;
663 }
664
665 /**
666  * Register emitter functions for mips backend
667  */
668 void mips_register_emitters(void) {
669         /* first clear the generic function pointer for all ops */
670         clear_irp_opcodes_generic_func();
671
672         /* register all emitter functions defined in spec */
673         mips_register_spec_emitters();
674
675         /* benode emitter */
676         register_emitter(op_be_IncSP, mips_emit_IncSP);
677         register_emitter(op_be_SetSP, mips_emit_this_shouldnt_happen);
678         register_emitter(op_be_AddSP, mips_emit_this_shouldnt_happen);
679         register_emitter(op_be_Call, mips_emit_Call);
680         register_emitter(op_be_Copy, mips_emit_Copy);
681         register_emitter(op_be_Keep, mips_emit_nothing);
682         register_emitter(op_be_Barrier, mips_emit_nothing);
683         register_emitter(op_be_Return, mips_emit_Return);
684         register_emitter(op_be_RegParams, mips_emit_nothing);
685         register_emitter(op_be_Spill, mips_emit_this_shouldnt_happen);
686         register_emitter(op_be_Reload, mips_emit_this_shouldnt_happen);
687         register_emitter(op_be_Perm, mips_emit_Perm);
688
689         register_emitter(op_Start, mips_emit_nothing);
690         register_emitter(op_Proj, mips_emit_nothing);
691         register_emitter(op_SymConst, mips_emit_this_shouldnt_happen);
692         register_emitter(op_Const, mips_emit_this_shouldnt_happen);
693         register_emitter(op_Jmp, mips_emit_Jump);
694         register_emitter(op_Cmp, mips_emit_this_shouldnt_happen);
695         register_emitter(op_Cond, mips_emit_this_shouldnt_happen);
696         register_emitter(op_Phi, mips_emit_nothing);
697 }
698
699 /**
700  * Emits assembly for a single node
701  */
702 static void mips_emit_node(mips_emit_env_t *env, const ir_node *node)
703 {
704         ir_op *op = get_irn_op(node);
705
706         if (op->ops.generic) {
707                 emit_func emit = (emit_func) op->ops.generic;
708                 (*emit) (env, node);
709         } else {
710                 panic("No emitter defined for node %+F", node);
711         }
712 }
713
714 /**
715  * Walks over the nodes in a block connected by scheduling edges
716  * and emits code for each node.
717  */
718 void mips_gen_block(mips_emit_env_t *env, ir_node *block)
719 {
720         ir_node *node;
721
722         if (! is_Block(block))
723                 return;
724
725         mips_emit_block_label(env, block);
726         be_emit_cstring(env->emit, ":\n");
727         be_emit_write_line(env->emit);
728
729         sched_foreach(block, node) {
730                 mips_emit_node(env, node);
731         }
732
733         be_emit_char(env->emit, '\n');
734         be_emit_write_line(env->emit);
735 }
736
737 /**
738  * Emits code for function start.
739  */
740 void mips_emit_func_prolog(mips_emit_env_t *env, ir_graph *irg)
741 {
742         ident *irg_ident = get_entity_ld_ident(get_irg_entity(irg));
743         be_emit_env_t *eenv = env->emit;
744
745         // dump jump tables
746         //irg_walk_graph(irg, NULL, dump_jump_tables, env);
747
748         be_emit_write_line(eenv);
749         be_gas_emit_switch_section(eenv, GAS_SECTION_TEXT);
750
751         be_emit_cstring(eenv, "\t.balign\t4\n");
752
753         be_emit_cstring(eenv, "\t.global\t");
754         be_emit_ident(eenv, irg_ident);
755         be_emit_char(eenv, '\n');
756
757         be_emit_cstring(eenv, "\t.set\tnomips16\n");
758
759         be_emit_cstring(eenv, "\t.ent\t");
760         be_emit_ident(eenv, irg_ident);
761         be_emit_char(eenv, '\n');
762
763         be_emit_ident(eenv, irg_ident);
764         be_emit_cstring(eenv, ":\n");
765
766         be_emit_cstring(eenv, "\t.frame\t$fp, 24, $ra\n");
767         be_emit_cstring(eenv, "\t.mask\t0xc0000000, -4\n");
768         be_emit_cstring(eenv, "\t.fmask\t0x00000000, 0\n");
769
770         be_emit_write_line(eenv);
771 }
772
773 /**
774  * Emits code for function end
775  */
776 void mips_emit_func_epilog(mips_emit_env_t *env, ir_graph *irg)
777 {
778         ident *irg_ident = get_entity_ident(get_irg_entity(irg));
779
780         be_emit_cstring(env->emit, "\t.end\t");
781         be_emit_ident(env->emit, irg_ident);
782         be_emit_char(env->emit, '\n');
783         be_emit_write_line(env->emit);
784 }
785
786 /**
787  * Sets labels for control flow nodes (jump target)
788  */
789 void mips_gen_labels(ir_node *block, void *env)
790 {
791         ir_node *pred;
792         int n = get_Block_n_cfgpreds(block);
793         (void) env;
794
795         for (n--; n >= 0; n--) {
796                 pred = get_Block_cfgpred(block, n);
797                 set_irn_link(pred, block);
798         }
799 }
800
801 /**
802  * Main driver
803  */
804 void mips_gen_routine(mips_code_gen_t *cg, ir_graph *irg)
805 {
806         mips_emit_env_t  env;
807         int i, n;
808
809         env.isa      = (mips_isa_t*) cg->arch_env->isa;
810         env.emit     = &env.isa->emit;
811         env.arch_env = cg->arch_env;
812         env.cg       = cg;
813
814         mips_register_emitters();
815
816         irg_block_walk_graph(irg, mips_gen_labels, NULL, &env);
817
818         mips_emit_func_prolog(&env, irg);
819
820         dump_ir_block_graph_sched(irg, "-kaputtelist");
821
822         for (i = 0, n = mips_get_sched_n_blocks(cg); i < n; ++i) {
823                 ir_node *block = mips_get_sched_block(cg, i);
824                 mips_gen_block(&env, block);
825         }
826
827         mips_emit_func_epilog(&env, irg);
828 }
829
830 void mips_init_emitter(void)
831 {
832         FIRM_DBG_REGISTER(dbg, "firm.be.mips.emitter");
833 }