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
44 #include "../besched.h"
45 #include "../benode_t.h"
46 #include "../beutil.h"
47 #include "../begnuas.h"
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"
55 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
57 #define BLOCK_PREFIX ".L"
59 #define SNPRINTF_BUF_LEN 128
61 static const mips_isa_t *isa;
62 static const arch_env_t *arch_env;
63 static const mips_code_gen_t *cg;
66 * Returns the register at in position pos.
68 static const arch_register_t *get_in_reg(const ir_node *node, int pos)
71 const arch_register_t *reg = NULL;
73 assert(get_irn_arity(node) > pos && "Invalid IN position");
75 /* The out register of the operator at position pos is the
76 in register we need. */
77 op = get_irn_n(node, pos);
79 reg = arch_get_irn_register(arch_env, op);
81 assert(reg && "no in register found");
86 * Returns the register at out position pos.
88 static const arch_register_t *get_out_reg(const ir_node *node, int pos)
91 const arch_register_t *reg = NULL;
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 */
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);
103 const ir_edge_t *edge;
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);
115 assert(reg && "no out register found");
119 /*************************************************************
121 * (_) | | / _| | | | |
122 * _ __ _ __ _ _ __ | |_| |_ | |__ ___| |_ __ ___ _ __
123 * | '_ \| '__| | '_ \| __| _| | '_ \ / _ \ | '_ \ / _ \ '__|
124 * | |_) | | | | | | | |_| | | | | | __/ | |_) | __/ |
125 * | .__/|_| |_|_| |_|\__|_| |_| |_|\___|_| .__/ \___|_|
128 *************************************************************/
131 * Emit the name of the source register at given input position.
133 void mips_emit_source_register(const ir_node *node, int pos)
135 const arch_register_t *reg = get_in_reg(node, pos);
137 be_emit_string(arch_register_get_name(reg));
141 * Emit the name of the destination register at given output position.
143 void mips_emit_dest_register(const ir_node *node, int pos)
145 const arch_register_t *reg = get_out_reg(node, pos);
147 be_emit_string(arch_register_get_name(reg));
151 static const char *get_symconst_str(ir_node *node)
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);
170 * Return a const or symconst as string.
172 static const char *node_const_to_str(ir_node *n)
175 const mips_attr_t *attr = get_mips_attr(n);
178 if(is_mips_load_r(n) || is_mips_store_r(n)) {
179 mips_attr_t *attr = get_mips_attr(n);
182 if(attr->tv != NULL) {
183 val = get_tarval_long(attr->tv);
184 snprintf(buf, sizeof(buf), "%ld", val);
188 if(attr->stack_entity != NULL) {
189 snprintf(buf, sizeof(buf), "%d", attr->stack_entity_offset);
193 symconst = get_irn_n(n, 1);
194 assert(get_irn_opcode(symconst) == iro_SymConst);
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));
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);
206 unsigned long val = get_tarval_long(attr->tv);
207 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
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);
218 unsigned long val = get_tarval_long(attr->tv);
219 val = (val & 0xffff0000) >> 16;
220 snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
226 assert(attr->tv != NULL);
227 val = get_tarval_long(attr->tv);
228 snprintf(buf, sizeof(buf), "%ld", val);
234 void mips_emit_load_store_address(const ir_node *node, int pos)
236 const mips_load_store_attr_t *attr = get_mips_load_store_attr_const(node);
238 be_emit_irprintf("%d(", attr->offset);
239 mips_emit_source_register(node, pos);
243 void mips_emit_immediate_suffix(const ir_node *node, int pos)
245 ir_node *op = get_irn_n(node, pos);
246 if(is_mips_Immediate(op))
250 void mips_emit_immediate(const ir_node *node)
252 const mips_immediate_attr_t *attr = get_mips_immediate_attr_const(node);
254 switch(attr->imm_type) {
256 be_emit_irprintf("%d", attr->val);
258 case MIPS_IMM_SYMCONST_LO:
259 be_emit_cstring("%lo($");
260 be_emit_ident(get_entity_ld_ident(attr->entity));
262 be_emit_irprintf("%+d", attr->val);
266 case MIPS_IMM_SYMCONST_HI:
267 be_emit_cstring("%hi($");
268 be_emit_ident(get_entity_ld_ident(attr->entity));
270 be_emit_irprintf("%+d", attr->val);
275 panic("invalid immediate type found");
280 * Emit the name of the destination register at given output position.
282 void mips_emit_source_register_or_immediate(const ir_node *node, int pos)
284 const ir_node *op = get_irn_n(node, pos);
285 if(is_mips_Immediate(op)) {
286 mips_emit_immediate(op);
288 mips_emit_source_register(node, pos);
294 * Add a number to a prefix. This number will not be used a second time.
296 static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
298 static unsigned long id = 0;
299 snprintf(buf, buflen, "%s%lu", prefix, ++id);
304 /************************************************************************/
306 /************************************************************************/
309 void mips_emit_IncSP(const ir_node *node)
311 int offset = be_get_IncSP_offset(node);
314 be_emit_cstring("\t/* omitted IncSP with 0 */");
315 be_emit_finish_line_gas(node);
319 if(offset > 0xffff || offset < -0xffff) {
320 panic("stackframe > 2^16 bytes not supported yet\n");
324 be_emit_irprintf("\tsubu $sp, $sp, %d", offset);
326 be_emit_irprintf("\taddu $sp, $sp, %d", -offset);
328 be_emit_finish_line_gas(node);
331 static void mips_emit_Copy(const ir_node *node)
333 be_emit_cstring("\tmove ");
334 mips_emit_dest_register(node, 0);
335 be_emit_cstring(", ");
336 mips_emit_source_register(node, 0);
337 be_emit_finish_line_gas(node);
340 static void mips_emit_Return(const ir_node* node)
342 be_emit_cstring("\tj $ra");
343 be_emit_finish_line_gas(node);
346 static __attribute__((unused))
347 void mips_emit_nops(int n)
351 for(i = 0; i < n; ++i) {
352 be_emit_cstring("\tnop\n");
353 be_emit_write_line();
357 static void mips_emit_Perm(const ir_node *node)
359 assert(get_irn_arity(node) == 2);
361 be_emit_cstring("\txor ");
362 mips_emit_source_register(node, 0);
363 be_emit_cstring(", ");
364 mips_emit_source_register(node, 0);
365 be_emit_cstring(", ");
366 mips_emit_source_register(node, 1);
367 be_emit_finish_line_gas(node);
369 /* mips_emit_nops(3); */
371 be_emit_cstring("\txor ");
372 mips_emit_source_register(node, 1);
373 be_emit_cstring(", ");
374 mips_emit_source_register(node, 1);
375 be_emit_cstring(", ");
376 mips_emit_source_register(node, 0);
377 be_emit_finish_line_gas(node);
379 /* mips_emit_nops(3); */
381 be_emit_cstring("\txor ");
382 mips_emit_source_register(node, 0);
383 be_emit_cstring(", ");
384 mips_emit_source_register(node, 0);
385 be_emit_cstring(", ");
386 mips_emit_source_register(node, 1);
387 be_emit_finish_line_gas(node);
389 /* mips_emit_nops(3); */
392 /************************************************************************/
394 /************************************************************************/
396 static void mips_emit_Call(const ir_node *node)
400 be_emit_cstring("\tjal ");
402 /* call of immediate value (label) */
403 callee = be_Call_get_entity(node);
405 be_emit_ident(get_entity_ld_ident(callee));
407 mips_emit_source_register(node, be_pos_Call_ptr);
409 be_emit_finish_line_gas(node);
412 /************************************************************************
414 * | |_ _ _ __ ___ _ __ ___
415 * _ | | | | | '_ ` _ \| '_ \/ __|
416 * | |_| | |_| | | | | | | |_) \__ \
417 * \___/ \__,_|_| |_| |_| .__/|___/
419 ************************************************************************/
421 const char* mips_get_block_label(const ir_node* block)
424 snprintf(buf, sizeof(buf), "BLOCK_%ld", get_irn_node_nr(block));
430 * Emits a block label from the given block.
432 static void mips_emit_block_label(const ir_node *block)
434 if (has_Block_label(block)) {
435 be_emit_string(be_gas_label_prefix());
436 be_emit_irprintf("%lu", get_Block_label(block));
438 be_emit_cstring(BLOCK_PREFIX);
439 be_emit_irprintf("%d", get_irn_node_nr(block));
444 static void mips_emit_Jump(const ir_node *node)
446 const ir_node *block = get_irn_link(node);
447 assert(is_Block(block));
449 be_emit_cstring("\tb ");
450 mips_emit_block_label(block);
451 be_emit_finish_line_gas(node);
454 ir_node *mips_get_jump_block(const ir_node* node, long projn)
456 const ir_edge_t *oute;
457 for(oute = get_irn_out_edge_first(node); oute != NULL;
458 oute = get_irn_out_edge_next(node, oute)) {
459 ir_node *proj = get_edge_src_irn(oute);
461 assert(is_Proj(proj));
463 n = get_Proj_proj(proj);
465 return get_irn_link(proj);
471 void mips_emit_jump_target_proj(const ir_node *node, long projn)
473 ir_node *jumpblock = mips_get_jump_block(node, projn);
474 assert(jumpblock != NULL);
476 mips_emit_block_label(jumpblock);
479 void mips_emit_jump_target(const ir_node *node)
481 ir_node *jumpblock = get_irn_link(node);
482 assert(jumpblock != NULL);
484 mips_emit_block_label(jumpblock);
487 void mips_emit_jump_or_fallthrough(const ir_node *node, long pn)
489 ir_node *jumpblock = mips_get_jump_block(node, pn);
490 assert(jumpblock != NULL);
492 /* TODO: use fallthrough when possible */
493 be_emit_cstring("b ");
494 mips_emit_block_label(jumpblock);
497 /************************************************************************
499 * / ___|_ _(_) |_ ___| |__ | |_ _ _ __ ___ _ __ *
500 * \___ \ \ /\ / / | __/ __| '_ \ _ | | | | | '_ ` _ \| '_ \ *
501 * ___) \ V V /| | || (__| | | | |_| | |_| | | | | | | |_) | *
502 * |____/ \_/\_/ |_|\__\___|_| |_|\___/ \__,_|_| |_| |_| .__/ *
505 ************************************************************************/
508 /* jump table entry (target and corresponding number) */
509 typedef struct _branch_t {
514 /* jump table for switch generation */
515 typedef struct _jmp_tbl_t {
516 ir_node *defBlock; /**< default target */
517 int min_value; /**< smallest switch case */
518 int max_value; /**< largest switch case */
519 int num_branches; /**< number of jumps */
520 char *label; /**< label of the jump table */
521 branch_t *branches; /**< jump array */
525 * Compare two variables of type branch_t. Used to sort all switch cases
527 static int mips_cmp_branch_t(const void *a, const void *b)
529 branch_t *b1 = (branch_t *)a;
530 branch_t *b2 = (branch_t *)b;
532 if (b1->value <= b2->value)
538 const char* mips_get_jumptbl_label(const ir_node* switchjmp)
541 snprintf(buf, sizeof(buf), "__JUMPTBL%ld", get_irn_node_nr(switchjmp));
547 * Emits code for a SwitchJmp (creates a jump table if
548 * possible otherwise a cmp-jmp cascade). Stolen from ia32
550 void emit_mips_jump_table(const ir_node *irn)
552 int lastval, i, i2, pn;
555 const ir_edge_t *edge;
556 const mips_attr_t *attr = get_mips_attr_const(irn);
558 /* fill the table structure */
559 tbl.label = xmalloc(SNPRINTF_BUF_LEN);
560 tbl.label = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_");
562 tbl.num_branches = get_irn_n_edges(irn);
563 tbl.branches = xcalloc(tbl.num_branches, sizeof(tbl.branches[0]));
564 tbl.min_value = INT_MAX;
565 tbl.max_value = INT_MIN;
568 /* go over all proj's and collect them */
569 foreach_out_edge(irn, edge) {
570 proj = get_edge_src_irn(edge);
571 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
573 pn = get_Proj_proj(proj);
575 /* create branch entry */
576 tbl.branches[i].target = get_irn_link(proj);
577 tbl.branches[i].value = pn;
579 tbl.min_value = pn < tbl.min_value ? pn : tbl.min_value;
580 tbl.max_value = pn > tbl.max_value ? pn : tbl.max_value;
585 /* sort the branches by their number */
586 qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), mips_cmp_branch_t);
588 be_emit_string(mips_get_jumptbl_label(irn));
589 be_emit_cstring(":\n");
590 be_emit_write_line();
591 lastval = tbl.min_value;
592 for(i = 0; i < tbl.num_branches; ++i) {
593 const branch_t *branch = &tbl.branches[i];
594 int value = branch->value;
596 for(i2 = lastval + 1; i2 < value; ++i2) {
597 be_emit_cstring("\t.word ");
598 be_emit_ident(get_entity_ld_ident(attr->symconst));
600 be_emit_write_line();
603 be_emit_cstring("\t.word ");
604 mips_emit_block_label(branch->target);
606 be_emit_write_line();
608 lastval = branch->value;
617 static void dump_jump_tables(ir_node* node, void *data)
622 if(is_mips_SwitchJump(node)) {
623 be_emit_cstring(".data\n");
624 be_emit_write_line();
626 emit_mips_jump_table(node);
628 be_emit_cstring(".text\n");
629 be_emit_write_line();
634 /***********************************************************************************
637 * _ __ ___ __ _ _ _ __ | |_ _ __ __ _ _ __ ___ _____ _____ _ __| | __
638 * | '_ ` _ \ / _` | | '_ \ | _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
639 * | | | | | | (_| | | | | | | | | | | (_| | | | | | | __/\ V V / (_) | | | <
640 * |_| |_| |_|\__,_|_|_| |_| |_| |_| \__,_|_| |_| |_|\___| \_/\_/ \___/|_| |_|\_\
642 ***********************************************************************************/
644 static void mips_emit_nothing(const ir_node *node)
649 static void mips_emit_this_shouldnt_happen(const ir_node *node)
651 panic("Found non-lowered node %+F while emitting", node);
655 * The type of a emitter function.
657 typedef void (*emit_func) (const ir_node *);
660 * Set a node emitter. Make it a bit more type safe.
662 static void register_emitter(ir_op *op, emit_func func)
664 op->ops.generic = (op_func) func;
668 * Register emitter functions for mips backend
670 void mips_register_emitters(void)
672 /* first clear the generic function pointer for all ops */
673 clear_irp_opcodes_generic_func();
675 /* register all emitter functions defined in spec */
676 mips_register_spec_emitters();
679 register_emitter(op_be_IncSP, mips_emit_IncSP);
680 register_emitter(op_be_AddSP, mips_emit_this_shouldnt_happen);
681 register_emitter(op_be_Call, mips_emit_Call);
682 register_emitter(op_be_Copy, mips_emit_Copy);
683 register_emitter(op_be_Keep, mips_emit_nothing);
684 register_emitter(op_be_Barrier, mips_emit_nothing);
685 register_emitter(op_be_Return, mips_emit_Return);
686 register_emitter(op_be_RegParams, mips_emit_nothing);
687 register_emitter(op_be_Spill, mips_emit_this_shouldnt_happen);
688 register_emitter(op_be_Reload, mips_emit_this_shouldnt_happen);
689 register_emitter(op_be_Perm, mips_emit_Perm);
691 register_emitter(op_Start, mips_emit_nothing);
692 register_emitter(op_Proj, mips_emit_nothing);
693 register_emitter(op_SymConst, mips_emit_this_shouldnt_happen);
694 register_emitter(op_Const, mips_emit_this_shouldnt_happen);
695 register_emitter(op_Jmp, mips_emit_Jump);
696 register_emitter(op_Cmp, mips_emit_this_shouldnt_happen);
697 register_emitter(op_Cond, mips_emit_this_shouldnt_happen);
698 register_emitter(op_Phi, mips_emit_nothing);
702 * Emits assembly for a single node
704 static void mips_emit_node(const ir_node *node)
706 ir_op *op = get_irn_op(node);
708 if (op->ops.generic) {
709 emit_func emit = (emit_func) op->ops.generic;
712 panic("No emitter defined for node %+F", node);
717 * Walks over the nodes in a block connected by scheduling edges
718 * and emits code for each node.
720 void mips_gen_block(const ir_node *block)
724 if (! is_Block(block))
727 mips_emit_block_label(block);
728 be_emit_cstring(":\n");
729 be_emit_write_line();
731 sched_foreach(block, node) {
732 mips_emit_node(node);
736 be_emit_write_line();
740 * Emits code for function start.
742 void mips_emit_func_prolog(ir_graph *irg)
744 ident *irg_ident = get_entity_ld_ident(get_irg_entity(irg));
747 //irg_walk_graph(irg, NULL, dump_jump_tables, env);
749 be_emit_write_line();
750 be_gas_emit_switch_section(GAS_SECTION_TEXT);
752 be_emit_cstring("\t.balign\t4\n");
754 be_emit_cstring("\t.global\t");
755 be_emit_ident(irg_ident);
758 be_emit_cstring("\t.set\tnomips16\n");
760 be_emit_cstring("\t.ent\t");
761 be_emit_ident(irg_ident);
764 be_emit_ident(irg_ident);
765 be_emit_cstring(":\n");
767 be_emit_cstring("\t.frame\t$fp, 24, $ra\n");
768 be_emit_cstring("\t.mask\t0xc0000000, -4\n");
769 be_emit_cstring("\t.fmask\t0x00000000, 0\n");
771 be_emit_write_line();
775 * Emits code for function end
777 void mips_emit_func_epilog(ir_graph *irg)
779 ident *irg_ident = get_entity_ident(get_irg_entity(irg));
781 be_emit_cstring("\t.end\t");
782 be_emit_ident(irg_ident);
784 be_emit_write_line();
788 * Sets labels for control flow nodes (jump target)
790 void mips_gen_labels(ir_node *block, void *env)
793 int n = get_Block_n_cfgpreds(block);
796 for (n--; n >= 0; n--) {
797 pred = get_Block_cfgpred(block, n);
798 set_irn_link(pred, block);
805 void mips_gen_routine(mips_code_gen_t *mips_cg, ir_graph *irg)
810 isa = (const mips_isa_t*) cg->arch_env->isa;
811 arch_env = cg->arch_env;
813 mips_register_emitters();
815 irg_block_walk_graph(irg, mips_gen_labels, NULL, NULL);
817 mips_emit_func_prolog(irg);
819 dump_ir_block_graph_sched(irg, "-kaputtelist");
821 for (i = 0, n = mips_get_sched_n_blocks(cg); i < n; ++i) {
822 ir_node *block = mips_get_sched_block(cg, i);
823 mips_gen_block(block);
826 mips_emit_func_epilog(irg);
829 void mips_init_emitter(void)
831 FIRM_DBG_REGISTER(dbg, "firm.be.mips.emitter");