2 * Copyright (C) 1995-2008 University of Karlsruhe. All right reserved.
4 * This file is part of libFirm.
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.
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.
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
22 * @brief implementation of mips assembly emitter
23 * @author Matthias Braun, Mehdi
42 #include "../besched.h"
43 #include "../benode.h"
44 #include "../beutil.h"
45 #include "../begnuas.h"
47 #include "mips_emitter.h"
48 #include "gen_mips_emitter.h"
49 #include "mips_nodes_attr.h"
50 #include "mips_new_nodes.h"
51 #include "mips_map_regs.h"
53 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
55 #define SNPRINTF_BUF_LEN 128
58 * Returns the register at in position pos.
60 static const arch_register_t *get_in_reg(const ir_node *node, int pos)
63 const arch_register_t *reg = NULL;
65 assert(get_irn_arity(node) > pos && "Invalid IN position");
67 /* The out register of the operator at position pos is the
68 in register we need. */
69 op = get_irn_n(node, pos);
71 reg = arch_get_irn_register(op);
73 assert(reg && "no in register found");
78 * Returns the register at out position pos.
80 static const arch_register_t *get_out_reg(const ir_node *node, int pos)
83 const arch_register_t *reg = NULL;
85 /* 1st case: irn is not of mode_T, so it has only */
86 /* one OUT register -> good */
87 /* 2nd case: irn is of mode_T -> collect all Projs and ask the */
88 /* Proj with the corresponding projnum for the register */
90 if (get_irn_mode(node) != mode_T) {
91 reg = arch_get_irn_register(node);
92 } else if (is_mips_irn(node)) {
93 reg = arch_irn_get_register(node, pos);
95 const ir_edge_t *edge;
97 foreach_out_edge(node, edge) {
98 proj = get_edge_src_irn(edge);
99 assert(is_Proj(proj) && "non-Proj from mode_T node");
100 if (get_Proj_proj(proj) == pos) {
101 reg = arch_get_irn_register(proj);
107 assert(reg && "no out register found");
111 /*************************************************************
113 * (_) | | / _| | | | |
114 * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __
115 * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__|
116 * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ |
117 * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_|
120 *************************************************************/
123 * Emit the name of the source register at given input position.
125 void mips_emit_source_register(const ir_node *node, int pos)
127 const arch_register_t *reg = get_in_reg(node, pos);
129 be_emit_string(arch_register_get_name(reg));
133 * Emit the name of the destination register at given output position.
135 void mips_emit_dest_register(const ir_node *node, int pos)
137 const arch_register_t *reg = get_out_reg(node, pos);
139 be_emit_string(arch_register_get_name(reg));
143 static const char *get_symconst_str(ir_node *node)
147 switch (get_SymConst_kind(node)) {
148 case symconst_addr_ent:
149 id = get_entity_ident(get_SymConst_entity(node));
150 return get_id_str(id);
152 panic("Unsupported SymConst kind");
159 * Return a const or symconst as string.
161 static const char *node_const_to_str(ir_node *n)
164 const mips_attr_t *attr = get_mips_attr(n);
167 if (is_mips_load_r(n) || is_mips_store_r(n)) {
168 mips_attr_t *attr = get_mips_attr(n);
171 if (attr->tv != NULL) {
172 val = get_tarval_long(attr->tv);
173 snprintf(buf, sizeof(buf), "%ld", val);
177 if (attr->stack_entity != NULL) {
178 snprintf(buf, sizeof(buf), "%d", attr->stack_entity_offset);
182 symconst = get_irn_n(n, 1);
183 assert(get_irn_opcode(symconst) == iro_SymConst);
185 return get_symconst_str(symconst);
186 } else if (is_mips_la(n)) {
187 snprintf(buf, sizeof(buf), "%s", get_id_str(attr->symconst_id));
189 } else if (is_mips_lli(n)) {
190 assert(attr->tv != NULL);
191 if (get_mode_sign(get_tarval_mode(attr->tv))) {
192 long val = get_tarval_long(attr->tv);
193 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
195 unsigned long val = get_tarval_long(attr->tv);
196 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
200 } else if (is_mips_lui(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 val = (val & 0xffff0000) >> 16;
205 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
207 unsigned long val = get_tarval_long(attr->tv);
208 val = (val & 0xffff0000) >> 16;
209 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
215 assert(attr->tv != NULL);
216 val = get_tarval_long(attr->tv);
217 snprintf(buf, sizeof(buf), "%ld", val);
223 void mips_emit_load_store_address(const ir_node *node, int pos)
225 const mips_load_store_attr_t *attr = get_mips_load_store_attr_const(node);
227 be_emit_irprintf("%d(", attr->offset);
228 mips_emit_source_register(node, pos);
232 void mips_emit_immediate_suffix(const ir_node *node, int pos)
234 ir_node *op = get_irn_n(node, pos);
235 if (is_mips_Immediate(op))
239 void mips_emit_immediate(const ir_node *node)
241 const mips_immediate_attr_t *attr = get_mips_immediate_attr_const(node);
243 switch (attr->imm_type) {
245 be_emit_irprintf("%d", attr->val);
247 case MIPS_IMM_SYMCONST_LO:
248 be_emit_cstring("%lo($");
249 be_emit_ident(get_entity_ld_ident(attr->entity));
250 if (attr->val != 0) {
251 be_emit_irprintf("%+d", attr->val);
255 case MIPS_IMM_SYMCONST_HI:
256 be_emit_cstring("%hi($");
257 be_emit_ident(get_entity_ld_ident(attr->entity));
258 if (attr->val != 0) {
259 be_emit_irprintf("%+d", attr->val);
264 panic("invalid immediate type found");
269 * Emit the name of the destination register at given output position.
271 void mips_emit_source_register_or_immediate(const ir_node *node, int pos)
273 const ir_node *op = get_irn_n(node, pos);
274 if (is_mips_Immediate(op)) {
275 mips_emit_immediate(op);
277 mips_emit_source_register(node, pos);
283 * Add a number to a prefix. This number will not be used a second time.
285 static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
287 static unsigned long id = 0;
288 snprintf(buf, buflen, "%s%lu", prefix, ++id);
293 /************************************************************************/
295 /************************************************************************/
297 static void mips_emit_IncSP(const ir_node *node)
299 int offset = be_get_IncSP_offset(node);
305 if (offset > 0xffff || offset < -0xffff) {
306 panic("stackframe > 2^16 bytes not supported yet");
310 be_emit_irprintf("\tsubu $sp, $sp, %d", offset);
312 be_emit_irprintf("\taddu $sp, $sp, %d", -offset);
314 be_emit_finish_line_gas(node);
317 static void mips_emit_Copy(const ir_node *node)
319 be_emit_cstring("\tmove ");
320 mips_emit_dest_register(node, 0);
321 be_emit_cstring(", ");
322 mips_emit_source_register(node, 0);
323 be_emit_finish_line_gas(node);
326 static void mips_emit_Return(const ir_node* node)
328 be_emit_cstring("\tj $ra");
329 be_emit_finish_line_gas(node);
332 static __attribute__((unused))
333 void mips_emit_nops(int n)
337 for (i = 0; i < n; ++i) {
338 be_emit_cstring("\tnop\n");
339 be_emit_write_line();
343 static void mips_emit_Perm(const ir_node *node)
345 assert(get_irn_arity(node) == 2);
347 be_emit_cstring("\txor ");
348 mips_emit_source_register(node, 0);
349 be_emit_cstring(", ");
350 mips_emit_source_register(node, 0);
351 be_emit_cstring(", ");
352 mips_emit_source_register(node, 1);
353 be_emit_finish_line_gas(node);
355 /* mips_emit_nops(3); */
357 be_emit_cstring("\txor ");
358 mips_emit_source_register(node, 1);
359 be_emit_cstring(", ");
360 mips_emit_source_register(node, 1);
361 be_emit_cstring(", ");
362 mips_emit_source_register(node, 0);
363 be_emit_finish_line_gas(node);
365 /* mips_emit_nops(3); */
367 be_emit_cstring("\txor ");
368 mips_emit_source_register(node, 0);
369 be_emit_cstring(", ");
370 mips_emit_source_register(node, 0);
371 be_emit_cstring(", ");
372 mips_emit_source_register(node, 1);
373 be_emit_finish_line_gas(node);
375 /* mips_emit_nops(3); */
378 /************************************************************************/
380 /************************************************************************/
382 static void mips_emit_Call(const ir_node *node)
386 be_emit_cstring("\tjal ");
388 /* call of immediate value (label) */
389 callee = be_Call_get_entity(node);
390 if (callee != NULL) {
391 be_emit_ident(get_entity_ld_ident(callee));
393 mips_emit_source_register(node, be_pos_Call_ptr);
395 be_emit_finish_line_gas(node);
398 /************************************************************************
400 * | |_ _ _ __ ___ _ __ ___
401 * _ | | | | | '_ ` _ \| '_ \/ __|
402 * | |_| | |_| | | | | | | |_) \__ \
403 * \___/ \__,_|_| |_| |_| .__/|___/
405 ************************************************************************/
407 static void mips_emit_Jump(const ir_node *node)
409 const ir_node *block = get_irn_link(node);
410 assert(is_Block(block));
412 be_emit_cstring("\tb ");
413 be_gas_emit_block_name(block);
414 be_emit_finish_line_gas(node);
417 ir_node *mips_get_jump_block(const ir_node* node, long projn)
419 const ir_edge_t *oute;
420 for (oute = get_irn_out_edge_first(node); oute != NULL;
421 oute = get_irn_out_edge_next(node, oute)) {
422 ir_node *proj = get_edge_src_irn(oute);
424 assert(is_Proj(proj));
426 n = get_Proj_proj(proj);
428 return get_irn_link(proj);
434 void mips_emit_jump_target_proj(const ir_node *node, long projn)
436 ir_node *jumpblock = mips_get_jump_block(node, projn);
437 assert(jumpblock != NULL);
439 be_gas_emit_block_name(jumpblock);
442 void mips_emit_jump_target(const ir_node *node)
444 ir_node *jumpblock = get_irn_link(node);
445 assert(jumpblock != NULL);
447 be_gas_emit_block_name(jumpblock);
450 void mips_emit_jump_or_fallthrough(const ir_node *node, long pn)
452 ir_node *jumpblock = mips_get_jump_block(node, pn);
453 assert(jumpblock != NULL);
455 /* TODO: use fallthrough when possible */
456 be_emit_cstring("b ");
457 be_gas_emit_block_name(jumpblock);
460 /************************************************************************
462 * / ___|_ _(_) |_ ___| |__ | |_ _ _ __ ___ _ __ *
463 * \___ \ \ /\ / / | __/ __| '_ \ _ | | | | | '_ ` _ \| '_ \ *
464 * ___) \ V V /| | || (__| | | | |_| | |_| | | | | | | |_) | *
465 * |____/ \_/\_/ |_|\__\___|_| |_|\___/ \__,_|_| |_| |_| .__/ *
468 ************************************************************************/
471 /* jump table entry (target and corresponding number) */
472 typedef struct _branch_t {
477 /* jump table for switch generation */
478 typedef struct _jmp_tbl_t {
479 ir_node *defBlock; /**< default target */
480 int min_value; /**< smallest switch case */
481 int max_value; /**< largest switch case */
482 int num_branches; /**< number of jumps */
483 char *label; /**< label of the jump table */
484 branch_t *branches; /**< jump array */
488 * Compare two variables of type branch_t. Used to sort all switch cases
490 static int mips_cmp_branch_t(const void *a, const void *b)
492 branch_t *b1 = (branch_t *)a;
493 branch_t *b2 = (branch_t *)b;
495 if (b1->value <= b2->value)
501 const char* mips_get_jumptbl_label(const ir_node* switchjmp)
504 snprintf(buf, sizeof(buf), "__JUMPTBL%ld", get_irn_node_nr(switchjmp));
510 * Emits code for a SwitchJmp (creates a jump table if
511 * possible otherwise a cmp-jmp cascade). Stolen from ia32
513 void emit_mips_jump_table(const ir_node *irn)
515 int lastval, i, i2, pn;
518 const ir_edge_t *edge;
519 const mips_attr_t *attr = get_mips_attr_const(irn);
521 /* fill the table structure */
522 tbl.label = XMALLOCN(char, SNPRINTF_BUF_LEN);
523 tbl.label = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_");
525 tbl.num_branches = get_irn_n_edges(irn);
526 tbl.branches = XMALLOCNZ(branch_t, tbl.num_branches);
527 tbl.min_value = INT_MAX;
528 tbl.max_value = INT_MIN;
531 /* go over all proj's and collect them */
532 foreach_out_edge(irn, edge) {
533 proj = get_edge_src_irn(edge);
534 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
536 pn = get_Proj_proj(proj);
538 /* create branch entry */
539 tbl.branches[i].target = get_irn_link(proj);
540 tbl.branches[i].value = pn;
542 tbl.min_value = pn < tbl.min_value ? pn : tbl.min_value;
543 tbl.max_value = pn > tbl.max_value ? pn : tbl.max_value;
548 /* sort the branches by their number */
549 qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), mips_cmp_branch_t);
551 be_emit_string(mips_get_jumptbl_label(irn));
552 be_emit_cstring(":\n");
553 be_emit_write_line();
554 lastval = tbl.min_value;
555 for (i = 0; i < tbl.num_branches; ++i) {
556 const branch_t *branch = &tbl.branches[i];
557 int value = branch->value;
559 for (i2 = lastval + 1; i2 < value; ++i2) {
560 be_emit_cstring("\t.word ");
561 be_emit_ident(get_entity_ld_ident(attr->symconst));
563 be_emit_write_line();
566 be_emit_cstring("\t.word ");
567 be_gas_emit_block_name(branch->target);
569 be_emit_write_line();
571 lastval = branch->value;
580 static void dump_jump_tables(ir_node* node, void *data)
585 if (is_mips_SwitchJump(node)) {
586 be_emit_cstring(".data\n");
587 be_emit_write_line();
589 emit_mips_jump_table(node);
591 be_emit_cstring(".text\n");
592 be_emit_write_line();
597 /***********************************************************************************
600 * _ __ ___ __ _ _ _ __ | |_ _ __ __ _ _ __ ___ _____ _____ _ __| | __
601 * | '_ ` _ \ / _` | | '_ \ | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
602 * | | | | | | (_| | | | | | | | | | | (_| | | | | | | __/\ V V / (_) | | | <
603 * |_| |_| |_|\__,_|_|_| |_| |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\
605 ***********************************************************************************/
607 static void mips_emit_nothing(const ir_node *node)
612 static void mips_emit_this_shouldnt_happen(const ir_node *node)
614 panic("Found non-lowered node %+F while emitting", node);
618 * The type of a emitter function.
620 typedef void (*emit_func) (const ir_node *);
623 * Set a node emitter. Make it a bit more type safe.
625 static void register_emitter(ir_op *op, emit_func func)
627 op->ops.generic = (op_func) func;
631 * Register emitter functions for mips backend
633 void mips_register_emitters(void)
635 /* first clear the generic function pointer for all ops */
636 clear_irp_opcodes_generic_func();
638 /* register all emitter functions defined in spec */
639 mips_register_spec_emitters();
642 register_emitter(op_be_IncSP, mips_emit_IncSP);
643 register_emitter(op_be_AddSP, mips_emit_this_shouldnt_happen);
644 register_emitter(op_be_Call, mips_emit_Call);
645 register_emitter(op_be_Copy, mips_emit_Copy);
646 register_emitter(op_be_Keep, mips_emit_nothing);
647 register_emitter(op_be_Barrier, mips_emit_nothing);
648 register_emitter(op_be_Return, mips_emit_Return);
649 register_emitter(op_be_Start, mips_emit_nothing);
650 register_emitter(op_be_Spill, mips_emit_this_shouldnt_happen);
651 register_emitter(op_be_Reload, mips_emit_this_shouldnt_happen);
652 register_emitter(op_be_Perm, mips_emit_Perm);
654 register_emitter(op_Proj, mips_emit_nothing);
655 register_emitter(op_SymConst, mips_emit_this_shouldnt_happen);
656 register_emitter(op_Const, mips_emit_this_shouldnt_happen);
657 register_emitter(op_Jmp, mips_emit_Jump);
658 register_emitter(op_Cmp, mips_emit_this_shouldnt_happen);
659 register_emitter(op_Cond, mips_emit_this_shouldnt_happen);
660 register_emitter(op_Phi, mips_emit_nothing);
664 * Emits assembly for a single node
666 static void mips_emit_node(const ir_node *node)
668 ir_op *op = get_irn_op(node);
670 if (op->ops.generic) {
671 emit_func emit = (emit_func) op->ops.generic;
674 panic("No emitter defined for node %+F", node);
679 * Walks over the nodes in a block connected by scheduling edges
680 * and emits code for each node.
682 void mips_gen_block(const ir_node *block)
686 if (! is_Block(block))
689 be_gas_emit_block_name(block);
690 be_emit_cstring(":\n");
691 be_emit_write_line();
693 sched_foreach(block, node) {
694 mips_emit_node(node);
698 be_emit_write_line();
702 * Emits code for function start.
704 void mips_emit_func_prolog(ir_graph *irg)
706 ident *irg_ident = get_entity_ld_ident(get_irg_entity(irg));
709 //irg_walk_graph(irg, NULL, dump_jump_tables, env);
711 be_emit_write_line();
712 be_gas_emit_switch_section(GAS_SECTION_TEXT);
714 be_emit_cstring("\t.balign\t4\n");
716 be_emit_cstring("\t.global\t");
717 be_emit_ident(irg_ident);
720 be_emit_cstring("\t.set\tnomips16\n");
722 be_emit_cstring("\t.ent\t");
723 be_emit_ident(irg_ident);
726 be_emit_ident(irg_ident);
727 be_emit_cstring(":\n");
729 be_emit_cstring("\t.frame\t$fp, 24, $ra\n");
730 be_emit_cstring("\t.mask\t0xc0000000, -4\n");
731 be_emit_cstring("\t.fmask\t0x00000000, 0\n");
733 be_emit_write_line();
737 * Emits code for function end
739 void mips_emit_func_epilog(ir_graph *irg)
741 ident *irg_ident = get_entity_ident(get_irg_entity(irg));
743 be_emit_cstring("\t.end\t");
744 be_emit_ident(irg_ident);
746 be_emit_write_line();
750 * Sets labels for control flow nodes (jump target)
752 void mips_gen_labels(ir_node *block, void *env)
755 int n = get_Block_n_cfgpreds(block);
758 for (n--; n >= 0; n--) {
759 pred = get_Block_cfgpred(block, n);
760 set_irn_link(pred, block);
767 void mips_gen_routine(mips_code_gen_t *mips_cg, ir_graph *irg)
771 mips_register_emitters();
773 irg_block_walk_graph(irg, mips_gen_labels, NULL, NULL);
775 mips_emit_func_prolog(irg);
777 n = ARR_LEN(mips_cg->block_schedule);
778 for (i = 0; i < n; ++i) {
779 ir_node *block = mips_cg->block_schedule[i];
780 mips_gen_block(block);
783 mips_emit_func_epilog(irg);
786 void mips_init_emitter(void)
788 FIRM_DBG_REGISTER(dbg, "firm.be.mips.emitter");