Remove redundant be_set_transformed_node() in transformer functions. They are vestig...
[libfirm] / ir / be / mips / mips_emitter.c
1 /*
2  * Copyright (C) 1995-2008 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 static const mips_isa_t      *isa;
62 static const arch_env_t      *arch_env;
63 static const mips_code_gen_t *cg;
64
65 /**
66  * Returns the register at in position pos.
67  */
68 static const arch_register_t *get_in_reg(const ir_node *node, int pos)
69 {
70         ir_node                *op;
71         const arch_register_t  *reg = NULL;
72
73         assert(get_irn_arity(node) > pos && "Invalid IN position");
74
75         /* The out register of the operator at position pos is the
76            in register we need. */
77         op = get_irn_n(node, pos);
78
79         reg = arch_get_irn_register(arch_env, op);
80
81         assert(reg && "no in register found");
82         return reg;
83 }
84
85 /**
86  * Returns the register at out position pos.
87  */
88 static const arch_register_t *get_out_reg(const ir_node *node, int pos)
89 {
90         ir_node                *proj;
91         const arch_register_t  *reg = NULL;
92
93         /* 1st case: irn is not of mode_T, so it has only                 */
94         /*           one OUT register -> good                             */
95         /* 2nd case: irn is of mode_T -> collect all Projs and ask the    */
96         /*           Proj with the corresponding projnum for the register */
97
98         if (get_irn_mode(node) != mode_T) {
99                 reg = arch_get_irn_register(arch_env, node);
100         } else if (is_mips_irn(node)) {
101                 reg = get_mips_out_reg(node, pos);
102         } else {
103                 const ir_edge_t *edge;
104
105                 foreach_out_edge(node, edge) {
106                         proj = get_edge_src_irn(edge);
107                         assert(is_Proj(proj) && "non-Proj from mode_T node");
108                         if (get_Proj_proj(proj) == pos) {
109                                 reg = arch_get_irn_register(arch_env, proj);
110                                 break;
111                         }
112                 }
113         }
114
115         assert(reg && "no out register found");
116         return reg;
117 }
118
119 /*************************************************************
120  *             _       _    __   _          _
121  *            (_)     | |  / _| | |        | |
122  *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
123  * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
124  * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
125  * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
126  * | |                                       | |
127  * |_|                                       |_|
128  *************************************************************/
129
130 /**
131  * Emit the name of the source register at given input position.
132  */
133 void mips_emit_source_register(const ir_node *node, int pos)
134 {
135         const arch_register_t *reg = get_in_reg(node, pos);
136         be_emit_char('$');
137         be_emit_string(arch_register_get_name(reg));
138 }
139
140 /**
141  * Emit the name of the destination register at given output position.
142  */
143 void mips_emit_dest_register(const ir_node *node, int pos)
144 {
145         const arch_register_t *reg = get_out_reg(node, pos);
146         be_emit_char('$');
147         be_emit_string(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                 panic("Unsupported SymConst kind");
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(const ir_node *node, int pos)
235 {
236         const mips_load_store_attr_t *attr = get_mips_load_store_attr_const(node);
237
238         be_emit_irprintf("%d(", attr->offset);
239         mips_emit_source_register(node, pos);
240         be_emit_char(')');
241 }
242
243 void mips_emit_immediate_suffix(const ir_node *node, int pos)
244 {
245         ir_node *op = get_irn_n(node, pos);
246         if(is_mips_Immediate(op))
247                 be_emit_char('i');
248 }
249
250 void mips_emit_immediate(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("%d", attr->val);
257                 break;
258         case MIPS_IMM_SYMCONST_LO:
259                 be_emit_cstring("%lo($");
260                 be_emit_ident(get_entity_ld_ident(attr->entity));
261                 if(attr->val != 0) {
262                         be_emit_irprintf("%+d", attr->val);
263                 }
264                 be_emit_char(')');
265                 break;
266         case MIPS_IMM_SYMCONST_HI:
267                 be_emit_cstring("%hi($");
268                 be_emit_ident(get_entity_ld_ident(attr->entity));
269                 if(attr->val != 0) {
270                         be_emit_irprintf("%+d", attr->val);
271                 }
272                 be_emit_char(')');
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(const ir_node *node, int pos)
283 {
284         const ir_node *op = get_irn_n(node, pos);
285         if(is_mips_Immediate(op)) {
286                 mips_emit_immediate(op);
287         } else {
288                 mips_emit_source_register(node, pos);
289         }
290 }
291
292 #if 0
293 /*
294  * Add a number to a prefix. This number will not be used a second time.
295  */
296 static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
297 {
298         static unsigned long id = 0;
299         snprintf(buf, buflen, "%s%lu", prefix, ++id);
300         return buf;
301 }
302 #endif
303
304 /************************************************************************/
305 /* ABI Handling                                                         */
306 /************************************************************************/
307
308 static
309 void mips_emit_IncSP(const ir_node *node)
310 {
311         int   offset = be_get_IncSP_offset(node);
312
313         if(offset == 0) {
314                 return;
315         }
316
317         if(offset > 0xffff || offset < -0xffff) {
318                 panic("stackframe > 2^16 bytes not supported yet");
319         }
320
321         if(offset > 0) {
322                 be_emit_irprintf("\tsubu $sp, $sp, %d", offset);
323         } else {
324                 be_emit_irprintf("\taddu $sp, $sp, %d", -offset);
325         }
326         be_emit_finish_line_gas(node);
327 }
328
329 static void mips_emit_Copy(const ir_node *node)
330 {
331         be_emit_cstring("\tmove ");
332         mips_emit_dest_register(node, 0);
333         be_emit_cstring(", ");
334         mips_emit_source_register(node, 0);
335         be_emit_finish_line_gas(node);
336 }
337
338 static void mips_emit_Return(const ir_node* node)
339 {
340         be_emit_cstring("\tj $ra");
341         be_emit_finish_line_gas(node);
342 }
343
344 static __attribute__((unused))
345 void mips_emit_nops(int n)
346 {
347         int i;
348
349         for(i = 0; i < n; ++i) {
350                 be_emit_cstring("\tnop\n");
351                 be_emit_write_line();
352         }
353 }
354
355 static void mips_emit_Perm(const ir_node *node)
356 {
357         assert(get_irn_arity(node) == 2);
358
359         be_emit_cstring("\txor ");
360         mips_emit_source_register(node, 0);
361         be_emit_cstring(", ");
362         mips_emit_source_register(node, 0);
363         be_emit_cstring(", ");
364         mips_emit_source_register(node, 1);
365         be_emit_finish_line_gas(node);
366
367         /* mips_emit_nops(3); */
368
369         be_emit_cstring("\txor ");
370         mips_emit_source_register(node, 1);
371         be_emit_cstring(", ");
372         mips_emit_source_register(node, 1);
373         be_emit_cstring(", ");
374         mips_emit_source_register(node, 0);
375         be_emit_finish_line_gas(node);
376
377         /* mips_emit_nops(3); */
378
379         be_emit_cstring("\txor ");
380         mips_emit_source_register(node, 0);
381         be_emit_cstring(", ");
382         mips_emit_source_register(node, 0);
383         be_emit_cstring(", ");
384         mips_emit_source_register(node, 1);
385         be_emit_finish_line_gas(node);
386
387         /* mips_emit_nops(3); */
388 }
389
390 /************************************************************************/
391 /* Calls                                                                */
392 /************************************************************************/
393
394 static void mips_emit_Call(const ir_node *node)
395 {
396         ir_entity *callee;
397
398         be_emit_cstring("\tjal ");
399
400         /* call of immediate value (label) */
401         callee = be_Call_get_entity(node);
402         if(callee != NULL) {
403                 be_emit_ident(get_entity_ld_ident(callee));
404         } else {
405                 mips_emit_source_register(node, be_pos_Call_ptr);
406         }
407         be_emit_finish_line_gas(node);
408 }
409
410 /************************************************************************
411  *      _
412  *     | |_   _ _ __ ___  _ __  ___
413  *  _  | | | | | '_ ` _ \| '_ \/ __|
414  * | |_| | |_| | | | | | | |_) \__ \
415  *  \___/ \__,_|_| |_| |_| .__/|___/
416  *                       |_|
417  ************************************************************************/
418
419 const char* mips_get_block_label(const ir_node* block)
420 {
421         static char buf[64];
422         snprintf(buf, sizeof(buf), "BLOCK_%ld", get_irn_node_nr(block));
423
424         return buf;
425 }
426
427 /**
428  * Emits a block label from the given block.
429  */
430 static void mips_emit_block_label(const ir_node *block)
431 {
432         if (has_Block_label(block)) {
433                 be_emit_string(be_gas_block_label_prefix());
434                 be_emit_irprintf("%lu", get_Block_label(block));
435         } else {
436                 be_emit_cstring(BLOCK_PREFIX);
437                 be_emit_irprintf("%ld", get_irn_node_nr(block));
438
439         }
440 }
441
442 static void mips_emit_Jump(const ir_node *node)
443 {
444         const ir_node *block = get_irn_link(node);
445         assert(is_Block(block));
446
447         be_emit_cstring("\tb ");
448         mips_emit_block_label(block);
449         be_emit_finish_line_gas(node);
450 }
451
452 ir_node *mips_get_jump_block(const ir_node* node, long projn)
453 {
454         const ir_edge_t *oute;
455         for(oute = get_irn_out_edge_first(node); oute != NULL;
456             oute = get_irn_out_edge_next(node, oute)) {
457                 ir_node *proj = get_edge_src_irn(oute);
458                 long n;
459                 assert(is_Proj(proj));
460
461                 n = get_Proj_proj(proj);
462                 if(n == projn)
463                         return get_irn_link(proj);
464         }
465
466         return NULL;
467 }
468
469 void mips_emit_jump_target_proj(const ir_node *node, long projn)
470 {
471         ir_node *jumpblock = mips_get_jump_block(node, projn);
472         assert(jumpblock != NULL);
473
474         mips_emit_block_label(jumpblock);
475 }
476
477 void mips_emit_jump_target(const ir_node *node)
478 {
479         ir_node *jumpblock = get_irn_link(node);
480         assert(jumpblock != NULL);
481
482         mips_emit_block_label(jumpblock);
483 }
484
485 void mips_emit_jump_or_fallthrough(const ir_node *node, long pn)
486 {
487         ir_node *jumpblock = mips_get_jump_block(node, pn);
488         assert(jumpblock != NULL);
489
490         /* TODO: use fallthrough when possible */
491         be_emit_cstring("b ");
492         mips_emit_block_label(jumpblock);
493 }
494
495 /************************************************************************
496  *  ____          _ _       _         _                                 *
497  * / ___|_      _(_) |_ ___| |__     | |_   _ _ __ ___  _ __            *
498  * \___ \ \ /\ / / | __/ __| '_ \ _  | | | | | '_ ` _ \| '_ \           *
499  *  ___) \ V  V /| | || (__| | | | |_| | |_| | | | | | | |_) |          *
500  * |____/ \_/\_/ |_|\__\___|_| |_|\___/ \__,_|_| |_| |_| .__/           *
501  *                                                     |_|              *
502  *                                                                      *
503  ************************************************************************/
504
505 #if 0
506 /* jump table entry (target and corresponding number) */
507 typedef struct _branch_t {
508         ir_node *target;
509         int      value;
510 } branch_t;
511
512 /* jump table for switch generation */
513 typedef struct _jmp_tbl_t {
514         ir_node  *defBlock;        /**< default target */
515         int       min_value;       /**< smallest switch case */
516         int       max_value;       /**< largest switch case */
517         int       num_branches;    /**< number of jumps */
518         char     *label;           /**< label of the jump table */
519         branch_t *branches;        /**< jump array */
520 } jmp_tbl_t;
521
522 /**
523  * Compare two variables of type branch_t. Used to sort all switch cases
524  */
525 static int mips_cmp_branch_t(const void *a, const void *b)
526 {
527         branch_t *b1 = (branch_t *)a;
528         branch_t *b2 = (branch_t *)b;
529
530         if (b1->value <= b2->value)
531                 return -1;
532         else
533                 return 1;
534 }
535
536 const char* mips_get_jumptbl_label(const ir_node* switchjmp)
537 {
538         static char buf[64];
539         snprintf(buf, sizeof(buf), "__JUMPTBL%ld", get_irn_node_nr(switchjmp));
540
541         return buf;
542 }
543
544 /**
545  * Emits code for a SwitchJmp (creates a jump table if
546  * possible otherwise a cmp-jmp cascade). Stolen from ia32
547  */
548 void emit_mips_jump_table(const ir_node *irn)
549 {
550         int                lastval, i, i2, pn;
551         jmp_tbl_t          tbl;
552         ir_node           *proj;
553         const ir_edge_t   *edge;
554         const mips_attr_t *attr = get_mips_attr_const(irn);
555
556         /* fill the table structure */
557         tbl.label        = XMALLOCN(char, 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     = XMALLOCNZ(branch_t, tbl.num_branches);
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         be_emit_string(mips_get_jumptbl_label(irn));
587         be_emit_cstring(":\n");
588         be_emit_write_line();
589         lastval = tbl.min_value;
590         for(i = 0; i < tbl.num_branches; ++i) {
591                 const branch_t *branch = &tbl.branches[i];
592                 int value = branch->value;
593
594                 for(i2 = lastval + 1; i2 < value; ++i2) {
595                         be_emit_cstring("\t.word ");
596                         be_emit_ident(get_entity_ld_ident(attr->symconst));
597                         be_emit_char('\n');
598                         be_emit_write_line();
599                 }
600
601                 be_emit_cstring("\t.word ");
602                 mips_emit_block_label(branch->target);
603                 be_emit_char('\n');
604                 be_emit_write_line();
605
606                 lastval = branch->value;
607         }
608
609         if (tbl.label)
610                 free(tbl.label);
611         if (tbl.branches)
612                 free(tbl.branches);
613 }
614
615 static void dump_jump_tables(ir_node* node, void *data)
616 {
617         (void) data;
618
619         // emit jump tables
620         if(is_mips_SwitchJump(node)) {
621                 be_emit_cstring(".data\n");
622                 be_emit_write_line();
623
624                 emit_mips_jump_table(node);
625
626                 be_emit_cstring(".text\n");
627                 be_emit_write_line();
628         }
629 }
630 #endif
631
632 /***********************************************************************************
633  *                  _          __                                             _
634  *                 (_)        / _|                                           | |
635  *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
636  * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
637  * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
638  * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
639  *
640  ***********************************************************************************/
641
642 static void mips_emit_nothing(const ir_node *node)
643 {
644         (void) node;
645 }
646
647 static void mips_emit_this_shouldnt_happen(const ir_node *node)
648 {
649         panic("Found non-lowered node %+F while emitting", node);
650 }
651
652 /**
653  * The type of a emitter function.
654  */
655 typedef void (*emit_func) (const ir_node *);
656
657 /**
658  * Set a node emitter. Make it a bit more type safe.
659  */
660 static void register_emitter(ir_op *op, emit_func func)
661 {
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 {
670         /* first clear the generic function pointer for all ops */
671         clear_irp_opcodes_generic_func();
672
673         /* register all emitter functions defined in spec */
674         mips_register_spec_emitters();
675
676         /* benode emitter */
677         register_emitter(op_be_IncSP, mips_emit_IncSP);
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(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) (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(const ir_node *block)
719 {
720         ir_node *node;
721
722         if (! is_Block(block))
723                 return;
724
725         mips_emit_block_label(block);
726         be_emit_cstring(":\n");
727         be_emit_write_line();
728
729         sched_foreach(block, node) {
730                 mips_emit_node(node);
731         }
732
733         be_emit_char('\n');
734         be_emit_write_line();
735 }
736
737 /**
738  * Emits code for function start.
739  */
740 void mips_emit_func_prolog(ir_graph *irg)
741 {
742         ident *irg_ident = get_entity_ld_ident(get_irg_entity(irg));
743
744         // dump jump tables
745         //irg_walk_graph(irg, NULL, dump_jump_tables, env);
746
747         be_emit_write_line();
748         be_gas_emit_switch_section(GAS_SECTION_TEXT);
749
750         be_emit_cstring("\t.balign\t4\n");
751
752         be_emit_cstring("\t.global\t");
753         be_emit_ident(irg_ident);
754         be_emit_char('\n');
755
756         be_emit_cstring("\t.set\tnomips16\n");
757
758         be_emit_cstring("\t.ent\t");
759         be_emit_ident(irg_ident);
760         be_emit_char('\n');
761
762         be_emit_ident(irg_ident);
763         be_emit_cstring(":\n");
764
765         be_emit_cstring("\t.frame\t$fp, 24, $ra\n");
766         be_emit_cstring("\t.mask\t0xc0000000, -4\n");
767         be_emit_cstring("\t.fmask\t0x00000000, 0\n");
768
769         be_emit_write_line();
770 }
771
772 /**
773  * Emits code for function end
774  */
775 void mips_emit_func_epilog(ir_graph *irg)
776 {
777         ident *irg_ident = get_entity_ident(get_irg_entity(irg));
778
779         be_emit_cstring("\t.end\t");
780         be_emit_ident(irg_ident);
781         be_emit_char('\n');
782         be_emit_write_line();
783 }
784
785 /**
786  * Sets labels for control flow nodes (jump target)
787  */
788 void mips_gen_labels(ir_node *block, void *env)
789 {
790         ir_node *pred;
791         int n = get_Block_n_cfgpreds(block);
792         (void) env;
793
794         for (n--; n >= 0; n--) {
795                 pred = get_Block_cfgpred(block, n);
796                 set_irn_link(pred, block);
797         }
798 }
799
800 /**
801  * Main driver
802  */
803 void mips_gen_routine(mips_code_gen_t *mips_cg, ir_graph *irg)
804 {
805         int i, n;
806
807         cg       = mips_cg;
808         isa      = (const mips_isa_t*) cg->arch_env;
809         arch_env = cg->arch_env;
810
811         mips_register_emitters();
812
813         irg_block_walk_graph(irg, mips_gen_labels, NULL, NULL);
814
815         mips_emit_func_prolog(irg);
816
817         n = ARR_LEN(cg->block_schedule);
818         for (i = 0; i < n; ++i) {
819                 ir_node *block = cg->block_schedule[i];
820                 mips_gen_block(block);
821         }
822
823         mips_emit_func_epilog(irg);
824 }
825
826 void mips_init_emitter(void)
827 {
828         FIRM_DBG_REGISTER(dbg, "firm.be.mips.emitter");
829 }